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    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   57    HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61    render_breadcrumb_text,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inlays::Inlay;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   71    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   72    ToPoint,
   73};
   74pub use split::SplittableEditor;
   75pub use text::Bias;
   76
   77use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   78use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   79use anyhow::{Context as _, Result, anyhow, bail};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction_types::{
   93    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   94    SuggestionDisplayType,
   95};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  111    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  112    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  113    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  114    size,
  115};
  116use hover_links::{HoverLink, HoveredLinkState, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  120use itertools::{Either, Itertools};
  121use language::{
  122    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  123    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  124    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  125    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  126    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  127    TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145};
  146use parking_lot::Mutex;
  147use persistence::DB;
  148use project::{
  149    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  150    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  151    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  152    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::{
  154        breakpoint_store::{
  155            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  156            BreakpointStore, BreakpointStoreEvent,
  157        },
  158        session::{Session, SessionEvent},
  159    },
  160    git_store::GitStoreEvent,
  161    lsp_store::{
  162        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  163        OpenLspBufferHandle,
  164    },
  165    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  166};
  167use rand::seq::SliceRandom;
  168use regex::Regex;
  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 workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::{CollapseDirection, SearchEvent},
  212};
  213
  214use crate::{
  215    code_context_menus::CompletionsMenuSource,
  216    editor_settings::MultiCursorModifier,
  217    hover_links::{find_url, find_url_from_range},
  218    inlays::{
  219        InlineValueCache,
  220        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  221    },
  222    scroll::{ScrollOffset, ScrollPixelOffset},
  223    selections_collection::resolve_selections_wrapping_blocks,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260enum ReportEditorEvent {
  261    Saved { auto_saved: bool },
  262    EditorOpened,
  263    Closed,
  264}
  265
  266impl ReportEditorEvent {
  267    pub fn event_type(&self) -> &'static str {
  268        match self {
  269            Self::Saved { .. } => "Editor Saved",
  270            Self::EditorOpened => "Editor Opened",
  271            Self::Closed => "Editor Closed",
  272        }
  273    }
  274}
  275
  276pub enum ActiveDebugLine {}
  277pub enum DebugStackFrameLine {}
  278enum DocumentHighlightRead {}
  279enum DocumentHighlightWrite {}
  280enum InputComposition {}
  281pub enum PendingInput {}
  282enum SelectedTextHighlight {}
  283
  284pub enum ConflictsOuter {}
  285pub enum ConflictsOurs {}
  286pub enum ConflictsTheirs {}
  287pub enum ConflictsOursMarker {}
  288pub enum ConflictsTheirsMarker {}
  289
  290pub struct HunkAddedColor;
  291pub struct HunkRemovedColor;
  292
  293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  294pub enum Navigated {
  295    Yes,
  296    No,
  297}
  298
  299impl Navigated {
  300    pub fn from_bool(yes: bool) -> Navigated {
  301        if yes { Navigated::Yes } else { Navigated::No }
  302    }
  303}
  304
  305#[derive(Debug, Clone, PartialEq, Eq)]
  306enum DisplayDiffHunk {
  307    Folded {
  308        display_row: DisplayRow,
  309    },
  310    Unfolded {
  311        is_created_file: bool,
  312        diff_base_byte_range: Range<usize>,
  313        display_row_range: Range<DisplayRow>,
  314        multi_buffer_range: Range<Anchor>,
  315        status: DiffHunkStatus,
  316        word_diffs: Vec<Range<MultiBufferOffset>>,
  317    },
  318}
  319
  320pub enum HideMouseCursorOrigin {
  321    TypingAction,
  322    MovementAction,
  323}
  324
  325pub fn init(cx: &mut App) {
  326    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  327
  328    workspace::register_project_item::<Editor>(cx);
  329    workspace::FollowableViewRegistry::register::<Editor>(cx);
  330    workspace::register_serializable_item::<Editor>(cx);
  331
  332    cx.observe_new(
  333        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  334            workspace.register_action(Editor::new_file);
  335            workspace.register_action(Editor::new_file_split);
  336            workspace.register_action(Editor::new_file_vertical);
  337            workspace.register_action(Editor::new_file_horizontal);
  338            workspace.register_action(Editor::cancel_language_server_work);
  339            workspace.register_action(Editor::toggle_focus);
  340        },
  341    )
  342    .detach();
  343
  344    cx.on_action(move |_: &workspace::NewFile, cx| {
  345        let app_state = workspace::AppState::global(cx);
  346        if let Some(app_state) = app_state.upgrade() {
  347            workspace::open_new(
  348                Default::default(),
  349                app_state,
  350                cx,
  351                |workspace, window, cx| {
  352                    Editor::new_file(workspace, &Default::default(), window, cx)
  353                },
  354            )
  355            .detach();
  356        }
  357    })
  358    .on_action(move |_: &workspace::NewWindow, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    cx.activate(true);
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373}
  374
  375pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  376    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  377}
  378
  379pub trait DiagnosticRenderer {
  380    fn render_group(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        buffer_id: BufferId,
  384        snapshot: EditorSnapshot,
  385        editor: WeakEntity<Editor>,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Vec<BlockProperties<Anchor>>;
  389
  390    fn render_hover(
  391        &self,
  392        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  393        range: Range<Point>,
  394        buffer_id: BufferId,
  395        language_registry: Option<Arc<LanguageRegistry>>,
  396        cx: &mut App,
  397    ) -> Option<Entity<markdown::Markdown>>;
  398
  399    fn open_link(
  400        &self,
  401        editor: &mut Editor,
  402        link: SharedString,
  403        window: &mut Window,
  404        cx: &mut Context<Editor>,
  405    );
  406}
  407
  408pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  409
  410impl GlobalDiagnosticRenderer {
  411    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  412        cx.try_global::<Self>().map(|g| g.0.clone())
  413    }
  414}
  415
  416impl gpui::Global for GlobalDiagnosticRenderer {}
  417pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  418    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  419}
  420
  421pub struct SearchWithinRange;
  422
  423trait InvalidationRegion {
  424    fn ranges(&self) -> &[Range<Anchor>];
  425}
  426
  427#[derive(Clone, Debug, PartialEq)]
  428pub enum SelectPhase {
  429    Begin {
  430        position: DisplayPoint,
  431        add: bool,
  432        click_count: usize,
  433    },
  434    BeginColumnar {
  435        position: DisplayPoint,
  436        reset: bool,
  437        mode: ColumnarMode,
  438        goal_column: u32,
  439    },
  440    Extend {
  441        position: DisplayPoint,
  442        click_count: usize,
  443    },
  444    Update {
  445        position: DisplayPoint,
  446        goal_column: u32,
  447        scroll_delta: gpui::Point<f32>,
  448    },
  449    End,
  450}
  451
  452#[derive(Clone, Debug, PartialEq)]
  453pub enum ColumnarMode {
  454    FromMouse,
  455    FromSelection,
  456}
  457
  458#[derive(Clone, Debug)]
  459pub enum SelectMode {
  460    Character,
  461    Word(Range<Anchor>),
  462    Line(Range<Anchor>),
  463    All,
  464}
  465
  466#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  467pub enum SizingBehavior {
  468    /// The editor will layout itself using `size_full` and will include the vertical
  469    /// scroll margin as requested by user settings.
  470    #[default]
  471    Default,
  472    /// The editor will layout itself using `size_full`, but will not have any
  473    /// vertical overscroll.
  474    ExcludeOverscrollMargin,
  475    /// The editor will request a vertical size according to its content and will be
  476    /// layouted without a vertical scroll margin.
  477    SizeByContent,
  478}
  479
  480#[derive(Clone, PartialEq, Eq, Debug)]
  481pub enum EditorMode {
  482    SingleLine,
  483    AutoHeight {
  484        min_lines: usize,
  485        max_lines: Option<usize>,
  486    },
  487    Full {
  488        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  489        scale_ui_elements_with_buffer_font_size: bool,
  490        /// When set to `true`, the editor will render a background for the active line.
  491        show_active_line_background: bool,
  492        /// Determines the sizing behavior for this editor
  493        sizing_behavior: SizingBehavior,
  494    },
  495    Minimap {
  496        parent: WeakEntity<Editor>,
  497    },
  498}
  499
  500impl EditorMode {
  501    pub fn full() -> Self {
  502        Self::Full {
  503            scale_ui_elements_with_buffer_font_size: true,
  504            show_active_line_background: true,
  505            sizing_behavior: SizingBehavior::Default,
  506        }
  507    }
  508
  509    #[inline]
  510    pub fn is_full(&self) -> bool {
  511        matches!(self, Self::Full { .. })
  512    }
  513
  514    #[inline]
  515    pub fn is_single_line(&self) -> bool {
  516        matches!(self, Self::SingleLine { .. })
  517    }
  518
  519    #[inline]
  520    fn is_minimap(&self) -> bool {
  521        matches!(self, Self::Minimap { .. })
  522    }
  523}
  524
  525#[derive(Copy, Clone, Debug)]
  526pub enum SoftWrap {
  527    /// Prefer not to wrap at all.
  528    ///
  529    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  530    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  531    GitDiff,
  532    /// Prefer a single line generally, unless an overly long line is encountered.
  533    None,
  534    /// Soft wrap lines that exceed the editor width.
  535    EditorWidth,
  536    /// Soft wrap lines at the preferred line length.
  537    Column(u32),
  538    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  539    Bounded(u32),
  540}
  541
  542#[derive(Clone)]
  543pub struct EditorStyle {
  544    pub background: Hsla,
  545    pub border: Hsla,
  546    pub local_player: PlayerColor,
  547    pub text: TextStyle,
  548    pub scrollbar_width: Pixels,
  549    pub syntax: Arc<SyntaxTheme>,
  550    pub status: StatusColors,
  551    pub inlay_hints_style: HighlightStyle,
  552    pub edit_prediction_styles: EditPredictionStyles,
  553    pub unnecessary_code_fade: f32,
  554    pub show_underlines: bool,
  555}
  556
  557impl Default for EditorStyle {
  558    fn default() -> Self {
  559        Self {
  560            background: Hsla::default(),
  561            border: Hsla::default(),
  562            local_player: PlayerColor::default(),
  563            text: TextStyle::default(),
  564            scrollbar_width: Pixels::default(),
  565            syntax: Default::default(),
  566            // HACK: Status colors don't have a real default.
  567            // We should look into removing the status colors from the editor
  568            // style and retrieve them directly from the theme.
  569            status: StatusColors::dark(),
  570            inlay_hints_style: HighlightStyle::default(),
  571            edit_prediction_styles: EditPredictionStyles {
  572                insertion: HighlightStyle::default(),
  573                whitespace: HighlightStyle::default(),
  574            },
  575            unnecessary_code_fade: Default::default(),
  576            show_underlines: true,
  577        }
  578    }
  579}
  580
  581pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  582    let show_background = language_settings::language_settings(None, None, cx)
  583        .inlay_hints
  584        .show_background;
  585
  586    let mut style = cx.theme().syntax().get("hint");
  587
  588    if style.color.is_none() {
  589        style.color = Some(cx.theme().status().hint);
  590    }
  591
  592    if !show_background {
  593        style.background_color = None;
  594        return style;
  595    }
  596
  597    if style.background_color.is_none() {
  598        style.background_color = Some(cx.theme().status().hint_background);
  599    }
  600
  601    style
  602}
  603
  604pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  605    EditPredictionStyles {
  606        insertion: HighlightStyle {
  607            color: Some(cx.theme().status().predictive),
  608            ..HighlightStyle::default()
  609        },
  610        whitespace: HighlightStyle {
  611            background_color: Some(cx.theme().status().created_background),
  612            ..HighlightStyle::default()
  613        },
  614    }
  615}
  616
  617type CompletionId = usize;
  618
  619pub(crate) enum EditDisplayMode {
  620    TabAccept,
  621    DiffPopover,
  622    Inline,
  623}
  624
  625enum EditPrediction {
  626    Edit {
  627        edits: Vec<(Range<Anchor>, Arc<str>)>,
  628        edit_preview: Option<EditPreview>,
  629        display_mode: EditDisplayMode,
  630        snapshot: BufferSnapshot,
  631    },
  632    /// Move to a specific location in the active editor
  633    MoveWithin {
  634        target: Anchor,
  635        snapshot: BufferSnapshot,
  636    },
  637    /// Move to a specific location in a different editor (not the active one)
  638    MoveOutside {
  639        target: language::Anchor,
  640        snapshot: BufferSnapshot,
  641    },
  642}
  643
  644struct EditPredictionState {
  645    inlay_ids: Vec<InlayId>,
  646    completion: EditPrediction,
  647    completion_id: Option<SharedString>,
  648    invalidation_range: Option<Range<Anchor>>,
  649}
  650
  651enum EditPredictionSettings {
  652    Disabled,
  653    Enabled {
  654        show_in_menu: bool,
  655        preview_requires_modifier: bool,
  656    },
  657}
  658
  659enum EditPredictionHighlight {}
  660
  661#[derive(Debug, Clone)]
  662struct InlineDiagnostic {
  663    message: SharedString,
  664    group_id: usize,
  665    is_primary: bool,
  666    start: Point,
  667    severity: lsp::DiagnosticSeverity,
  668}
  669
  670pub enum MenuEditPredictionsPolicy {
  671    Never,
  672    ByProvider,
  673}
  674
  675pub enum EditPredictionPreview {
  676    /// Modifier is not pressed
  677    Inactive { released_too_fast: bool },
  678    /// Modifier pressed
  679    Active {
  680        since: Instant,
  681        previous_scroll_position: Option<ScrollAnchor>,
  682    },
  683}
  684
  685impl EditPredictionPreview {
  686    pub fn released_too_fast(&self) -> bool {
  687        match self {
  688            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  689            EditPredictionPreview::Active { .. } => false,
  690        }
  691    }
  692
  693    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  694        if let EditPredictionPreview::Active {
  695            previous_scroll_position,
  696            ..
  697        } = self
  698        {
  699            *previous_scroll_position = scroll_position;
  700        }
  701    }
  702}
  703
  704pub struct ContextMenuOptions {
  705    pub min_entries_visible: usize,
  706    pub max_entries_visible: usize,
  707    pub placement: Option<ContextMenuPlacement>,
  708}
  709
  710#[derive(Debug, Clone, PartialEq, Eq)]
  711pub enum ContextMenuPlacement {
  712    Above,
  713    Below,
  714}
  715
  716#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  717struct EditorActionId(usize);
  718
  719impl EditorActionId {
  720    pub fn post_inc(&mut self) -> Self {
  721        let answer = self.0;
  722
  723        *self = Self(answer + 1);
  724
  725        Self(answer)
  726    }
  727}
  728
  729// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  730// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  731
  732type BackgroundHighlight = (
  733    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  734    Arc<[Range<Anchor>]>,
  735);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  827pub enum BufferSerialization {
  828    All,
  829    NonDirtyBuffers,
  830}
  831
  832impl BufferSerialization {
  833    fn new(restore_unsaved_buffers: bool) -> Self {
  834        if restore_unsaved_buffers {
  835            Self::All
  836        } else {
  837            Self::NonDirtyBuffers
  838        }
  839    }
  840}
  841
  842#[derive(Clone, Debug)]
  843struct RunnableTasks {
  844    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  845    offset: multi_buffer::Anchor,
  846    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  847    column: u32,
  848    // Values of all named captures, including those starting with '_'
  849    extra_variables: HashMap<String, String>,
  850    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  851    context_range: Range<BufferOffset>,
  852}
  853
  854impl RunnableTasks {
  855    fn resolve<'a>(
  856        &'a self,
  857        cx: &'a task::TaskContext,
  858    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  859        self.templates.iter().filter_map(|(kind, template)| {
  860            template
  861                .resolve_task(&kind.to_id_base(), cx)
  862                .map(|task| (kind.clone(), task))
  863        })
  864    }
  865}
  866
  867#[derive(Clone)]
  868pub struct ResolvedTasks {
  869    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  870    position: Anchor,
  871}
  872
  873/// Addons allow storing per-editor state in other crates (e.g. Vim)
  874pub trait Addon: 'static {
  875    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  876
  877    fn render_buffer_header_controls(
  878        &self,
  879        _: &ExcerptInfo,
  880        _: &Window,
  881        _: &App,
  882    ) -> Option<AnyElement> {
  883        None
  884    }
  885
  886    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  887        None
  888    }
  889
  890    fn to_any(&self) -> &dyn std::any::Any;
  891
  892    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  893        None
  894    }
  895}
  896
  897struct ChangeLocation {
  898    current: Option<Vec<Anchor>>,
  899    original: Vec<Anchor>,
  900}
  901impl ChangeLocation {
  902    fn locations(&self) -> &[Anchor] {
  903        self.current.as_ref().unwrap_or(&self.original)
  904    }
  905}
  906
  907/// A set of caret positions, registered when the editor was edited.
  908pub struct ChangeList {
  909    changes: Vec<ChangeLocation>,
  910    /// Currently "selected" change.
  911    position: Option<usize>,
  912}
  913
  914impl ChangeList {
  915    pub fn new() -> Self {
  916        Self {
  917            changes: Vec::new(),
  918            position: None,
  919        }
  920    }
  921
  922    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  923    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  924    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  925        if self.changes.is_empty() {
  926            return None;
  927        }
  928
  929        let prev = self.position.unwrap_or(self.changes.len());
  930        let next = if direction == Direction::Prev {
  931            prev.saturating_sub(count)
  932        } else {
  933            (prev + count).min(self.changes.len() - 1)
  934        };
  935        self.position = Some(next);
  936        self.changes.get(next).map(|change| change.locations())
  937    }
  938
  939    /// Adds a new change to the list, resetting the change list position.
  940    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  941        self.position.take();
  942        if let Some(last) = self.changes.last_mut()
  943            && group
  944        {
  945            last.current = Some(new_positions)
  946        } else {
  947            self.changes.push(ChangeLocation {
  948                original: new_positions,
  949                current: None,
  950            });
  951        }
  952    }
  953
  954    pub fn last(&self) -> Option<&[Anchor]> {
  955        self.changes.last().map(|change| change.locations())
  956    }
  957
  958    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  959        self.changes.last().map(|change| change.original.as_slice())
  960    }
  961
  962    pub fn invert_last_group(&mut self) {
  963        if let Some(last) = self.changes.last_mut()
  964            && let Some(current) = last.current.as_mut()
  965        {
  966            mem::swap(&mut last.original, current);
  967        }
  968    }
  969}
  970
  971#[derive(Clone)]
  972struct InlineBlamePopoverState {
  973    scroll_handle: ScrollHandle,
  974    commit_message: Option<ParsedCommitMessage>,
  975    markdown: Entity<Markdown>,
  976}
  977
  978struct InlineBlamePopover {
  979    position: gpui::Point<Pixels>,
  980    hide_task: Option<Task<()>>,
  981    popover_bounds: Option<Bounds<Pixels>>,
  982    popover_state: InlineBlamePopoverState,
  983    keyboard_grace: bool,
  984}
  985
  986enum SelectionDragState {
  987    /// State when no drag related activity is detected.
  988    None,
  989    /// State when the mouse is down on a selection that is about to be dragged.
  990    ReadyToDrag {
  991        selection: Selection<Anchor>,
  992        click_position: gpui::Point<Pixels>,
  993        mouse_down_time: Instant,
  994    },
  995    /// State when the mouse is dragging the selection in the editor.
  996    Dragging {
  997        selection: Selection<Anchor>,
  998        drop_cursor: Selection<Anchor>,
  999        hide_drop_cursor: bool,
 1000    },
 1001}
 1002
 1003enum ColumnarSelectionState {
 1004    FromMouse {
 1005        selection_tail: Anchor,
 1006        display_point: Option<DisplayPoint>,
 1007    },
 1008    FromSelection {
 1009        selection_tail: Anchor,
 1010    },
 1011}
 1012
 1013/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1014/// a breakpoint on them.
 1015#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1016struct PhantomBreakpointIndicator {
 1017    display_row: DisplayRow,
 1018    /// There's a small debounce between hovering over the line and showing the indicator.
 1019    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1020    is_active: bool,
 1021    collides_with_existing_breakpoint: bool,
 1022}
 1023
 1024/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1025/// in diff view mode.
 1026#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1027pub(crate) struct PhantomDiffReviewIndicator {
 1028    pub display_row: DisplayRow,
 1029    /// There's a small debounce between hovering over the line and showing the indicator.
 1030    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1031    pub is_active: bool,
 1032}
 1033
 1034/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1035///
 1036/// See the [module level documentation](self) for more information.
 1037pub struct Editor {
 1038    focus_handle: FocusHandle,
 1039    last_focused_descendant: Option<WeakFocusHandle>,
 1040    /// The text buffer being edited
 1041    buffer: Entity<MultiBuffer>,
 1042    /// Map of how text in the buffer should be displayed.
 1043    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1044    pub display_map: Entity<DisplayMap>,
 1045    placeholder_display_map: Option<Entity<DisplayMap>>,
 1046    pub selections: SelectionsCollection,
 1047    pub scroll_manager: ScrollManager,
 1048    /// When inline assist editors are linked, they all render cursors because
 1049    /// typing enters text into each of them, even the ones that aren't focused.
 1050    pub(crate) show_cursor_when_unfocused: bool,
 1051    columnar_selection_state: Option<ColumnarSelectionState>,
 1052    add_selections_state: Option<AddSelectionsState>,
 1053    select_next_state: Option<SelectNextState>,
 1054    select_prev_state: Option<SelectNextState>,
 1055    selection_history: SelectionHistory,
 1056    defer_selection_effects: bool,
 1057    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1058    autoclose_regions: Vec<AutocloseRegion>,
 1059    snippet_stack: InvalidationStack<SnippetState>,
 1060    select_syntax_node_history: SelectSyntaxNodeHistory,
 1061    ime_transaction: Option<TransactionId>,
 1062    pub diagnostics_max_severity: DiagnosticSeverity,
 1063    active_diagnostics: ActiveDiagnostic,
 1064    show_inline_diagnostics: bool,
 1065    inline_diagnostics_update: Task<()>,
 1066    inline_diagnostics_enabled: bool,
 1067    diagnostics_enabled: bool,
 1068    word_completions_enabled: bool,
 1069    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1070    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1071    hard_wrap: Option<usize>,
 1072    project: Option<Entity<Project>>,
 1073    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1074    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1075    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1076    blink_manager: Entity<BlinkManager>,
 1077    show_cursor_names: bool,
 1078    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1079    pub show_local_selections: bool,
 1080    mode: EditorMode,
 1081    show_breadcrumbs: bool,
 1082    show_gutter: bool,
 1083    show_scrollbars: ScrollbarAxes,
 1084    minimap_visibility: MinimapVisibility,
 1085    offset_content: bool,
 1086    disable_expand_excerpt_buttons: bool,
 1087    delegate_expand_excerpts: bool,
 1088    show_line_numbers: Option<bool>,
 1089    use_relative_line_numbers: Option<bool>,
 1090    show_git_diff_gutter: Option<bool>,
 1091    show_code_actions: Option<bool>,
 1092    show_runnables: Option<bool>,
 1093    show_breakpoints: Option<bool>,
 1094    show_diff_review_button: bool,
 1095    show_wrap_guides: Option<bool>,
 1096    show_indent_guides: Option<bool>,
 1097    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1098    highlight_order: usize,
 1099    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1100    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1101    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1102    scrollbar_marker_state: ScrollbarMarkerState,
 1103    active_indent_guides_state: ActiveIndentGuidesState,
 1104    nav_history: Option<ItemNavHistory>,
 1105    context_menu: RefCell<Option<CodeContextMenu>>,
 1106    context_menu_options: Option<ContextMenuOptions>,
 1107    mouse_context_menu: Option<MouseContextMenu>,
 1108    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1109    inline_blame_popover: Option<InlineBlamePopover>,
 1110    inline_blame_popover_show_task: Option<Task<()>>,
 1111    signature_help_state: SignatureHelpState,
 1112    auto_signature_help: Option<bool>,
 1113    find_all_references_task_sources: Vec<Anchor>,
 1114    next_completion_id: CompletionId,
 1115    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1116    code_actions_task: Option<Task<Result<()>>>,
 1117    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1118    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1119    debounced_selection_highlight_complete: bool,
 1120    document_highlights_task: Option<Task<()>>,
 1121    linked_editing_range_task: Option<Task<Option<()>>>,
 1122    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1123    pending_rename: Option<RenameState>,
 1124    searchable: bool,
 1125    cursor_shape: CursorShape,
 1126    /// Whether the cursor is offset one character to the left when something is
 1127    /// selected (needed for vim visual mode)
 1128    cursor_offset_on_selection: bool,
 1129    current_line_highlight: Option<CurrentLineHighlight>,
 1130    pub collapse_matches: bool,
 1131    autoindent_mode: Option<AutoindentMode>,
 1132    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1133    input_enabled: bool,
 1134    use_modal_editing: bool,
 1135    read_only: bool,
 1136    leader_id: Option<CollaboratorId>,
 1137    remote_id: Option<ViewId>,
 1138    pub hover_state: HoverState,
 1139    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1140    prev_pressure_stage: Option<PressureStage>,
 1141    gutter_hovered: bool,
 1142    hovered_link_state: Option<HoveredLinkState>,
 1143    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1144    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1145    active_edit_prediction: Option<EditPredictionState>,
 1146    /// Used to prevent flickering as the user types while the menu is open
 1147    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1148    edit_prediction_settings: EditPredictionSettings,
 1149    edit_predictions_hidden_for_vim_mode: bool,
 1150    show_edit_predictions_override: Option<bool>,
 1151    show_completions_on_input_override: Option<bool>,
 1152    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1153    edit_prediction_preview: EditPredictionPreview,
 1154    edit_prediction_indent_conflict: bool,
 1155    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1156    next_inlay_id: usize,
 1157    next_color_inlay_id: usize,
 1158    _subscriptions: Vec<Subscription>,
 1159    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1160    gutter_dimensions: GutterDimensions,
 1161    style: Option<EditorStyle>,
 1162    text_style_refinement: Option<TextStyleRefinement>,
 1163    next_editor_action_id: EditorActionId,
 1164    editor_actions: Rc<
 1165        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1166    >,
 1167    use_autoclose: bool,
 1168    use_auto_surround: bool,
 1169    auto_replace_emoji_shortcode: bool,
 1170    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1171    show_git_blame_gutter: bool,
 1172    show_git_blame_inline: bool,
 1173    show_git_blame_inline_delay_task: Option<Task<()>>,
 1174    git_blame_inline_enabled: bool,
 1175    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1176    buffer_serialization: Option<BufferSerialization>,
 1177    show_selection_menu: Option<bool>,
 1178    blame: Option<Entity<GitBlame>>,
 1179    blame_subscription: Option<Subscription>,
 1180    custom_context_menu: Option<
 1181        Box<
 1182            dyn 'static
 1183                + Fn(
 1184                    &mut Self,
 1185                    DisplayPoint,
 1186                    &mut Window,
 1187                    &mut Context<Self>,
 1188                ) -> Option<Entity<ui::ContextMenu>>,
 1189        >,
 1190    >,
 1191    last_bounds: Option<Bounds<Pixels>>,
 1192    last_position_map: Option<Rc<PositionMap>>,
 1193    expect_bounds_change: Option<Bounds<Pixels>>,
 1194    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1195    tasks_update_task: Option<Task<()>>,
 1196    breakpoint_store: Option<Entity<BreakpointStore>>,
 1197    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1198    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1199    hovered_diff_hunk_row: Option<DisplayRow>,
 1200    pull_diagnostics_task: Task<()>,
 1201    pull_diagnostics_background_task: Task<()>,
 1202    in_project_search: bool,
 1203    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1204    breadcrumb_header: Option<String>,
 1205    focused_block: Option<FocusedBlock>,
 1206    next_scroll_position: NextScrollCursorCenterTopBottom,
 1207    addons: HashMap<TypeId, Box<dyn Addon>>,
 1208    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1209    load_diff_task: Option<Shared<Task<()>>>,
 1210    /// Whether we are temporarily displaying a diff other than git's
 1211    temporary_diff_override: bool,
 1212    selection_mark_mode: bool,
 1213    toggle_fold_multiple_buffers: Task<()>,
 1214    _scroll_cursor_center_top_bottom_task: Task<()>,
 1215    serialize_selections: Task<()>,
 1216    serialize_folds: Task<()>,
 1217    mouse_cursor_hidden: bool,
 1218    minimap: Option<Entity<Self>>,
 1219    hide_mouse_mode: HideMouseMode,
 1220    pub change_list: ChangeList,
 1221    inline_value_cache: InlineValueCache,
 1222    number_deleted_lines: bool,
 1223
 1224    selection_drag_state: SelectionDragState,
 1225    colors: Option<LspColorData>,
 1226    post_scroll_update: Task<()>,
 1227    refresh_colors_task: Task<()>,
 1228    inlay_hints: Option<LspInlayHintData>,
 1229    folding_newlines: Task<()>,
 1230    select_next_is_case_sensitive: Option<bool>,
 1231    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1232    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1233    accent_data: Option<AccentData>,
 1234    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1235}
 1236
 1237#[derive(Debug, PartialEq)]
 1238struct AccentData {
 1239    colors: AccentColors,
 1240    overrides: Vec<SharedString>,
 1241}
 1242
 1243fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1244    if debounce_ms > 0 {
 1245        Some(Duration::from_millis(debounce_ms))
 1246    } else {
 1247        None
 1248    }
 1249}
 1250
 1251#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1252enum NextScrollCursorCenterTopBottom {
 1253    #[default]
 1254    Center,
 1255    Top,
 1256    Bottom,
 1257}
 1258
 1259impl NextScrollCursorCenterTopBottom {
 1260    fn next(&self) -> Self {
 1261        match self {
 1262            Self::Center => Self::Top,
 1263            Self::Top => Self::Bottom,
 1264            Self::Bottom => Self::Center,
 1265        }
 1266    }
 1267}
 1268
 1269#[derive(Clone)]
 1270pub struct EditorSnapshot {
 1271    pub mode: EditorMode,
 1272    show_gutter: bool,
 1273    offset_content: bool,
 1274    show_line_numbers: Option<bool>,
 1275    number_deleted_lines: bool,
 1276    show_git_diff_gutter: Option<bool>,
 1277    show_code_actions: Option<bool>,
 1278    show_runnables: Option<bool>,
 1279    show_breakpoints: Option<bool>,
 1280    git_blame_gutter_max_author_length: Option<usize>,
 1281    pub display_snapshot: DisplaySnapshot,
 1282    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1283    is_focused: bool,
 1284    scroll_anchor: ScrollAnchor,
 1285    ongoing_scroll: OngoingScroll,
 1286    current_line_highlight: CurrentLineHighlight,
 1287    gutter_hovered: bool,
 1288}
 1289
 1290#[derive(Default, Debug, Clone, Copy)]
 1291pub struct GutterDimensions {
 1292    pub left_padding: Pixels,
 1293    pub right_padding: Pixels,
 1294    pub width: Pixels,
 1295    pub margin: Pixels,
 1296    pub git_blame_entries_width: Option<Pixels>,
 1297}
 1298
 1299impl GutterDimensions {
 1300    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1301        Self {
 1302            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1303            ..Default::default()
 1304        }
 1305    }
 1306
 1307    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1308        -cx.text_system().descent(font_id, font_size)
 1309    }
 1310    /// The full width of the space taken up by the gutter.
 1311    pub fn full_width(&self) -> Pixels {
 1312        self.margin + self.width
 1313    }
 1314
 1315    /// The width of the space reserved for the fold indicators,
 1316    /// use alongside 'justify_end' and `gutter_width` to
 1317    /// right align content with the line numbers
 1318    pub fn fold_area_width(&self) -> Pixels {
 1319        self.margin + self.right_padding
 1320    }
 1321}
 1322
 1323struct CharacterDimensions {
 1324    em_width: Pixels,
 1325    em_advance: Pixels,
 1326    line_height: Pixels,
 1327}
 1328
 1329#[derive(Debug)]
 1330pub struct RemoteSelection {
 1331    pub replica_id: ReplicaId,
 1332    pub selection: Selection<Anchor>,
 1333    pub cursor_shape: CursorShape,
 1334    pub collaborator_id: CollaboratorId,
 1335    pub line_mode: bool,
 1336    pub user_name: Option<SharedString>,
 1337    pub color: PlayerColor,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct SelectionHistoryEntry {
 1342    selections: Arc<[Selection<Anchor>]>,
 1343    select_next_state: Option<SelectNextState>,
 1344    select_prev_state: Option<SelectNextState>,
 1345    add_selections_state: Option<AddSelectionsState>,
 1346}
 1347
 1348#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1349enum SelectionHistoryMode {
 1350    #[default]
 1351    Normal,
 1352    Undoing,
 1353    Redoing,
 1354    Skipping,
 1355}
 1356
 1357#[derive(Clone, PartialEq, Eq, Hash)]
 1358struct HoveredCursor {
 1359    replica_id: ReplicaId,
 1360    selection_id: usize,
 1361}
 1362
 1363#[derive(Debug)]
 1364/// SelectionEffects controls the side-effects of updating the selection.
 1365///
 1366/// The default behaviour does "what you mostly want":
 1367/// - it pushes to the nav history if the cursor moved by >10 lines
 1368/// - it re-triggers completion requests
 1369/// - it scrolls to fit
 1370///
 1371/// You might want to modify these behaviours. For example when doing a "jump"
 1372/// like go to definition, we always want to add to nav history; but when scrolling
 1373/// in vim mode we never do.
 1374///
 1375/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1376/// move.
 1377#[derive(Clone)]
 1378pub struct SelectionEffects {
 1379    nav_history: Option<bool>,
 1380    completions: bool,
 1381    scroll: Option<Autoscroll>,
 1382}
 1383
 1384impl Default for SelectionEffects {
 1385    fn default() -> Self {
 1386        Self {
 1387            nav_history: None,
 1388            completions: true,
 1389            scroll: Some(Autoscroll::fit()),
 1390        }
 1391    }
 1392}
 1393impl SelectionEffects {
 1394    pub fn scroll(scroll: Autoscroll) -> Self {
 1395        Self {
 1396            scroll: Some(scroll),
 1397            ..Default::default()
 1398        }
 1399    }
 1400
 1401    pub fn no_scroll() -> Self {
 1402        Self {
 1403            scroll: None,
 1404            ..Default::default()
 1405        }
 1406    }
 1407
 1408    pub fn completions(self, completions: bool) -> Self {
 1409        Self {
 1410            completions,
 1411            ..self
 1412        }
 1413    }
 1414
 1415    pub fn nav_history(self, nav_history: bool) -> Self {
 1416        Self {
 1417            nav_history: Some(nav_history),
 1418            ..self
 1419        }
 1420    }
 1421}
 1422
 1423struct DeferredSelectionEffectsState {
 1424    changed: bool,
 1425    effects: SelectionEffects,
 1426    old_cursor_position: Anchor,
 1427    history_entry: SelectionHistoryEntry,
 1428}
 1429
 1430#[derive(Default)]
 1431struct SelectionHistory {
 1432    #[allow(clippy::type_complexity)]
 1433    selections_by_transaction:
 1434        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1435    mode: SelectionHistoryMode,
 1436    undo_stack: VecDeque<SelectionHistoryEntry>,
 1437    redo_stack: VecDeque<SelectionHistoryEntry>,
 1438}
 1439
 1440impl SelectionHistory {
 1441    #[track_caller]
 1442    fn insert_transaction(
 1443        &mut self,
 1444        transaction_id: TransactionId,
 1445        selections: Arc<[Selection<Anchor>]>,
 1446    ) {
 1447        if selections.is_empty() {
 1448            log::error!(
 1449                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1450                std::panic::Location::caller()
 1451            );
 1452            return;
 1453        }
 1454        self.selections_by_transaction
 1455            .insert(transaction_id, (selections, None));
 1456    }
 1457
 1458    #[allow(clippy::type_complexity)]
 1459    fn transaction(
 1460        &self,
 1461        transaction_id: TransactionId,
 1462    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1463        self.selections_by_transaction.get(&transaction_id)
 1464    }
 1465
 1466    #[allow(clippy::type_complexity)]
 1467    fn transaction_mut(
 1468        &mut self,
 1469        transaction_id: TransactionId,
 1470    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1471        self.selections_by_transaction.get_mut(&transaction_id)
 1472    }
 1473
 1474    fn push(&mut self, entry: SelectionHistoryEntry) {
 1475        if !entry.selections.is_empty() {
 1476            match self.mode {
 1477                SelectionHistoryMode::Normal => {
 1478                    self.push_undo(entry);
 1479                    self.redo_stack.clear();
 1480                }
 1481                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1482                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1483                SelectionHistoryMode::Skipping => {}
 1484            }
 1485        }
 1486    }
 1487
 1488    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1489        if self
 1490            .undo_stack
 1491            .back()
 1492            .is_none_or(|e| e.selections != entry.selections)
 1493        {
 1494            self.undo_stack.push_back(entry);
 1495            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1496                self.undo_stack.pop_front();
 1497            }
 1498        }
 1499    }
 1500
 1501    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1502        if self
 1503            .redo_stack
 1504            .back()
 1505            .is_none_or(|e| e.selections != entry.selections)
 1506        {
 1507            self.redo_stack.push_back(entry);
 1508            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1509                self.redo_stack.pop_front();
 1510            }
 1511        }
 1512    }
 1513}
 1514
 1515#[derive(Clone, Copy)]
 1516pub struct RowHighlightOptions {
 1517    pub autoscroll: bool,
 1518    pub include_gutter: bool,
 1519}
 1520
 1521impl Default for RowHighlightOptions {
 1522    fn default() -> Self {
 1523        Self {
 1524            autoscroll: Default::default(),
 1525            include_gutter: true,
 1526        }
 1527    }
 1528}
 1529
 1530struct RowHighlight {
 1531    index: usize,
 1532    range: Range<Anchor>,
 1533    color: Hsla,
 1534    options: RowHighlightOptions,
 1535    type_id: TypeId,
 1536}
 1537
 1538#[derive(Clone, Debug)]
 1539struct AddSelectionsState {
 1540    groups: Vec<AddSelectionsGroup>,
 1541}
 1542
 1543#[derive(Clone, Debug)]
 1544struct AddSelectionsGroup {
 1545    above: bool,
 1546    stack: Vec<usize>,
 1547}
 1548
 1549#[derive(Clone)]
 1550struct SelectNextState {
 1551    query: AhoCorasick,
 1552    wordwise: bool,
 1553    done: bool,
 1554}
 1555
 1556impl std::fmt::Debug for SelectNextState {
 1557    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1558        f.debug_struct(std::any::type_name::<Self>())
 1559            .field("wordwise", &self.wordwise)
 1560            .field("done", &self.done)
 1561            .finish()
 1562    }
 1563}
 1564
 1565#[derive(Debug)]
 1566struct AutocloseRegion {
 1567    selection_id: usize,
 1568    range: Range<Anchor>,
 1569    pair: BracketPair,
 1570}
 1571
 1572#[derive(Debug)]
 1573struct SnippetState {
 1574    ranges: Vec<Vec<Range<Anchor>>>,
 1575    active_index: usize,
 1576    choices: Vec<Option<Vec<String>>>,
 1577}
 1578
 1579#[doc(hidden)]
 1580pub struct RenameState {
 1581    pub range: Range<Anchor>,
 1582    pub old_name: Arc<str>,
 1583    pub editor: Entity<Editor>,
 1584    block_id: CustomBlockId,
 1585}
 1586
 1587struct InvalidationStack<T>(Vec<T>);
 1588
 1589struct RegisteredEditPredictionDelegate {
 1590    provider: Arc<dyn EditPredictionDelegateHandle>,
 1591    _subscription: Subscription,
 1592}
 1593
 1594#[derive(Debug, PartialEq, Eq)]
 1595pub struct ActiveDiagnosticGroup {
 1596    pub active_range: Range<Anchor>,
 1597    pub active_message: String,
 1598    pub group_id: usize,
 1599    pub blocks: HashSet<CustomBlockId>,
 1600}
 1601
 1602#[derive(Debug, PartialEq, Eq)]
 1603
 1604pub(crate) enum ActiveDiagnostic {
 1605    None,
 1606    All,
 1607    Group(ActiveDiagnosticGroup),
 1608}
 1609
 1610#[derive(Serialize, Deserialize, Clone, Debug)]
 1611pub struct ClipboardSelection {
 1612    /// The number of bytes in this selection.
 1613    pub len: usize,
 1614    /// Whether this was a full-line selection.
 1615    pub is_entire_line: bool,
 1616    /// The indentation of the first line when this content was originally copied.
 1617    pub first_line_indent: u32,
 1618    #[serde(default)]
 1619    pub file_path: Option<PathBuf>,
 1620    #[serde(default)]
 1621    pub line_range: Option<RangeInclusive<u32>>,
 1622}
 1623
 1624impl ClipboardSelection {
 1625    pub fn for_buffer(
 1626        len: usize,
 1627        is_entire_line: bool,
 1628        range: Range<Point>,
 1629        buffer: &MultiBufferSnapshot,
 1630        project: Option<&Entity<Project>>,
 1631        cx: &App,
 1632    ) -> Self {
 1633        let first_line_indent = buffer
 1634            .indent_size_for_line(MultiBufferRow(range.start.row))
 1635            .len;
 1636
 1637        let file_path = util::maybe!({
 1638            let project = project?.read(cx);
 1639            let file = buffer.file_at(range.start)?;
 1640            let project_path = ProjectPath {
 1641                worktree_id: file.worktree_id(cx),
 1642                path: file.path().clone(),
 1643            };
 1644            project.absolute_path(&project_path, cx)
 1645        });
 1646
 1647        let line_range = file_path.as_ref().and_then(|_| {
 1648            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1649            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1650            if start_excerpt_id == end_excerpt_id {
 1651                Some(start_point.row..=end_point.row)
 1652            } else {
 1653                None
 1654            }
 1655        });
 1656
 1657        Self {
 1658            len,
 1659            is_entire_line,
 1660            first_line_indent,
 1661            file_path,
 1662            line_range,
 1663        }
 1664    }
 1665}
 1666
 1667// selections, scroll behavior, was newest selection reversed
 1668type SelectSyntaxNodeHistoryState = (
 1669    Box<[Selection<MultiBufferOffset>]>,
 1670    SelectSyntaxNodeScrollBehavior,
 1671    bool,
 1672);
 1673
 1674#[derive(Default)]
 1675struct SelectSyntaxNodeHistory {
 1676    stack: Vec<SelectSyntaxNodeHistoryState>,
 1677    // disable temporarily to allow changing selections without losing the stack
 1678    pub disable_clearing: bool,
 1679}
 1680
 1681impl SelectSyntaxNodeHistory {
 1682    pub fn try_clear(&mut self) {
 1683        if !self.disable_clearing {
 1684            self.stack.clear();
 1685        }
 1686    }
 1687
 1688    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1689        self.stack.push(selection);
 1690    }
 1691
 1692    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1693        self.stack.pop()
 1694    }
 1695}
 1696
 1697enum SelectSyntaxNodeScrollBehavior {
 1698    CursorTop,
 1699    FitSelection,
 1700    CursorBottom,
 1701}
 1702
 1703#[derive(Debug)]
 1704pub(crate) struct NavigationData {
 1705    cursor_anchor: Anchor,
 1706    cursor_position: Point,
 1707    scroll_anchor: ScrollAnchor,
 1708    scroll_top_row: u32,
 1709}
 1710
 1711#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1712pub enum GotoDefinitionKind {
 1713    Symbol,
 1714    Declaration,
 1715    Type,
 1716    Implementation,
 1717}
 1718
 1719pub enum FormatTarget {
 1720    Buffers(HashSet<Entity<Buffer>>),
 1721    Ranges(Vec<Range<MultiBufferPoint>>),
 1722}
 1723
 1724pub(crate) struct FocusedBlock {
 1725    id: BlockId,
 1726    focus_handle: WeakFocusHandle,
 1727}
 1728
 1729#[derive(Clone, Debug)]
 1730enum JumpData {
 1731    MultiBufferRow {
 1732        row: MultiBufferRow,
 1733        line_offset_from_top: u32,
 1734    },
 1735    MultiBufferPoint {
 1736        excerpt_id: ExcerptId,
 1737        position: Point,
 1738        anchor: text::Anchor,
 1739        line_offset_from_top: u32,
 1740    },
 1741}
 1742
 1743pub enum MultibufferSelectionMode {
 1744    First,
 1745    All,
 1746}
 1747
 1748#[derive(Clone, Copy, Debug, Default)]
 1749pub struct RewrapOptions {
 1750    pub override_language_settings: bool,
 1751    pub preserve_existing_whitespace: bool,
 1752}
 1753
 1754impl Editor {
 1755    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let buffer = cx.new(|cx| Buffer::local("", cx));
 1757        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1758        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1759    }
 1760
 1761    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1762        let buffer = cx.new(|cx| Buffer::local("", cx));
 1763        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1764        Self::new(EditorMode::full(), buffer, None, window, cx)
 1765    }
 1766
 1767    pub fn auto_height(
 1768        min_lines: usize,
 1769        max_lines: usize,
 1770        window: &mut Window,
 1771        cx: &mut Context<Self>,
 1772    ) -> Self {
 1773        let buffer = cx.new(|cx| Buffer::local("", cx));
 1774        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1775        Self::new(
 1776            EditorMode::AutoHeight {
 1777                min_lines,
 1778                max_lines: Some(max_lines),
 1779            },
 1780            buffer,
 1781            None,
 1782            window,
 1783            cx,
 1784        )
 1785    }
 1786
 1787    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1788    /// The editor grows as tall as needed to fit its content.
 1789    pub fn auto_height_unbounded(
 1790        min_lines: usize,
 1791        window: &mut Window,
 1792        cx: &mut Context<Self>,
 1793    ) -> Self {
 1794        let buffer = cx.new(|cx| Buffer::local("", cx));
 1795        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1796        Self::new(
 1797            EditorMode::AutoHeight {
 1798                min_lines,
 1799                max_lines: None,
 1800            },
 1801            buffer,
 1802            None,
 1803            window,
 1804            cx,
 1805        )
 1806    }
 1807
 1808    pub fn for_buffer(
 1809        buffer: Entity<Buffer>,
 1810        project: Option<Entity<Project>>,
 1811        window: &mut Window,
 1812        cx: &mut Context<Self>,
 1813    ) -> Self {
 1814        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1815        Self::new(EditorMode::full(), buffer, project, window, cx)
 1816    }
 1817
 1818    pub fn for_multibuffer(
 1819        buffer: Entity<MultiBuffer>,
 1820        project: Option<Entity<Project>>,
 1821        window: &mut Window,
 1822        cx: &mut Context<Self>,
 1823    ) -> Self {
 1824        Self::new(EditorMode::full(), buffer, project, window, cx)
 1825    }
 1826
 1827    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1828        let mut clone = Self::new(
 1829            self.mode.clone(),
 1830            self.buffer.clone(),
 1831            self.project.clone(),
 1832            window,
 1833            cx,
 1834        );
 1835        self.display_map.update(cx, |display_map, cx| {
 1836            let snapshot = display_map.snapshot(cx);
 1837            clone.display_map.update(cx, |display_map, cx| {
 1838                display_map.set_state(&snapshot, cx);
 1839            });
 1840        });
 1841        clone.folds_did_change(cx);
 1842        clone.selections.clone_state(&self.selections);
 1843        clone.scroll_manager.clone_state(&self.scroll_manager);
 1844        clone.searchable = self.searchable;
 1845        clone.read_only = self.read_only;
 1846        clone
 1847    }
 1848
 1849    pub fn new(
 1850        mode: EditorMode,
 1851        buffer: Entity<MultiBuffer>,
 1852        project: Option<Entity<Project>>,
 1853        window: &mut Window,
 1854        cx: &mut Context<Self>,
 1855    ) -> Self {
 1856        Editor::new_internal(mode, buffer, project, None, window, cx)
 1857    }
 1858
 1859    pub fn sticky_headers(
 1860        &self,
 1861        style: &EditorStyle,
 1862        cx: &App,
 1863    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1864        let multi_buffer = self.buffer().read(cx);
 1865        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1866        let multi_buffer_visible_start = self
 1867            .scroll_manager
 1868            .anchor()
 1869            .anchor
 1870            .to_point(&multi_buffer_snapshot);
 1871        let max_row = multi_buffer_snapshot.max_point().row;
 1872
 1873        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1874        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1875
 1876        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1877            let outline_items = buffer
 1878                .outline_items_containing(
 1879                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1880                    true,
 1881                    Some(style.syntax.as_ref()),
 1882                )
 1883                .into_iter()
 1884                .map(|outline_item| OutlineItem {
 1885                    depth: outline_item.depth,
 1886                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1887                    source_range_for_text: Anchor::range_in_buffer(
 1888                        *excerpt_id,
 1889                        outline_item.source_range_for_text,
 1890                    ),
 1891                    text: outline_item.text,
 1892                    highlight_ranges: outline_item.highlight_ranges,
 1893                    name_ranges: outline_item.name_ranges,
 1894                    body_range: outline_item
 1895                        .body_range
 1896                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1897                    annotation_range: outline_item
 1898                        .annotation_range
 1899                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1900                });
 1901            return Some(outline_items.collect());
 1902        }
 1903
 1904        None
 1905    }
 1906
 1907    fn new_internal(
 1908        mode: EditorMode,
 1909        multi_buffer: Entity<MultiBuffer>,
 1910        project: Option<Entity<Project>>,
 1911        display_map: Option<Entity<DisplayMap>>,
 1912        window: &mut Window,
 1913        cx: &mut Context<Self>,
 1914    ) -> Self {
 1915        debug_assert!(
 1916            display_map.is_none() || mode.is_minimap(),
 1917            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1918        );
 1919
 1920        let full_mode = mode.is_full();
 1921        let is_minimap = mode.is_minimap();
 1922        let diagnostics_max_severity = if full_mode {
 1923            EditorSettings::get_global(cx)
 1924                .diagnostics_max_severity
 1925                .unwrap_or(DiagnosticSeverity::Hint)
 1926        } else {
 1927            DiagnosticSeverity::Off
 1928        };
 1929        let style = window.text_style();
 1930        let font_size = style.font_size.to_pixels(window.rem_size());
 1931        let editor = cx.entity().downgrade();
 1932        let fold_placeholder = FoldPlaceholder {
 1933            constrain_width: false,
 1934            render: Arc::new(move |fold_id, fold_range, cx| {
 1935                let editor = editor.clone();
 1936                div()
 1937                    .id(fold_id)
 1938                    .bg(cx.theme().colors().ghost_element_background)
 1939                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1940                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1941                    .rounded_xs()
 1942                    .size_full()
 1943                    .cursor_pointer()
 1944                    .child("")
 1945                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1946                    .on_click(move |_, _window, cx| {
 1947                        editor
 1948                            .update(cx, |editor, cx| {
 1949                                editor.unfold_ranges(
 1950                                    &[fold_range.start..fold_range.end],
 1951                                    true,
 1952                                    false,
 1953                                    cx,
 1954                                );
 1955                                cx.stop_propagation();
 1956                            })
 1957                            .ok();
 1958                    })
 1959                    .into_any()
 1960            }),
 1961            merge_adjacent: true,
 1962            ..FoldPlaceholder::default()
 1963        };
 1964        let display_map = display_map.unwrap_or_else(|| {
 1965            cx.new(|cx| {
 1966                DisplayMap::new(
 1967                    multi_buffer.clone(),
 1968                    style.font(),
 1969                    font_size,
 1970                    None,
 1971                    FILE_HEADER_HEIGHT,
 1972                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1973                    fold_placeholder,
 1974                    diagnostics_max_severity,
 1975                    cx,
 1976                )
 1977            })
 1978        });
 1979
 1980        let selections = SelectionsCollection::new();
 1981
 1982        let blink_manager = cx.new(|cx| {
 1983            let mut blink_manager = BlinkManager::new(
 1984                CURSOR_BLINK_INTERVAL,
 1985                |cx| EditorSettings::get_global(cx).cursor_blink,
 1986                cx,
 1987            );
 1988            if is_minimap {
 1989                blink_manager.disable(cx);
 1990            }
 1991            blink_manager
 1992        });
 1993
 1994        let soft_wrap_mode_override =
 1995            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1996
 1997        let mut project_subscriptions = Vec::new();
 1998        if full_mode && let Some(project) = project.as_ref() {
 1999            project_subscriptions.push(cx.subscribe_in(
 2000                project,
 2001                window,
 2002                |editor, _, event, window, cx| match event {
 2003                    project::Event::RefreshCodeLens => {
 2004                        // we always query lens with actions, without storing them, always refreshing them
 2005                    }
 2006                    project::Event::RefreshInlayHints {
 2007                        server_id,
 2008                        request_id,
 2009                    } => {
 2010                        editor.refresh_inlay_hints(
 2011                            InlayHintRefreshReason::RefreshRequested {
 2012                                server_id: *server_id,
 2013                                request_id: *request_id,
 2014                            },
 2015                            cx,
 2016                        );
 2017                    }
 2018                    project::Event::LanguageServerRemoved(..) => {
 2019                        if editor.tasks_update_task.is_none() {
 2020                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2021                        }
 2022                        editor.registered_buffers.clear();
 2023                        editor.register_visible_buffers(cx);
 2024                    }
 2025                    project::Event::LanguageServerAdded(..) => {
 2026                        if editor.tasks_update_task.is_none() {
 2027                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2028                        }
 2029                    }
 2030                    project::Event::SnippetEdit(id, snippet_edits) => {
 2031                        // todo(lw): Non singletons
 2032                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2033                            let snapshot = buffer.read(cx).snapshot();
 2034                            let focus_handle = editor.focus_handle(cx);
 2035                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2036                                for (range, snippet) in snippet_edits {
 2037                                    let buffer_range =
 2038                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2039                                    editor
 2040                                        .insert_snippet(
 2041                                            &[MultiBufferOffset(buffer_range.start)
 2042                                                ..MultiBufferOffset(buffer_range.end)],
 2043                                            snippet.clone(),
 2044                                            window,
 2045                                            cx,
 2046                                        )
 2047                                        .ok();
 2048                                }
 2049                            }
 2050                        }
 2051                    }
 2052                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2053                        let buffer_id = *buffer_id;
 2054                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2055                            editor.register_buffer(buffer_id, cx);
 2056                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2057                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2058                            refresh_linked_ranges(editor, window, cx);
 2059                            editor.refresh_code_actions(window, cx);
 2060                            editor.refresh_document_highlights(cx);
 2061                        }
 2062                    }
 2063
 2064                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2065                        let Some(workspace) = editor.workspace() else {
 2066                            return;
 2067                        };
 2068                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2069                        else {
 2070                            return;
 2071                        };
 2072
 2073                        if active_editor.entity_id() == cx.entity_id() {
 2074                            let entity_id = cx.entity_id();
 2075                            workspace.update(cx, |this, cx| {
 2076                                this.panes_mut()
 2077                                    .iter_mut()
 2078                                    .filter(|pane| pane.entity_id() != entity_id)
 2079                                    .for_each(|p| {
 2080                                        p.update(cx, |pane, _| {
 2081                                            pane.nav_history_mut().rename_item(
 2082                                                entity_id,
 2083                                                project_path.clone(),
 2084                                                abs_path.clone().into(),
 2085                                            );
 2086                                        })
 2087                                    });
 2088                            });
 2089
 2090                            Self::open_transaction_for_hidden_buffers(
 2091                                workspace,
 2092                                transaction.clone(),
 2093                                "Rename".to_string(),
 2094                                window,
 2095                                cx,
 2096                            );
 2097                        }
 2098                    }
 2099
 2100                    project::Event::WorkspaceEditApplied(transaction) => {
 2101                        let Some(workspace) = editor.workspace() else {
 2102                            return;
 2103                        };
 2104                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2105                        else {
 2106                            return;
 2107                        };
 2108
 2109                        if active_editor.entity_id() == cx.entity_id() {
 2110                            Self::open_transaction_for_hidden_buffers(
 2111                                workspace,
 2112                                transaction.clone(),
 2113                                "LSP Edit".to_string(),
 2114                                window,
 2115                                cx,
 2116                            );
 2117                        }
 2118                    }
 2119
 2120                    _ => {}
 2121                },
 2122            ));
 2123            if let Some(task_inventory) = project
 2124                .read(cx)
 2125                .task_store()
 2126                .read(cx)
 2127                .task_inventory()
 2128                .cloned()
 2129            {
 2130                project_subscriptions.push(cx.observe_in(
 2131                    &task_inventory,
 2132                    window,
 2133                    |editor, _, window, cx| {
 2134                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2135                    },
 2136                ));
 2137            };
 2138
 2139            project_subscriptions.push(cx.subscribe_in(
 2140                &project.read(cx).breakpoint_store(),
 2141                window,
 2142                |editor, _, event, window, cx| match event {
 2143                    BreakpointStoreEvent::ClearDebugLines => {
 2144                        editor.clear_row_highlights::<ActiveDebugLine>();
 2145                        editor.refresh_inline_values(cx);
 2146                    }
 2147                    BreakpointStoreEvent::SetDebugLine => {
 2148                        if editor.go_to_active_debug_line(window, cx) {
 2149                            cx.stop_propagation();
 2150                        }
 2151
 2152                        editor.refresh_inline_values(cx);
 2153                    }
 2154                    _ => {}
 2155                },
 2156            ));
 2157            let git_store = project.read(cx).git_store().clone();
 2158            let project = project.clone();
 2159            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2160                if let GitStoreEvent::RepositoryAdded = event {
 2161                    this.load_diff_task = Some(
 2162                        update_uncommitted_diff_for_buffer(
 2163                            cx.entity(),
 2164                            &project,
 2165                            this.buffer.read(cx).all_buffers(),
 2166                            this.buffer.clone(),
 2167                            cx,
 2168                        )
 2169                        .shared(),
 2170                    );
 2171                }
 2172            }));
 2173        }
 2174
 2175        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2176
 2177        let inlay_hint_settings =
 2178            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2179        let focus_handle = cx.focus_handle();
 2180        if !is_minimap {
 2181            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2182                .detach();
 2183            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2184                .detach();
 2185            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2186                .detach();
 2187            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2188                .detach();
 2189            cx.observe_pending_input(window, Self::observe_pending_input)
 2190                .detach();
 2191        }
 2192
 2193        let show_indent_guides =
 2194            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2195                Some(false)
 2196            } else {
 2197                None
 2198            };
 2199
 2200        let breakpoint_store = match (&mode, project.as_ref()) {
 2201            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2202            _ => None,
 2203        };
 2204
 2205        let mut code_action_providers = Vec::new();
 2206        let mut load_uncommitted_diff = None;
 2207        if let Some(project) = project.clone() {
 2208            load_uncommitted_diff = Some(
 2209                update_uncommitted_diff_for_buffer(
 2210                    cx.entity(),
 2211                    &project,
 2212                    multi_buffer.read(cx).all_buffers(),
 2213                    multi_buffer.clone(),
 2214                    cx,
 2215                )
 2216                .shared(),
 2217            );
 2218            code_action_providers.push(Rc::new(project) as Rc<_>);
 2219        }
 2220
 2221        let mut editor = Self {
 2222            focus_handle,
 2223            show_cursor_when_unfocused: false,
 2224            last_focused_descendant: None,
 2225            buffer: multi_buffer.clone(),
 2226            display_map: display_map.clone(),
 2227            placeholder_display_map: None,
 2228            selections,
 2229            scroll_manager: ScrollManager::new(cx),
 2230            columnar_selection_state: None,
 2231            add_selections_state: None,
 2232            select_next_state: None,
 2233            select_prev_state: None,
 2234            selection_history: SelectionHistory::default(),
 2235            defer_selection_effects: false,
 2236            deferred_selection_effects_state: None,
 2237            autoclose_regions: Vec::new(),
 2238            snippet_stack: InvalidationStack::default(),
 2239            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2240            ime_transaction: None,
 2241            active_diagnostics: ActiveDiagnostic::None,
 2242            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2243            inline_diagnostics_update: Task::ready(()),
 2244            inline_diagnostics: Vec::new(),
 2245            soft_wrap_mode_override,
 2246            diagnostics_max_severity,
 2247            hard_wrap: None,
 2248            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2249            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2250            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2251            project,
 2252            blink_manager: blink_manager.clone(),
 2253            show_local_selections: true,
 2254            show_scrollbars: ScrollbarAxes {
 2255                horizontal: full_mode,
 2256                vertical: full_mode,
 2257            },
 2258            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2259            offset_content: !matches!(mode, EditorMode::SingleLine),
 2260            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2261            show_gutter: full_mode,
 2262            show_line_numbers: (!full_mode).then_some(false),
 2263            use_relative_line_numbers: None,
 2264            disable_expand_excerpt_buttons: !full_mode,
 2265            delegate_expand_excerpts: false,
 2266            show_git_diff_gutter: None,
 2267            show_code_actions: None,
 2268            show_runnables: None,
 2269            show_breakpoints: None,
 2270            show_diff_review_button: false,
 2271            show_wrap_guides: None,
 2272            show_indent_guides,
 2273            buffers_with_disabled_indent_guides: HashSet::default(),
 2274            highlight_order: 0,
 2275            highlighted_rows: HashMap::default(),
 2276            background_highlights: HashMap::default(),
 2277            gutter_highlights: HashMap::default(),
 2278            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2279            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2280            nav_history: None,
 2281            context_menu: RefCell::new(None),
 2282            context_menu_options: None,
 2283            mouse_context_menu: None,
 2284            completion_tasks: Vec::new(),
 2285            inline_blame_popover: None,
 2286            inline_blame_popover_show_task: None,
 2287            signature_help_state: SignatureHelpState::default(),
 2288            auto_signature_help: None,
 2289            find_all_references_task_sources: Vec::new(),
 2290            next_completion_id: 0,
 2291            next_inlay_id: 0,
 2292            code_action_providers,
 2293            available_code_actions: None,
 2294            code_actions_task: None,
 2295            quick_selection_highlight_task: None,
 2296            debounced_selection_highlight_task: None,
 2297            debounced_selection_highlight_complete: false,
 2298            document_highlights_task: None,
 2299            linked_editing_range_task: None,
 2300            pending_rename: None,
 2301            searchable: !is_minimap,
 2302            cursor_shape: EditorSettings::get_global(cx)
 2303                .cursor_shape
 2304                .unwrap_or_default(),
 2305            cursor_offset_on_selection: false,
 2306            current_line_highlight: None,
 2307            autoindent_mode: Some(AutoindentMode::EachLine),
 2308            collapse_matches: false,
 2309            workspace: None,
 2310            input_enabled: !is_minimap,
 2311            use_modal_editing: full_mode,
 2312            read_only: is_minimap,
 2313            use_autoclose: true,
 2314            use_auto_surround: true,
 2315            auto_replace_emoji_shortcode: false,
 2316            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2317            leader_id: None,
 2318            remote_id: None,
 2319            hover_state: HoverState::default(),
 2320            pending_mouse_down: None,
 2321            prev_pressure_stage: None,
 2322            hovered_link_state: None,
 2323            edit_prediction_provider: None,
 2324            active_edit_prediction: None,
 2325            stale_edit_prediction_in_menu: None,
 2326            edit_prediction_preview: EditPredictionPreview::Inactive {
 2327                released_too_fast: false,
 2328            },
 2329            inline_diagnostics_enabled: full_mode,
 2330            diagnostics_enabled: full_mode,
 2331            word_completions_enabled: full_mode,
 2332            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2333            gutter_hovered: false,
 2334            pixel_position_of_newest_cursor: None,
 2335            last_bounds: None,
 2336            last_position_map: None,
 2337            expect_bounds_change: None,
 2338            gutter_dimensions: GutterDimensions::default(),
 2339            style: None,
 2340            show_cursor_names: false,
 2341            hovered_cursors: HashMap::default(),
 2342            next_editor_action_id: EditorActionId::default(),
 2343            editor_actions: Rc::default(),
 2344            edit_predictions_hidden_for_vim_mode: false,
 2345            show_edit_predictions_override: None,
 2346            show_completions_on_input_override: None,
 2347            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2348            edit_prediction_settings: EditPredictionSettings::Disabled,
 2349            edit_prediction_indent_conflict: false,
 2350            edit_prediction_requires_modifier_in_indent_conflict: true,
 2351            custom_context_menu: None,
 2352            show_git_blame_gutter: false,
 2353            show_git_blame_inline: false,
 2354            show_selection_menu: None,
 2355            show_git_blame_inline_delay_task: None,
 2356            git_blame_inline_enabled: full_mode
 2357                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2358            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2359            buffer_serialization: is_minimap.not().then(|| {
 2360                BufferSerialization::new(
 2361                    ProjectSettings::get_global(cx)
 2362                        .session
 2363                        .restore_unsaved_buffers,
 2364                )
 2365            }),
 2366            blame: None,
 2367            blame_subscription: None,
 2368            tasks: BTreeMap::default(),
 2369
 2370            breakpoint_store,
 2371            gutter_breakpoint_indicator: (None, None),
 2372            gutter_diff_review_indicator: (None, None),
 2373            hovered_diff_hunk_row: None,
 2374            _subscriptions: (!is_minimap)
 2375                .then(|| {
 2376                    vec![
 2377                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2378                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2379                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2380                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2381                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2382                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2383                        cx.observe_window_activation(window, |editor, window, cx| {
 2384                            let active = window.is_window_active();
 2385                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2386                                if active {
 2387                                    blink_manager.enable(cx);
 2388                                } else {
 2389                                    blink_manager.disable(cx);
 2390                                }
 2391                            });
 2392                            if active {
 2393                                editor.show_mouse_cursor(cx);
 2394                            }
 2395                        }),
 2396                    ]
 2397                })
 2398                .unwrap_or_default(),
 2399            tasks_update_task: None,
 2400            pull_diagnostics_task: Task::ready(()),
 2401            pull_diagnostics_background_task: Task::ready(()),
 2402            colors: None,
 2403            refresh_colors_task: Task::ready(()),
 2404            inlay_hints: None,
 2405            next_color_inlay_id: 0,
 2406            post_scroll_update: Task::ready(()),
 2407            linked_edit_ranges: Default::default(),
 2408            in_project_search: false,
 2409            previous_search_ranges: None,
 2410            breadcrumb_header: None,
 2411            focused_block: None,
 2412            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2413            addons: HashMap::default(),
 2414            registered_buffers: HashMap::default(),
 2415            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2416            selection_mark_mode: false,
 2417            toggle_fold_multiple_buffers: Task::ready(()),
 2418            serialize_selections: Task::ready(()),
 2419            serialize_folds: Task::ready(()),
 2420            text_style_refinement: None,
 2421            load_diff_task: load_uncommitted_diff,
 2422            temporary_diff_override: false,
 2423            mouse_cursor_hidden: false,
 2424            minimap: None,
 2425            hide_mouse_mode: EditorSettings::get_global(cx)
 2426                .hide_mouse
 2427                .unwrap_or_default(),
 2428            change_list: ChangeList::new(),
 2429            mode,
 2430            selection_drag_state: SelectionDragState::None,
 2431            folding_newlines: Task::ready(()),
 2432            lookup_key: None,
 2433            select_next_is_case_sensitive: None,
 2434            applicable_language_settings: HashMap::default(),
 2435            accent_data: None,
 2436            fetched_tree_sitter_chunks: HashMap::default(),
 2437            number_deleted_lines: false,
 2438        };
 2439
 2440        if is_minimap {
 2441            return editor;
 2442        }
 2443
 2444        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2445        editor.accent_data = editor.fetch_accent_data(cx);
 2446
 2447        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2448            editor
 2449                ._subscriptions
 2450                .push(cx.observe(breakpoints, |_, _, cx| {
 2451                    cx.notify();
 2452                }));
 2453        }
 2454        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2455        editor._subscriptions.extend(project_subscriptions);
 2456
 2457        editor._subscriptions.push(cx.subscribe_in(
 2458            &cx.entity(),
 2459            window,
 2460            |editor, _, e: &EditorEvent, window, cx| match e {
 2461                EditorEvent::ScrollPositionChanged { local, .. } => {
 2462                    if *local {
 2463                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2464                        editor.inline_blame_popover.take();
 2465                        let new_anchor = editor.scroll_manager.anchor();
 2466                        let snapshot = editor.snapshot(window, cx);
 2467                        editor.update_restoration_data(cx, move |data| {
 2468                            data.scroll_position = (
 2469                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2470                                new_anchor.offset,
 2471                            );
 2472                        });
 2473
 2474                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2475                            cx.background_executor()
 2476                                .timer(Duration::from_millis(50))
 2477                                .await;
 2478                            editor
 2479                                .update_in(cx, |editor, window, cx| {
 2480                                    editor.register_visible_buffers(cx);
 2481                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2482                                    editor.refresh_inlay_hints(
 2483                                        InlayHintRefreshReason::NewLinesShown,
 2484                                        cx,
 2485                                    );
 2486                                    editor.colorize_brackets(false, cx);
 2487                                })
 2488                                .ok();
 2489                        });
 2490                    }
 2491                }
 2492                EditorEvent::Edited { .. } => {
 2493                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2494                        .map(|vim_mode| vim_mode.0)
 2495                        .unwrap_or(false);
 2496                    if !vim_mode {
 2497                        let display_map = editor.display_snapshot(cx);
 2498                        let selections = editor.selections.all_adjusted_display(&display_map);
 2499                        let pop_state = editor
 2500                            .change_list
 2501                            .last()
 2502                            .map(|previous| {
 2503                                previous.len() == selections.len()
 2504                                    && previous.iter().enumerate().all(|(ix, p)| {
 2505                                        p.to_display_point(&display_map).row()
 2506                                            == selections[ix].head().row()
 2507                                    })
 2508                            })
 2509                            .unwrap_or(false);
 2510                        let new_positions = selections
 2511                            .into_iter()
 2512                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2513                            .collect();
 2514                        editor
 2515                            .change_list
 2516                            .push_to_change_list(pop_state, new_positions);
 2517                    }
 2518                }
 2519                _ => (),
 2520            },
 2521        ));
 2522
 2523        if let Some(dap_store) = editor
 2524            .project
 2525            .as_ref()
 2526            .map(|project| project.read(cx).dap_store())
 2527        {
 2528            let weak_editor = cx.weak_entity();
 2529
 2530            editor
 2531                ._subscriptions
 2532                .push(
 2533                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2534                        let session_entity = cx.entity();
 2535                        weak_editor
 2536                            .update(cx, |editor, cx| {
 2537                                editor._subscriptions.push(
 2538                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2539                                );
 2540                            })
 2541                            .ok();
 2542                    }),
 2543                );
 2544
 2545            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2546                editor
 2547                    ._subscriptions
 2548                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2549            }
 2550        }
 2551
 2552        // skip adding the initial selection to selection history
 2553        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2554        editor.end_selection(window, cx);
 2555        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2556
 2557        editor.scroll_manager.show_scrollbars(window, cx);
 2558        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2559
 2560        if full_mode {
 2561            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2562            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2563
 2564            if editor.git_blame_inline_enabled {
 2565                editor.start_git_blame_inline(false, window, cx);
 2566            }
 2567
 2568            editor.go_to_active_debug_line(window, cx);
 2569
 2570            editor.minimap =
 2571                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2572            editor.colors = Some(LspColorData::new(cx));
 2573            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2574
 2575            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2576                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2577            }
 2578            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2579        }
 2580
 2581        editor
 2582    }
 2583
 2584    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2585        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2586    }
 2587
 2588    pub fn deploy_mouse_context_menu(
 2589        &mut self,
 2590        position: gpui::Point<Pixels>,
 2591        context_menu: Entity<ContextMenu>,
 2592        window: &mut Window,
 2593        cx: &mut Context<Self>,
 2594    ) {
 2595        self.mouse_context_menu = Some(MouseContextMenu::new(
 2596            self,
 2597            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2598            context_menu,
 2599            window,
 2600            cx,
 2601        ));
 2602    }
 2603
 2604    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2605        self.mouse_context_menu
 2606            .as_ref()
 2607            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2608    }
 2609
 2610    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2611        if self
 2612            .selections
 2613            .pending_anchor()
 2614            .is_some_and(|pending_selection| {
 2615                let snapshot = self.buffer().read(cx).snapshot(cx);
 2616                pending_selection.range().includes(range, &snapshot)
 2617            })
 2618        {
 2619            return true;
 2620        }
 2621
 2622        self.selections
 2623            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2624            .into_iter()
 2625            .any(|selection| {
 2626                // This is needed to cover a corner case, if we just check for an existing
 2627                // selection in the fold range, having a cursor at the start of the fold
 2628                // marks it as selected. Non-empty selections don't cause this.
 2629                let length = selection.end - selection.start;
 2630                length > 0
 2631            })
 2632    }
 2633
 2634    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2635        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2636    }
 2637
 2638    fn key_context_internal(
 2639        &self,
 2640        has_active_edit_prediction: bool,
 2641        window: &mut Window,
 2642        cx: &mut App,
 2643    ) -> KeyContext {
 2644        let mut key_context = KeyContext::new_with_defaults();
 2645        key_context.add("Editor");
 2646        let mode = match self.mode {
 2647            EditorMode::SingleLine => "single_line",
 2648            EditorMode::AutoHeight { .. } => "auto_height",
 2649            EditorMode::Minimap { .. } => "minimap",
 2650            EditorMode::Full { .. } => "full",
 2651        };
 2652
 2653        if EditorSettings::jupyter_enabled(cx) {
 2654            key_context.add("jupyter");
 2655        }
 2656
 2657        key_context.set("mode", mode);
 2658        if self.pending_rename.is_some() {
 2659            key_context.add("renaming");
 2660        }
 2661
 2662        if let Some(snippet_stack) = self.snippet_stack.last() {
 2663            key_context.add("in_snippet");
 2664
 2665            if snippet_stack.active_index > 0 {
 2666                key_context.add("has_previous_tabstop");
 2667            }
 2668
 2669            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2670                key_context.add("has_next_tabstop");
 2671            }
 2672        }
 2673
 2674        match self.context_menu.borrow().as_ref() {
 2675            Some(CodeContextMenu::Completions(menu)) => {
 2676                if menu.visible() {
 2677                    key_context.add("menu");
 2678                    key_context.add("showing_completions");
 2679                }
 2680            }
 2681            Some(CodeContextMenu::CodeActions(menu)) => {
 2682                if menu.visible() {
 2683                    key_context.add("menu");
 2684                    key_context.add("showing_code_actions")
 2685                }
 2686            }
 2687            None => {}
 2688        }
 2689
 2690        if self.signature_help_state.has_multiple_signatures() {
 2691            key_context.add("showing_signature_help");
 2692        }
 2693
 2694        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2695        if !self.focus_handle(cx).contains_focused(window, cx)
 2696            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2697        {
 2698            for addon in self.addons.values() {
 2699                addon.extend_key_context(&mut key_context, cx)
 2700            }
 2701        }
 2702
 2703        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2704            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2705                Some(
 2706                    file.full_path(cx)
 2707                        .extension()?
 2708                        .to_string_lossy()
 2709                        .to_lowercase(),
 2710                )
 2711            }) {
 2712                key_context.set("extension", extension);
 2713            }
 2714        } else {
 2715            key_context.add("multibuffer");
 2716        }
 2717
 2718        if has_active_edit_prediction {
 2719            if self.edit_prediction_in_conflict() {
 2720                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2721            } else {
 2722                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2723                key_context.add("copilot_suggestion");
 2724            }
 2725        }
 2726
 2727        if self.selection_mark_mode {
 2728            key_context.add("selection_mode");
 2729        }
 2730
 2731        let disjoint = self.selections.disjoint_anchors();
 2732        let snapshot = self.snapshot(window, cx);
 2733        let snapshot = snapshot.buffer_snapshot();
 2734        if self.mode == EditorMode::SingleLine
 2735            && let [selection] = disjoint
 2736            && selection.start == selection.end
 2737            && selection.end.to_offset(snapshot) == snapshot.len()
 2738        {
 2739            key_context.add("end_of_input");
 2740        }
 2741
 2742        if self.has_any_expanded_diff_hunks(cx) {
 2743            key_context.add("diffs_expanded");
 2744        }
 2745
 2746        key_context
 2747    }
 2748
 2749    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2750        self.last_bounds.as_ref()
 2751    }
 2752
 2753    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2754        if self.mouse_cursor_hidden {
 2755            self.mouse_cursor_hidden = false;
 2756            cx.notify();
 2757        }
 2758    }
 2759
 2760    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2761        let hide_mouse_cursor = match origin {
 2762            HideMouseCursorOrigin::TypingAction => {
 2763                matches!(
 2764                    self.hide_mouse_mode,
 2765                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2766                )
 2767            }
 2768            HideMouseCursorOrigin::MovementAction => {
 2769                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2770            }
 2771        };
 2772        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2773            self.mouse_cursor_hidden = hide_mouse_cursor;
 2774            cx.notify();
 2775        }
 2776    }
 2777
 2778    pub fn edit_prediction_in_conflict(&self) -> bool {
 2779        if !self.show_edit_predictions_in_menu() {
 2780            return false;
 2781        }
 2782
 2783        let showing_completions = self
 2784            .context_menu
 2785            .borrow()
 2786            .as_ref()
 2787            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2788
 2789        showing_completions
 2790            || self.edit_prediction_requires_modifier()
 2791            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2792            // bindings to insert tab characters.
 2793            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2794    }
 2795
 2796    pub fn accept_edit_prediction_keybind(
 2797        &self,
 2798        granularity: EditPredictionGranularity,
 2799        window: &mut Window,
 2800        cx: &mut App,
 2801    ) -> AcceptEditPredictionBinding {
 2802        let key_context = self.key_context_internal(true, window, cx);
 2803        let in_conflict = self.edit_prediction_in_conflict();
 2804
 2805        let bindings =
 2806            match granularity {
 2807                EditPredictionGranularity::Word => window
 2808                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2809                EditPredictionGranularity::Line => window
 2810                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2811                EditPredictionGranularity::Full => {
 2812                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2813                }
 2814            };
 2815
 2816        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2817            !in_conflict
 2818                || binding
 2819                    .keystrokes()
 2820                    .first()
 2821                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2822        }))
 2823    }
 2824
 2825    pub fn new_file(
 2826        workspace: &mut Workspace,
 2827        _: &workspace::NewFile,
 2828        window: &mut Window,
 2829        cx: &mut Context<Workspace>,
 2830    ) {
 2831        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2832            "Failed to create buffer",
 2833            window,
 2834            cx,
 2835            |e, _, _| match e.error_code() {
 2836                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2837                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2838                e.error_tag("required").unwrap_or("the latest version")
 2839            )),
 2840                _ => None,
 2841            },
 2842        );
 2843    }
 2844
 2845    pub fn new_in_workspace(
 2846        workspace: &mut Workspace,
 2847        window: &mut Window,
 2848        cx: &mut Context<Workspace>,
 2849    ) -> Task<Result<Entity<Editor>>> {
 2850        let project = workspace.project().clone();
 2851        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2852
 2853        cx.spawn_in(window, async move |workspace, cx| {
 2854            let buffer = create.await?;
 2855            workspace.update_in(cx, |workspace, window, cx| {
 2856                let editor =
 2857                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2858                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2859                editor
 2860            })
 2861        })
 2862    }
 2863
 2864    fn new_file_vertical(
 2865        workspace: &mut Workspace,
 2866        _: &workspace::NewFileSplitVertical,
 2867        window: &mut Window,
 2868        cx: &mut Context<Workspace>,
 2869    ) {
 2870        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2871    }
 2872
 2873    fn new_file_horizontal(
 2874        workspace: &mut Workspace,
 2875        _: &workspace::NewFileSplitHorizontal,
 2876        window: &mut Window,
 2877        cx: &mut Context<Workspace>,
 2878    ) {
 2879        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2880    }
 2881
 2882    fn new_file_split(
 2883        workspace: &mut Workspace,
 2884        action: &workspace::NewFileSplit,
 2885        window: &mut Window,
 2886        cx: &mut Context<Workspace>,
 2887    ) {
 2888        Self::new_file_in_direction(workspace, action.0, window, cx)
 2889    }
 2890
 2891    fn new_file_in_direction(
 2892        workspace: &mut Workspace,
 2893        direction: SplitDirection,
 2894        window: &mut Window,
 2895        cx: &mut Context<Workspace>,
 2896    ) {
 2897        let project = workspace.project().clone();
 2898        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2899
 2900        cx.spawn_in(window, async move |workspace, cx| {
 2901            let buffer = create.await?;
 2902            workspace.update_in(cx, move |workspace, window, cx| {
 2903                workspace.split_item(
 2904                    direction,
 2905                    Box::new(
 2906                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2907                    ),
 2908                    window,
 2909                    cx,
 2910                )
 2911            })?;
 2912            anyhow::Ok(())
 2913        })
 2914        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2915            match e.error_code() {
 2916                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2917                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2918                e.error_tag("required").unwrap_or("the latest version")
 2919            )),
 2920                _ => None,
 2921            }
 2922        });
 2923    }
 2924
 2925    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2926        self.leader_id
 2927    }
 2928
 2929    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2930        &self.buffer
 2931    }
 2932
 2933    pub fn project(&self) -> Option<&Entity<Project>> {
 2934        self.project.as_ref()
 2935    }
 2936
 2937    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2938        self.workspace.as_ref()?.0.upgrade()
 2939    }
 2940
 2941    /// Returns the workspace serialization ID if this editor should be serialized.
 2942    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2943        self.workspace
 2944            .as_ref()
 2945            .filter(|_| self.should_serialize_buffer())
 2946            .and_then(|workspace| workspace.1)
 2947    }
 2948
 2949    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2950        self.buffer().read(cx).title(cx)
 2951    }
 2952
 2953    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2954        let git_blame_gutter_max_author_length = self
 2955            .render_git_blame_gutter(cx)
 2956            .then(|| {
 2957                if let Some(blame) = self.blame.as_ref() {
 2958                    let max_author_length =
 2959                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2960                    Some(max_author_length)
 2961                } else {
 2962                    None
 2963                }
 2964            })
 2965            .flatten();
 2966
 2967        EditorSnapshot {
 2968            mode: self.mode.clone(),
 2969            show_gutter: self.show_gutter,
 2970            offset_content: self.offset_content,
 2971            show_line_numbers: self.show_line_numbers,
 2972            number_deleted_lines: self.number_deleted_lines,
 2973            show_git_diff_gutter: self.show_git_diff_gutter,
 2974            show_code_actions: self.show_code_actions,
 2975            show_runnables: self.show_runnables,
 2976            show_breakpoints: self.show_breakpoints,
 2977            git_blame_gutter_max_author_length,
 2978            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2979            placeholder_display_snapshot: self
 2980                .placeholder_display_map
 2981                .as_ref()
 2982                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2983            scroll_anchor: self.scroll_manager.anchor(),
 2984            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2985            is_focused: self.focus_handle.is_focused(window),
 2986            current_line_highlight: self
 2987                .current_line_highlight
 2988                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2989            gutter_hovered: self.gutter_hovered,
 2990        }
 2991    }
 2992
 2993    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2994        self.buffer.read(cx).language_at(point, cx)
 2995    }
 2996
 2997    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2998        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2999    }
 3000
 3001    pub fn active_excerpt(
 3002        &self,
 3003        cx: &App,
 3004    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3005        self.buffer
 3006            .read(cx)
 3007            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3008    }
 3009
 3010    pub fn mode(&self) -> &EditorMode {
 3011        &self.mode
 3012    }
 3013
 3014    pub fn set_mode(&mut self, mode: EditorMode) {
 3015        self.mode = mode;
 3016    }
 3017
 3018    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3019        self.collaboration_hub.as_deref()
 3020    }
 3021
 3022    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3023        self.collaboration_hub = Some(hub);
 3024    }
 3025
 3026    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3027        self.in_project_search = in_project_search;
 3028    }
 3029
 3030    pub fn set_custom_context_menu(
 3031        &mut self,
 3032        f: impl 'static
 3033        + Fn(
 3034            &mut Self,
 3035            DisplayPoint,
 3036            &mut Window,
 3037            &mut Context<Self>,
 3038        ) -> Option<Entity<ui::ContextMenu>>,
 3039    ) {
 3040        self.custom_context_menu = Some(Box::new(f))
 3041    }
 3042
 3043    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3044        self.completion_provider = provider;
 3045    }
 3046
 3047    #[cfg(any(test, feature = "test-support"))]
 3048    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3049        self.completion_provider.clone()
 3050    }
 3051
 3052    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3053        self.semantics_provider.clone()
 3054    }
 3055
 3056    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3057        self.semantics_provider = provider;
 3058    }
 3059
 3060    pub fn set_edit_prediction_provider<T>(
 3061        &mut self,
 3062        provider: Option<Entity<T>>,
 3063        window: &mut Window,
 3064        cx: &mut Context<Self>,
 3065    ) where
 3066        T: EditPredictionDelegate,
 3067    {
 3068        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3069            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3070                if this.focus_handle.is_focused(window) {
 3071                    this.update_visible_edit_prediction(window, cx);
 3072                }
 3073            }),
 3074            provider: Arc::new(provider),
 3075        });
 3076        self.update_edit_prediction_settings(cx);
 3077        self.refresh_edit_prediction(false, false, window, cx);
 3078    }
 3079
 3080    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3081        self.placeholder_display_map
 3082            .as_ref()
 3083            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3084    }
 3085
 3086    pub fn set_placeholder_text(
 3087        &mut self,
 3088        placeholder_text: &str,
 3089        window: &mut Window,
 3090        cx: &mut Context<Self>,
 3091    ) {
 3092        let multibuffer = cx
 3093            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3094
 3095        let style = window.text_style();
 3096
 3097        self.placeholder_display_map = Some(cx.new(|cx| {
 3098            DisplayMap::new(
 3099                multibuffer,
 3100                style.font(),
 3101                style.font_size.to_pixels(window.rem_size()),
 3102                None,
 3103                FILE_HEADER_HEIGHT,
 3104                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3105                Default::default(),
 3106                DiagnosticSeverity::Off,
 3107                cx,
 3108            )
 3109        }));
 3110        cx.notify();
 3111    }
 3112
 3113    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3114        self.cursor_shape = cursor_shape;
 3115
 3116        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3117        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3118
 3119        cx.notify();
 3120    }
 3121
 3122    pub fn cursor_shape(&self) -> CursorShape {
 3123        self.cursor_shape
 3124    }
 3125
 3126    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3127        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3128    }
 3129
 3130    pub fn set_current_line_highlight(
 3131        &mut self,
 3132        current_line_highlight: Option<CurrentLineHighlight>,
 3133    ) {
 3134        self.current_line_highlight = current_line_highlight;
 3135    }
 3136
 3137    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3138        self.collapse_matches = collapse_matches;
 3139    }
 3140
 3141    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3142        if self.collapse_matches {
 3143            return range.start..range.start;
 3144        }
 3145        range.clone()
 3146    }
 3147
 3148    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3149        self.display_map.read(cx).clip_at_line_ends
 3150    }
 3151
 3152    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3153        if self.display_map.read(cx).clip_at_line_ends != clip {
 3154            self.display_map
 3155                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3156        }
 3157    }
 3158
 3159    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3160        self.input_enabled = input_enabled;
 3161    }
 3162
 3163    pub fn set_edit_predictions_hidden_for_vim_mode(
 3164        &mut self,
 3165        hidden: bool,
 3166        window: &mut Window,
 3167        cx: &mut Context<Self>,
 3168    ) {
 3169        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3170            self.edit_predictions_hidden_for_vim_mode = hidden;
 3171            if hidden {
 3172                self.update_visible_edit_prediction(window, cx);
 3173            } else {
 3174                self.refresh_edit_prediction(true, false, window, cx);
 3175            }
 3176        }
 3177    }
 3178
 3179    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3180        self.menu_edit_predictions_policy = value;
 3181    }
 3182
 3183    pub fn set_autoindent(&mut self, autoindent: bool) {
 3184        if autoindent {
 3185            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3186        } else {
 3187            self.autoindent_mode = None;
 3188        }
 3189    }
 3190
 3191    pub fn capability(&self, cx: &App) -> Capability {
 3192        if self.read_only {
 3193            Capability::ReadOnly
 3194        } else {
 3195            self.buffer.read(cx).capability()
 3196        }
 3197    }
 3198
 3199    pub fn read_only(&self, cx: &App) -> bool {
 3200        self.read_only || self.buffer.read(cx).read_only()
 3201    }
 3202
 3203    pub fn set_read_only(&mut self, read_only: bool) {
 3204        self.read_only = read_only;
 3205    }
 3206
 3207    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3208        self.use_autoclose = autoclose;
 3209    }
 3210
 3211    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3212        self.use_auto_surround = auto_surround;
 3213    }
 3214
 3215    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3216        self.auto_replace_emoji_shortcode = auto_replace;
 3217    }
 3218
 3219    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3220        self.buffer_serialization = should_serialize.then(|| {
 3221            BufferSerialization::new(
 3222                ProjectSettings::get_global(cx)
 3223                    .session
 3224                    .restore_unsaved_buffers,
 3225            )
 3226        })
 3227    }
 3228
 3229    fn should_serialize_buffer(&self) -> bool {
 3230        self.buffer_serialization.is_some()
 3231    }
 3232
 3233    pub fn toggle_edit_predictions(
 3234        &mut self,
 3235        _: &ToggleEditPrediction,
 3236        window: &mut Window,
 3237        cx: &mut Context<Self>,
 3238    ) {
 3239        if self.show_edit_predictions_override.is_some() {
 3240            self.set_show_edit_predictions(None, window, cx);
 3241        } else {
 3242            let show_edit_predictions = !self.edit_predictions_enabled();
 3243            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3244        }
 3245    }
 3246
 3247    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3248        self.show_completions_on_input_override = show_completions_on_input;
 3249    }
 3250
 3251    pub fn set_show_edit_predictions(
 3252        &mut self,
 3253        show_edit_predictions: Option<bool>,
 3254        window: &mut Window,
 3255        cx: &mut Context<Self>,
 3256    ) {
 3257        self.show_edit_predictions_override = show_edit_predictions;
 3258        self.update_edit_prediction_settings(cx);
 3259
 3260        if let Some(false) = show_edit_predictions {
 3261            self.discard_edit_prediction(false, cx);
 3262        } else {
 3263            self.refresh_edit_prediction(false, true, window, cx);
 3264        }
 3265    }
 3266
 3267    fn edit_predictions_disabled_in_scope(
 3268        &self,
 3269        buffer: &Entity<Buffer>,
 3270        buffer_position: language::Anchor,
 3271        cx: &App,
 3272    ) -> bool {
 3273        let snapshot = buffer.read(cx).snapshot();
 3274        let settings = snapshot.settings_at(buffer_position, cx);
 3275
 3276        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3277            return false;
 3278        };
 3279
 3280        scope.override_name().is_some_and(|scope_name| {
 3281            settings
 3282                .edit_predictions_disabled_in
 3283                .iter()
 3284                .any(|s| s == scope_name)
 3285        })
 3286    }
 3287
 3288    pub fn set_use_modal_editing(&mut self, to: bool) {
 3289        self.use_modal_editing = to;
 3290    }
 3291
 3292    pub fn use_modal_editing(&self) -> bool {
 3293        self.use_modal_editing
 3294    }
 3295
 3296    fn selections_did_change(
 3297        &mut self,
 3298        local: bool,
 3299        old_cursor_position: &Anchor,
 3300        effects: SelectionEffects,
 3301        window: &mut Window,
 3302        cx: &mut Context<Self>,
 3303    ) {
 3304        window.invalidate_character_coordinates();
 3305
 3306        // Copy selections to primary selection buffer
 3307        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3308        if local {
 3309            let selections = self
 3310                .selections
 3311                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3312            let buffer_handle = self.buffer.read(cx).read(cx);
 3313
 3314            let mut text = String::new();
 3315            for (index, selection) in selections.iter().enumerate() {
 3316                let text_for_selection = buffer_handle
 3317                    .text_for_range(selection.start..selection.end)
 3318                    .collect::<String>();
 3319
 3320                text.push_str(&text_for_selection);
 3321                if index != selections.len() - 1 {
 3322                    text.push('\n');
 3323                }
 3324            }
 3325
 3326            if !text.is_empty() {
 3327                cx.write_to_primary(ClipboardItem::new_string(text));
 3328            }
 3329        }
 3330
 3331        let selection_anchors = self.selections.disjoint_anchors_arc();
 3332
 3333        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3334            self.buffer.update(cx, |buffer, cx| {
 3335                buffer.set_active_selections(
 3336                    &selection_anchors,
 3337                    self.selections.line_mode(),
 3338                    self.cursor_shape,
 3339                    cx,
 3340                )
 3341            });
 3342        }
 3343        let display_map = self
 3344            .display_map
 3345            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3346        let buffer = display_map.buffer_snapshot();
 3347        if self.selections.count() == 1 {
 3348            self.add_selections_state = None;
 3349        }
 3350        self.select_next_state = None;
 3351        self.select_prev_state = None;
 3352        self.select_syntax_node_history.try_clear();
 3353        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3354        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3355        self.take_rename(false, window, cx);
 3356
 3357        let newest_selection = self.selections.newest_anchor();
 3358        let new_cursor_position = newest_selection.head();
 3359        let selection_start = newest_selection.start;
 3360
 3361        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3362            self.push_to_nav_history(
 3363                *old_cursor_position,
 3364                Some(new_cursor_position.to_point(buffer)),
 3365                false,
 3366                effects.nav_history == Some(true),
 3367                cx,
 3368            );
 3369        }
 3370
 3371        if local {
 3372            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3373                self.register_buffer(buffer_id, cx);
 3374            }
 3375
 3376            let mut context_menu = self.context_menu.borrow_mut();
 3377            let completion_menu = match context_menu.as_ref() {
 3378                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3379                Some(CodeContextMenu::CodeActions(_)) => {
 3380                    *context_menu = None;
 3381                    None
 3382                }
 3383                None => None,
 3384            };
 3385            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3386            drop(context_menu);
 3387
 3388            if effects.completions
 3389                && let Some(completion_position) = completion_position
 3390            {
 3391                let start_offset = selection_start.to_offset(buffer);
 3392                let position_matches = start_offset == completion_position.to_offset(buffer);
 3393                let continue_showing = if let Some((snap, ..)) =
 3394                    buffer.point_to_buffer_offset(completion_position)
 3395                    && !snap.capability.editable()
 3396                {
 3397                    false
 3398                } else if position_matches {
 3399                    if self.snippet_stack.is_empty() {
 3400                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3401                            == Some(CharKind::Word)
 3402                    } else {
 3403                        // Snippet choices can be shown even when the cursor is in whitespace.
 3404                        // Dismissing the menu with actions like backspace is handled by
 3405                        // invalidation regions.
 3406                        true
 3407                    }
 3408                } else {
 3409                    false
 3410                };
 3411
 3412                if continue_showing {
 3413                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3414                } else {
 3415                    self.hide_context_menu(window, cx);
 3416                }
 3417            }
 3418
 3419            hide_hover(self, cx);
 3420
 3421            if old_cursor_position.to_display_point(&display_map).row()
 3422                != new_cursor_position.to_display_point(&display_map).row()
 3423            {
 3424                self.available_code_actions.take();
 3425            }
 3426            self.refresh_code_actions(window, cx);
 3427            self.refresh_document_highlights(cx);
 3428            refresh_linked_ranges(self, window, cx);
 3429
 3430            self.refresh_selected_text_highlights(false, window, cx);
 3431            self.refresh_matching_bracket_highlights(window, cx);
 3432            self.update_visible_edit_prediction(window, cx);
 3433            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3434            self.inline_blame_popover.take();
 3435            if self.git_blame_inline_enabled {
 3436                self.start_inline_blame_timer(window, cx);
 3437            }
 3438        }
 3439
 3440        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3441        cx.emit(EditorEvent::SelectionsChanged { local });
 3442
 3443        let selections = &self.selections.disjoint_anchors_arc();
 3444        if selections.len() == 1 {
 3445            cx.emit(SearchEvent::ActiveMatchChanged)
 3446        }
 3447        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3448            let inmemory_selections = selections
 3449                .iter()
 3450                .map(|s| {
 3451                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3452                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3453                })
 3454                .collect();
 3455            self.update_restoration_data(cx, |data| {
 3456                data.selections = inmemory_selections;
 3457            });
 3458
 3459            if WorkspaceSettings::get(None, cx).restore_on_startup
 3460                != RestoreOnStartupBehavior::EmptyTab
 3461                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3462            {
 3463                let snapshot = self.buffer().read(cx).snapshot(cx);
 3464                let selections = selections.clone();
 3465                let background_executor = cx.background_executor().clone();
 3466                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3467                self.serialize_selections = cx.background_spawn(async move {
 3468                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3469                    let db_selections = selections
 3470                        .iter()
 3471                        .map(|selection| {
 3472                            (
 3473                                selection.start.to_offset(&snapshot).0,
 3474                                selection.end.to_offset(&snapshot).0,
 3475                            )
 3476                        })
 3477                        .collect();
 3478
 3479                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3480                        .await
 3481                        .with_context(|| {
 3482                            format!(
 3483                                "persisting editor selections for editor {editor_id}, \
 3484                                workspace {workspace_id:?}"
 3485                            )
 3486                        })
 3487                        .log_err();
 3488                });
 3489            }
 3490        }
 3491
 3492        cx.notify();
 3493    }
 3494
 3495    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3496        use text::ToOffset as _;
 3497        use text::ToPoint as _;
 3498
 3499        if self.mode.is_minimap()
 3500            || WorkspaceSettings::get(None, cx).restore_on_startup
 3501                == RestoreOnStartupBehavior::EmptyTab
 3502        {
 3503            return;
 3504        }
 3505
 3506        if !self.buffer().read(cx).is_singleton() {
 3507            return;
 3508        }
 3509
 3510        let display_snapshot = self
 3511            .display_map
 3512            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3513        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3514            return;
 3515        };
 3516        let inmemory_folds = display_snapshot
 3517            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3518            .map(|fold| {
 3519                fold.range.start.text_anchor.to_point(&snapshot)
 3520                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3521            })
 3522            .collect();
 3523        self.update_restoration_data(cx, |data| {
 3524            data.folds = inmemory_folds;
 3525        });
 3526
 3527        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3528            return;
 3529        };
 3530        let background_executor = cx.background_executor().clone();
 3531        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3532        const FINGERPRINT_LEN: usize = 32;
 3533        let db_folds = display_snapshot
 3534            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3535            .map(|fold| {
 3536                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3537                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3538
 3539                // Extract fingerprints - content at fold boundaries for validation on restore
 3540                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3541                // content that might change independently.
 3542                // start_fp: first min(32, fold_len) bytes of fold content
 3543                // end_fp: last min(32, fold_len) bytes of fold content
 3544                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3545                let fold_len = end - start;
 3546                let start_fp_end = snapshot
 3547                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3548                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3549                let end_fp_start = snapshot
 3550                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3551                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3552
 3553                (start, end, start_fp, end_fp)
 3554            })
 3555            .collect::<Vec<_>>();
 3556        self.serialize_folds = cx.background_spawn(async move {
 3557            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3558            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3559                .await
 3560                .with_context(|| {
 3561                    format!(
 3562                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3563                    )
 3564                })
 3565                .log_err();
 3566        });
 3567    }
 3568
 3569    pub fn sync_selections(
 3570        &mut self,
 3571        other: Entity<Editor>,
 3572        cx: &mut Context<Self>,
 3573    ) -> gpui::Subscription {
 3574        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3575        if !other_selections.is_empty() {
 3576            self.selections
 3577                .change_with(&self.display_snapshot(cx), |selections| {
 3578                    selections.select_anchors(other_selections);
 3579                });
 3580        }
 3581
 3582        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3583            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3584                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3585                if other_selections.is_empty() {
 3586                    return;
 3587                }
 3588                let snapshot = this.display_snapshot(cx);
 3589                this.selections.change_with(&snapshot, |selections| {
 3590                    selections.select_anchors(other_selections);
 3591                });
 3592            }
 3593        });
 3594
 3595        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3596            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3597                let these_selections = this.selections.disjoint_anchors().to_vec();
 3598                if these_selections.is_empty() {
 3599                    return;
 3600                }
 3601                other.update(cx, |other_editor, cx| {
 3602                    let snapshot = other_editor.display_snapshot(cx);
 3603                    other_editor
 3604                        .selections
 3605                        .change_with(&snapshot, |selections| {
 3606                            selections.select_anchors(these_selections);
 3607                        })
 3608                });
 3609            }
 3610        });
 3611
 3612        Subscription::join(other_subscription, this_subscription)
 3613    }
 3614
 3615    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3616        if self.buffer().read(cx).is_singleton() {
 3617            return;
 3618        }
 3619        let snapshot = self.buffer.read(cx).snapshot(cx);
 3620        let buffer_ids: HashSet<BufferId> = self
 3621            .selections
 3622            .disjoint_anchor_ranges()
 3623            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3624            .collect();
 3625        for buffer_id in buffer_ids {
 3626            self.unfold_buffer(buffer_id, cx);
 3627        }
 3628    }
 3629
 3630    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3631    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3632    /// effects of selection change occur at the end of the transaction.
 3633    pub fn change_selections<R>(
 3634        &mut self,
 3635        effects: SelectionEffects,
 3636        window: &mut Window,
 3637        cx: &mut Context<Self>,
 3638        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3639    ) -> R {
 3640        let snapshot = self.display_snapshot(cx);
 3641        if let Some(state) = &mut self.deferred_selection_effects_state {
 3642            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3643            state.effects.completions = effects.completions;
 3644            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3645            let (changed, result) = self.selections.change_with(&snapshot, change);
 3646            state.changed |= changed;
 3647            return result;
 3648        }
 3649        let mut state = DeferredSelectionEffectsState {
 3650            changed: false,
 3651            effects,
 3652            old_cursor_position: self.selections.newest_anchor().head(),
 3653            history_entry: SelectionHistoryEntry {
 3654                selections: self.selections.disjoint_anchors_arc(),
 3655                select_next_state: self.select_next_state.clone(),
 3656                select_prev_state: self.select_prev_state.clone(),
 3657                add_selections_state: self.add_selections_state.clone(),
 3658            },
 3659        };
 3660        let (changed, result) = self.selections.change_with(&snapshot, change);
 3661        state.changed = state.changed || changed;
 3662        if self.defer_selection_effects {
 3663            self.deferred_selection_effects_state = Some(state);
 3664        } else {
 3665            self.apply_selection_effects(state, window, cx);
 3666        }
 3667        result
 3668    }
 3669
 3670    /// Defers the effects of selection change, so that the effects of multiple calls to
 3671    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3672    /// to selection history and the state of popovers based on selection position aren't
 3673    /// erroneously updated.
 3674    pub fn with_selection_effects_deferred<R>(
 3675        &mut self,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3679    ) -> R {
 3680        let already_deferred = self.defer_selection_effects;
 3681        self.defer_selection_effects = true;
 3682        let result = update(self, window, cx);
 3683        if !already_deferred {
 3684            self.defer_selection_effects = false;
 3685            if let Some(state) = self.deferred_selection_effects_state.take() {
 3686                self.apply_selection_effects(state, window, cx);
 3687            }
 3688        }
 3689        result
 3690    }
 3691
 3692    fn apply_selection_effects(
 3693        &mut self,
 3694        state: DeferredSelectionEffectsState,
 3695        window: &mut Window,
 3696        cx: &mut Context<Self>,
 3697    ) {
 3698        if state.changed {
 3699            self.selection_history.push(state.history_entry);
 3700
 3701            if let Some(autoscroll) = state.effects.scroll {
 3702                self.request_autoscroll(autoscroll, cx);
 3703            }
 3704
 3705            let old_cursor_position = &state.old_cursor_position;
 3706
 3707            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3708
 3709            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3710                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3711            }
 3712        }
 3713    }
 3714
 3715    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3716    where
 3717        I: IntoIterator<Item = (Range<S>, T)>,
 3718        S: ToOffset,
 3719        T: Into<Arc<str>>,
 3720    {
 3721        if self.read_only(cx) {
 3722            return;
 3723        }
 3724
 3725        self.buffer
 3726            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3727    }
 3728
 3729    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3730    where
 3731        I: IntoIterator<Item = (Range<S>, T)>,
 3732        S: ToOffset,
 3733        T: Into<Arc<str>>,
 3734    {
 3735        if self.read_only(cx) {
 3736            return;
 3737        }
 3738
 3739        self.buffer.update(cx, |buffer, cx| {
 3740            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3741        });
 3742    }
 3743
 3744    pub fn edit_with_block_indent<I, S, T>(
 3745        &mut self,
 3746        edits: I,
 3747        original_indent_columns: Vec<Option<u32>>,
 3748        cx: &mut Context<Self>,
 3749    ) where
 3750        I: IntoIterator<Item = (Range<S>, T)>,
 3751        S: ToOffset,
 3752        T: Into<Arc<str>>,
 3753    {
 3754        if self.read_only(cx) {
 3755            return;
 3756        }
 3757
 3758        self.buffer.update(cx, |buffer, cx| {
 3759            buffer.edit(
 3760                edits,
 3761                Some(AutoindentMode::Block {
 3762                    original_indent_columns,
 3763                }),
 3764                cx,
 3765            )
 3766        });
 3767    }
 3768
 3769    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3770        self.hide_context_menu(window, cx);
 3771
 3772        match phase {
 3773            SelectPhase::Begin {
 3774                position,
 3775                add,
 3776                click_count,
 3777            } => self.begin_selection(position, add, click_count, window, cx),
 3778            SelectPhase::BeginColumnar {
 3779                position,
 3780                goal_column,
 3781                reset,
 3782                mode,
 3783            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3784            SelectPhase::Extend {
 3785                position,
 3786                click_count,
 3787            } => self.extend_selection(position, click_count, window, cx),
 3788            SelectPhase::Update {
 3789                position,
 3790                goal_column,
 3791                scroll_delta,
 3792            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3793            SelectPhase::End => self.end_selection(window, cx),
 3794        }
 3795    }
 3796
 3797    fn extend_selection(
 3798        &mut self,
 3799        position: DisplayPoint,
 3800        click_count: usize,
 3801        window: &mut Window,
 3802        cx: &mut Context<Self>,
 3803    ) {
 3804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3805        let tail = self
 3806            .selections
 3807            .newest::<MultiBufferOffset>(&display_map)
 3808            .tail();
 3809        let click_count = click_count.max(match self.selections.select_mode() {
 3810            SelectMode::Character => 1,
 3811            SelectMode::Word(_) => 2,
 3812            SelectMode::Line(_) => 3,
 3813            SelectMode::All => 4,
 3814        });
 3815        self.begin_selection(position, false, click_count, window, cx);
 3816
 3817        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3818
 3819        let current_selection = match self.selections.select_mode() {
 3820            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3821            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3822        };
 3823
 3824        let mut pending_selection = self
 3825            .selections
 3826            .pending_anchor()
 3827            .cloned()
 3828            .expect("extend_selection not called with pending selection");
 3829
 3830        if pending_selection
 3831            .start
 3832            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3833            == Ordering::Greater
 3834        {
 3835            pending_selection.start = current_selection.start;
 3836        }
 3837        if pending_selection
 3838            .end
 3839            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3840            == Ordering::Less
 3841        {
 3842            pending_selection.end = current_selection.end;
 3843            pending_selection.reversed = true;
 3844        }
 3845
 3846        let mut pending_mode = self.selections.pending_mode().unwrap();
 3847        match &mut pending_mode {
 3848            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3849            _ => {}
 3850        }
 3851
 3852        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3853            SelectionEffects::scroll(Autoscroll::fit())
 3854        } else {
 3855            SelectionEffects::no_scroll()
 3856        };
 3857
 3858        self.change_selections(effects, window, cx, |s| {
 3859            s.set_pending(pending_selection.clone(), pending_mode);
 3860            s.set_is_extending(true);
 3861        });
 3862    }
 3863
 3864    fn begin_selection(
 3865        &mut self,
 3866        position: DisplayPoint,
 3867        add: bool,
 3868        click_count: usize,
 3869        window: &mut Window,
 3870        cx: &mut Context<Self>,
 3871    ) {
 3872        if !self.focus_handle.is_focused(window) {
 3873            self.last_focused_descendant = None;
 3874            window.focus(&self.focus_handle, cx);
 3875        }
 3876
 3877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3878        let buffer = display_map.buffer_snapshot();
 3879        let position = display_map.clip_point(position, Bias::Left);
 3880
 3881        let start;
 3882        let end;
 3883        let mode;
 3884        let mut auto_scroll;
 3885        match click_count {
 3886            1 => {
 3887                start = buffer.anchor_before(position.to_point(&display_map));
 3888                end = start;
 3889                mode = SelectMode::Character;
 3890                auto_scroll = true;
 3891            }
 3892            2 => {
 3893                let position = display_map
 3894                    .clip_point(position, Bias::Left)
 3895                    .to_offset(&display_map, Bias::Left);
 3896                let (range, _) = buffer.surrounding_word(position, None);
 3897                start = buffer.anchor_before(range.start);
 3898                end = buffer.anchor_before(range.end);
 3899                mode = SelectMode::Word(start..end);
 3900                auto_scroll = true;
 3901            }
 3902            3 => {
 3903                let position = display_map
 3904                    .clip_point(position, Bias::Left)
 3905                    .to_point(&display_map);
 3906                let line_start = display_map.prev_line_boundary(position).0;
 3907                let next_line_start = buffer.clip_point(
 3908                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3909                    Bias::Left,
 3910                );
 3911                start = buffer.anchor_before(line_start);
 3912                end = buffer.anchor_before(next_line_start);
 3913                mode = SelectMode::Line(start..end);
 3914                auto_scroll = true;
 3915            }
 3916            _ => {
 3917                start = buffer.anchor_before(MultiBufferOffset(0));
 3918                end = buffer.anchor_before(buffer.len());
 3919                mode = SelectMode::All;
 3920                auto_scroll = false;
 3921            }
 3922        }
 3923        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3924
 3925        let point_to_delete: Option<usize> = {
 3926            let selected_points: Vec<Selection<Point>> =
 3927                self.selections.disjoint_in_range(start..end, &display_map);
 3928
 3929            if !add || click_count > 1 {
 3930                None
 3931            } else if !selected_points.is_empty() {
 3932                Some(selected_points[0].id)
 3933            } else {
 3934                let clicked_point_already_selected =
 3935                    self.selections.disjoint_anchors().iter().find(|selection| {
 3936                        selection.start.to_point(buffer) == start.to_point(buffer)
 3937                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3938                    });
 3939
 3940                clicked_point_already_selected.map(|selection| selection.id)
 3941            }
 3942        };
 3943
 3944        let selections_count = self.selections.count();
 3945        let effects = if auto_scroll {
 3946            SelectionEffects::default()
 3947        } else {
 3948            SelectionEffects::no_scroll()
 3949        };
 3950
 3951        self.change_selections(effects, window, cx, |s| {
 3952            if let Some(point_to_delete) = point_to_delete {
 3953                s.delete(point_to_delete);
 3954
 3955                if selections_count == 1 {
 3956                    s.set_pending_anchor_range(start..end, mode);
 3957                }
 3958            } else {
 3959                if !add {
 3960                    s.clear_disjoint();
 3961                }
 3962
 3963                s.set_pending_anchor_range(start..end, mode);
 3964            }
 3965        });
 3966    }
 3967
 3968    fn begin_columnar_selection(
 3969        &mut self,
 3970        position: DisplayPoint,
 3971        goal_column: u32,
 3972        reset: bool,
 3973        mode: ColumnarMode,
 3974        window: &mut Window,
 3975        cx: &mut Context<Self>,
 3976    ) {
 3977        if !self.focus_handle.is_focused(window) {
 3978            self.last_focused_descendant = None;
 3979            window.focus(&self.focus_handle, cx);
 3980        }
 3981
 3982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3983
 3984        if reset {
 3985            let pointer_position = display_map
 3986                .buffer_snapshot()
 3987                .anchor_before(position.to_point(&display_map));
 3988
 3989            self.change_selections(
 3990                SelectionEffects::scroll(Autoscroll::newest()),
 3991                window,
 3992                cx,
 3993                |s| {
 3994                    s.clear_disjoint();
 3995                    s.set_pending_anchor_range(
 3996                        pointer_position..pointer_position,
 3997                        SelectMode::Character,
 3998                    );
 3999                },
 4000            );
 4001        };
 4002
 4003        let tail = self.selections.newest::<Point>(&display_map).tail();
 4004        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4005        self.columnar_selection_state = match mode {
 4006            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4007                selection_tail: selection_anchor,
 4008                display_point: if reset {
 4009                    if position.column() != goal_column {
 4010                        Some(DisplayPoint::new(position.row(), goal_column))
 4011                    } else {
 4012                        None
 4013                    }
 4014                } else {
 4015                    None
 4016                },
 4017            }),
 4018            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4019                selection_tail: selection_anchor,
 4020            }),
 4021        };
 4022
 4023        if !reset {
 4024            self.select_columns(position, goal_column, &display_map, window, cx);
 4025        }
 4026    }
 4027
 4028    fn update_selection(
 4029        &mut self,
 4030        position: DisplayPoint,
 4031        goal_column: u32,
 4032        scroll_delta: gpui::Point<f32>,
 4033        window: &mut Window,
 4034        cx: &mut Context<Self>,
 4035    ) {
 4036        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4037
 4038        if self.columnar_selection_state.is_some() {
 4039            self.select_columns(position, goal_column, &display_map, window, cx);
 4040        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4041            let buffer = display_map.buffer_snapshot();
 4042            let head;
 4043            let tail;
 4044            let mode = self.selections.pending_mode().unwrap();
 4045            match &mode {
 4046                SelectMode::Character => {
 4047                    head = position.to_point(&display_map);
 4048                    tail = pending.tail().to_point(buffer);
 4049                }
 4050                SelectMode::Word(original_range) => {
 4051                    let offset = display_map
 4052                        .clip_point(position, Bias::Left)
 4053                        .to_offset(&display_map, Bias::Left);
 4054                    let original_range = original_range.to_offset(buffer);
 4055
 4056                    let head_offset = if buffer.is_inside_word(offset, None)
 4057                        || original_range.contains(&offset)
 4058                    {
 4059                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4060                        if word_range.start < original_range.start {
 4061                            word_range.start
 4062                        } else {
 4063                            word_range.end
 4064                        }
 4065                    } else {
 4066                        offset
 4067                    };
 4068
 4069                    head = head_offset.to_point(buffer);
 4070                    if head_offset <= original_range.start {
 4071                        tail = original_range.end.to_point(buffer);
 4072                    } else {
 4073                        tail = original_range.start.to_point(buffer);
 4074                    }
 4075                }
 4076                SelectMode::Line(original_range) => {
 4077                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4078
 4079                    let position = display_map
 4080                        .clip_point(position, Bias::Left)
 4081                        .to_point(&display_map);
 4082                    let line_start = display_map.prev_line_boundary(position).0;
 4083                    let next_line_start = buffer.clip_point(
 4084                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4085                        Bias::Left,
 4086                    );
 4087
 4088                    if line_start < original_range.start {
 4089                        head = line_start
 4090                    } else {
 4091                        head = next_line_start
 4092                    }
 4093
 4094                    if head <= original_range.start {
 4095                        tail = original_range.end;
 4096                    } else {
 4097                        tail = original_range.start;
 4098                    }
 4099                }
 4100                SelectMode::All => {
 4101                    return;
 4102                }
 4103            };
 4104
 4105            if head < tail {
 4106                pending.start = buffer.anchor_before(head);
 4107                pending.end = buffer.anchor_before(tail);
 4108                pending.reversed = true;
 4109            } else {
 4110                pending.start = buffer.anchor_before(tail);
 4111                pending.end = buffer.anchor_before(head);
 4112                pending.reversed = false;
 4113            }
 4114
 4115            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4116                s.set_pending(pending.clone(), mode);
 4117            });
 4118        } else {
 4119            log::error!("update_selection dispatched with no pending selection");
 4120            return;
 4121        }
 4122
 4123        self.apply_scroll_delta(scroll_delta, window, cx);
 4124        cx.notify();
 4125    }
 4126
 4127    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4128        self.columnar_selection_state.take();
 4129        if let Some(pending_mode) = self.selections.pending_mode() {
 4130            let selections = self
 4131                .selections
 4132                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4133            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4134                s.select(selections);
 4135                s.clear_pending();
 4136                if s.is_extending() {
 4137                    s.set_is_extending(false);
 4138                } else {
 4139                    s.set_select_mode(pending_mode);
 4140                }
 4141            });
 4142        }
 4143    }
 4144
 4145    fn select_columns(
 4146        &mut self,
 4147        head: DisplayPoint,
 4148        goal_column: u32,
 4149        display_map: &DisplaySnapshot,
 4150        window: &mut Window,
 4151        cx: &mut Context<Self>,
 4152    ) {
 4153        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4154            return;
 4155        };
 4156
 4157        let tail = match columnar_state {
 4158            ColumnarSelectionState::FromMouse {
 4159                selection_tail,
 4160                display_point,
 4161            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4162            ColumnarSelectionState::FromSelection { selection_tail } => {
 4163                selection_tail.to_display_point(display_map)
 4164            }
 4165        };
 4166
 4167        let start_row = cmp::min(tail.row(), head.row());
 4168        let end_row = cmp::max(tail.row(), head.row());
 4169        let start_column = cmp::min(tail.column(), goal_column);
 4170        let end_column = cmp::max(tail.column(), goal_column);
 4171        let reversed = start_column < tail.column();
 4172
 4173        let selection_ranges = (start_row.0..=end_row.0)
 4174            .map(DisplayRow)
 4175            .filter_map(|row| {
 4176                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4177                    || start_column <= display_map.line_len(row))
 4178                    && !display_map.is_block_line(row)
 4179                {
 4180                    let start = display_map
 4181                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4182                        .to_point(display_map);
 4183                    let end = display_map
 4184                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4185                        .to_point(display_map);
 4186                    if reversed {
 4187                        Some(end..start)
 4188                    } else {
 4189                        Some(start..end)
 4190                    }
 4191                } else {
 4192                    None
 4193                }
 4194            })
 4195            .collect::<Vec<_>>();
 4196        if selection_ranges.is_empty() {
 4197            return;
 4198        }
 4199
 4200        let ranges = match columnar_state {
 4201            ColumnarSelectionState::FromMouse { .. } => {
 4202                let mut non_empty_ranges = selection_ranges
 4203                    .iter()
 4204                    .filter(|selection_range| selection_range.start != selection_range.end)
 4205                    .peekable();
 4206                if non_empty_ranges.peek().is_some() {
 4207                    non_empty_ranges.cloned().collect()
 4208                } else {
 4209                    selection_ranges
 4210                }
 4211            }
 4212            _ => selection_ranges,
 4213        };
 4214
 4215        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4216            s.select_ranges(ranges);
 4217        });
 4218        cx.notify();
 4219    }
 4220
 4221    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4222        self.selections
 4223            .all_adjusted(snapshot)
 4224            .iter()
 4225            .any(|selection| !selection.is_empty())
 4226    }
 4227
 4228    pub fn has_pending_nonempty_selection(&self) -> bool {
 4229        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4230            Some(Selection { start, end, .. }) => start != end,
 4231            None => false,
 4232        };
 4233
 4234        pending_nonempty_selection
 4235            || (self.columnar_selection_state.is_some()
 4236                && self.selections.disjoint_anchors().len() > 1)
 4237    }
 4238
 4239    pub fn has_pending_selection(&self) -> bool {
 4240        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4241    }
 4242
 4243    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4244        self.selection_mark_mode = false;
 4245        self.selection_drag_state = SelectionDragState::None;
 4246
 4247        if self.dismiss_menus_and_popups(true, window, cx) {
 4248            cx.notify();
 4249            return;
 4250        }
 4251        if self.clear_expanded_diff_hunks(cx) {
 4252            cx.notify();
 4253            return;
 4254        }
 4255        if self.show_git_blame_gutter {
 4256            self.show_git_blame_gutter = false;
 4257            cx.notify();
 4258            return;
 4259        }
 4260
 4261        if self.mode.is_full()
 4262            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4263        {
 4264            cx.notify();
 4265            return;
 4266        }
 4267
 4268        cx.propagate();
 4269    }
 4270
 4271    pub fn dismiss_menus_and_popups(
 4272        &mut self,
 4273        is_user_requested: bool,
 4274        window: &mut Window,
 4275        cx: &mut Context<Self>,
 4276    ) -> bool {
 4277        let mut dismissed = false;
 4278
 4279        dismissed |= self.take_rename(false, window, cx).is_some();
 4280        dismissed |= self.hide_blame_popover(true, cx);
 4281        dismissed |= hide_hover(self, cx);
 4282        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4283        dismissed |= self.hide_context_menu(window, cx).is_some();
 4284        dismissed |= self.mouse_context_menu.take().is_some();
 4285        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4286        dismissed |= self.snippet_stack.pop().is_some();
 4287
 4288        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4289            self.dismiss_diagnostics(cx);
 4290            dismissed = true;
 4291        }
 4292
 4293        dismissed
 4294    }
 4295
 4296    fn linked_editing_ranges_for(
 4297        &self,
 4298        selection: Range<text::Anchor>,
 4299        cx: &App,
 4300    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4301        if self.linked_edit_ranges.is_empty() {
 4302            return None;
 4303        }
 4304        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4305            selection.end.buffer_id.and_then(|end_buffer_id| {
 4306                if selection.start.buffer_id != Some(end_buffer_id) {
 4307                    return None;
 4308                }
 4309                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4310                let snapshot = buffer.read(cx).snapshot();
 4311                self.linked_edit_ranges
 4312                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4313                    .map(|ranges| (ranges, snapshot, buffer))
 4314            })?;
 4315        use text::ToOffset as TO;
 4316        // find offset from the start of current range to current cursor position
 4317        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4318
 4319        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4320        let start_difference = start_offset - start_byte_offset;
 4321        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4322        let end_difference = end_offset - start_byte_offset;
 4323        // Current range has associated linked ranges.
 4324        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4325        for range in linked_ranges.iter() {
 4326            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4327            let end_offset = start_offset + end_difference;
 4328            let start_offset = start_offset + start_difference;
 4329            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4330                continue;
 4331            }
 4332            if self.selections.disjoint_anchor_ranges().any(|s| {
 4333                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4334                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4335                {
 4336                    return false;
 4337                }
 4338                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4339                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4340            }) {
 4341                continue;
 4342            }
 4343            let start = buffer_snapshot.anchor_after(start_offset);
 4344            let end = buffer_snapshot.anchor_after(end_offset);
 4345            linked_edits
 4346                .entry(buffer.clone())
 4347                .or_default()
 4348                .push(start..end);
 4349        }
 4350        Some(linked_edits)
 4351    }
 4352
 4353    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4354        let text: Arc<str> = text.into();
 4355
 4356        if self.read_only(cx) {
 4357            return;
 4358        }
 4359
 4360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4361
 4362        self.unfold_buffers_with_selections(cx);
 4363
 4364        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4365        let mut bracket_inserted = false;
 4366        let mut edits = Vec::new();
 4367        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4368        let mut new_selections = Vec::with_capacity(selections.len());
 4369        let mut new_autoclose_regions = Vec::new();
 4370        let snapshot = self.buffer.read(cx).read(cx);
 4371        let mut clear_linked_edit_ranges = false;
 4372        let mut all_selections_read_only = true;
 4373        let mut has_adjacent_edits = false;
 4374        let mut in_adjacent_group = false;
 4375
 4376        let mut regions = self
 4377            .selections_with_autoclose_regions(selections, &snapshot)
 4378            .peekable();
 4379
 4380        while let Some((selection, autoclose_region)) = regions.next() {
 4381            if snapshot
 4382                .point_to_buffer_point(selection.head())
 4383                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4384            {
 4385                continue;
 4386            }
 4387            if snapshot
 4388                .point_to_buffer_point(selection.tail())
 4389                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4390            {
 4391                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4392                continue;
 4393            }
 4394            all_selections_read_only = false;
 4395
 4396            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4397                // Determine if the inserted text matches the opening or closing
 4398                // bracket of any of this language's bracket pairs.
 4399                let mut bracket_pair = None;
 4400                let mut is_bracket_pair_start = false;
 4401                let mut is_bracket_pair_end = false;
 4402                if !text.is_empty() {
 4403                    let mut bracket_pair_matching_end = None;
 4404                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4405                    //  and they are removing the character that triggered IME popup.
 4406                    for (pair, enabled) in scope.brackets() {
 4407                        if !pair.close && !pair.surround {
 4408                            continue;
 4409                        }
 4410
 4411                        if enabled && pair.start.ends_with(text.as_ref()) {
 4412                            let prefix_len = pair.start.len() - text.len();
 4413                            let preceding_text_matches_prefix = prefix_len == 0
 4414                                || (selection.start.column >= (prefix_len as u32)
 4415                                    && snapshot.contains_str_at(
 4416                                        Point::new(
 4417                                            selection.start.row,
 4418                                            selection.start.column - (prefix_len as u32),
 4419                                        ),
 4420                                        &pair.start[..prefix_len],
 4421                                    ));
 4422                            if preceding_text_matches_prefix {
 4423                                bracket_pair = Some(pair.clone());
 4424                                is_bracket_pair_start = true;
 4425                                break;
 4426                            }
 4427                        }
 4428                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4429                        {
 4430                            // take first bracket pair matching end, but don't break in case a later bracket
 4431                            // pair matches start
 4432                            bracket_pair_matching_end = Some(pair.clone());
 4433                        }
 4434                    }
 4435                    if let Some(end) = bracket_pair_matching_end
 4436                        && bracket_pair.is_none()
 4437                    {
 4438                        bracket_pair = Some(end);
 4439                        is_bracket_pair_end = true;
 4440                    }
 4441                }
 4442
 4443                if let Some(bracket_pair) = bracket_pair {
 4444                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4445                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4446                    let auto_surround =
 4447                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4448                    if selection.is_empty() {
 4449                        if is_bracket_pair_start {
 4450                            // If the inserted text is a suffix of an opening bracket and the
 4451                            // selection is preceded by the rest of the opening bracket, then
 4452                            // insert the closing bracket.
 4453                            let following_text_allows_autoclose = snapshot
 4454                                .chars_at(selection.start)
 4455                                .next()
 4456                                .is_none_or(|c| scope.should_autoclose_before(c));
 4457
 4458                            let preceding_text_allows_autoclose = selection.start.column == 0
 4459                                || snapshot
 4460                                    .reversed_chars_at(selection.start)
 4461                                    .next()
 4462                                    .is_none_or(|c| {
 4463                                        bracket_pair.start != bracket_pair.end
 4464                                            || !snapshot
 4465                                                .char_classifier_at(selection.start)
 4466                                                .is_word(c)
 4467                                    });
 4468
 4469                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4470                                && bracket_pair.start.len() == 1
 4471                            {
 4472                                let target = bracket_pair.start.chars().next().unwrap();
 4473                                let mut byte_offset = 0u32;
 4474                                let current_line_count = snapshot
 4475                                    .reversed_chars_at(selection.start)
 4476                                    .take_while(|&c| c != '\n')
 4477                                    .filter(|c| {
 4478                                        byte_offset += c.len_utf8() as u32;
 4479                                        if *c != target {
 4480                                            return false;
 4481                                        }
 4482
 4483                                        let point = Point::new(
 4484                                            selection.start.row,
 4485                                            selection.start.column.saturating_sub(byte_offset),
 4486                                        );
 4487
 4488                                        let is_enabled = snapshot
 4489                                            .language_scope_at(point)
 4490                                            .and_then(|scope| {
 4491                                                scope
 4492                                                    .brackets()
 4493                                                    .find(|(pair, _)| {
 4494                                                        pair.start == bracket_pair.start
 4495                                                    })
 4496                                                    .map(|(_, enabled)| enabled)
 4497                                            })
 4498                                            .unwrap_or(true);
 4499
 4500                                        let is_delimiter = snapshot
 4501                                            .language_scope_at(Point::new(
 4502                                                point.row,
 4503                                                point.column + 1,
 4504                                            ))
 4505                                            .and_then(|scope| {
 4506                                                scope
 4507                                                    .brackets()
 4508                                                    .find(|(pair, _)| {
 4509                                                        pair.start == bracket_pair.start
 4510                                                    })
 4511                                                    .map(|(_, enabled)| !enabled)
 4512                                            })
 4513                                            .unwrap_or(false);
 4514
 4515                                        is_enabled && !is_delimiter
 4516                                    })
 4517                                    .count();
 4518                                current_line_count % 2 == 1
 4519                            } else {
 4520                                false
 4521                            };
 4522
 4523                            if autoclose
 4524                                && bracket_pair.close
 4525                                && following_text_allows_autoclose
 4526                                && preceding_text_allows_autoclose
 4527                                && !is_closing_quote
 4528                            {
 4529                                let anchor = snapshot.anchor_before(selection.end);
 4530                                new_selections.push((selection.map(|_| anchor), text.len()));
 4531                                new_autoclose_regions.push((
 4532                                    anchor,
 4533                                    text.len(),
 4534                                    selection.id,
 4535                                    bracket_pair.clone(),
 4536                                ));
 4537                                edits.push((
 4538                                    selection.range(),
 4539                                    format!("{}{}", text, bracket_pair.end).into(),
 4540                                ));
 4541                                bracket_inserted = true;
 4542                                continue;
 4543                            }
 4544                        }
 4545
 4546                        if let Some(region) = autoclose_region {
 4547                            // If the selection is followed by an auto-inserted closing bracket,
 4548                            // then don't insert that closing bracket again; just move the selection
 4549                            // past the closing bracket.
 4550                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4551                                && text.as_ref() == region.pair.end.as_str()
 4552                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4553                            if should_skip {
 4554                                let anchor = snapshot.anchor_after(selection.end);
 4555                                new_selections
 4556                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4557                                continue;
 4558                            }
 4559                        }
 4560
 4561                        let always_treat_brackets_as_autoclosed = snapshot
 4562                            .language_settings_at(selection.start, cx)
 4563                            .always_treat_brackets_as_autoclosed;
 4564                        if always_treat_brackets_as_autoclosed
 4565                            && is_bracket_pair_end
 4566                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4567                        {
 4568                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4569                            // and the inserted text is a closing bracket and the selection is followed
 4570                            // by the closing bracket then move the selection past the closing bracket.
 4571                            let anchor = snapshot.anchor_after(selection.end);
 4572                            new_selections.push((selection.map(|_| anchor), text.len()));
 4573                            continue;
 4574                        }
 4575                    }
 4576                    // If an opening bracket is 1 character long and is typed while
 4577                    // text is selected, then surround that text with the bracket pair.
 4578                    else if auto_surround
 4579                        && bracket_pair.surround
 4580                        && is_bracket_pair_start
 4581                        && bracket_pair.start.chars().count() == 1
 4582                    {
 4583                        edits.push((selection.start..selection.start, text.clone()));
 4584                        edits.push((
 4585                            selection.end..selection.end,
 4586                            bracket_pair.end.as_str().into(),
 4587                        ));
 4588                        bracket_inserted = true;
 4589                        new_selections.push((
 4590                            Selection {
 4591                                id: selection.id,
 4592                                start: snapshot.anchor_after(selection.start),
 4593                                end: snapshot.anchor_before(selection.end),
 4594                                reversed: selection.reversed,
 4595                                goal: selection.goal,
 4596                            },
 4597                            0,
 4598                        ));
 4599                        continue;
 4600                    }
 4601                }
 4602            }
 4603
 4604            if self.auto_replace_emoji_shortcode
 4605                && selection.is_empty()
 4606                && text.as_ref().ends_with(':')
 4607                && let Some(possible_emoji_short_code) =
 4608                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4609                && !possible_emoji_short_code.is_empty()
 4610                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4611            {
 4612                let emoji_shortcode_start = Point::new(
 4613                    selection.start.row,
 4614                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4615                );
 4616
 4617                // Remove shortcode from buffer
 4618                edits.push((
 4619                    emoji_shortcode_start..selection.start,
 4620                    "".to_string().into(),
 4621                ));
 4622                new_selections.push((
 4623                    Selection {
 4624                        id: selection.id,
 4625                        start: snapshot.anchor_after(emoji_shortcode_start),
 4626                        end: snapshot.anchor_before(selection.start),
 4627                        reversed: selection.reversed,
 4628                        goal: selection.goal,
 4629                    },
 4630                    0,
 4631                ));
 4632
 4633                // Insert emoji
 4634                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4635                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4636                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4637
 4638                continue;
 4639            }
 4640
 4641            let next_is_adjacent = regions
 4642                .peek()
 4643                .is_some_and(|(next, _)| selection.end == next.start);
 4644
 4645            // If not handling any auto-close operation, then just replace the selected
 4646            // text with the given input and move the selection to the end of the
 4647            // newly inserted text.
 4648            let anchor = if in_adjacent_group || next_is_adjacent {
 4649                // After edits the right bias would shift those anchor to the next visible fragment
 4650                // but we want to resolve to the previous one
 4651                snapshot.anchor_before(selection.end)
 4652            } else {
 4653                snapshot.anchor_after(selection.end)
 4654            };
 4655
 4656            if !self.linked_edit_ranges.is_empty() {
 4657                let start_anchor = snapshot.anchor_before(selection.start);
 4658
 4659                let is_word_char = text.chars().next().is_none_or(|char| {
 4660                    let classifier = snapshot
 4661                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4662                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4663                    classifier.is_word(char)
 4664                });
 4665
 4666                if is_word_char {
 4667                    if let Some(ranges) = self
 4668                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4669                    {
 4670                        for (buffer, edits) in ranges {
 4671                            linked_edits
 4672                                .entry(buffer.clone())
 4673                                .or_default()
 4674                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4675                        }
 4676                    }
 4677                } else {
 4678                    clear_linked_edit_ranges = true;
 4679                }
 4680            }
 4681
 4682            new_selections.push((selection.map(|_| anchor), 0));
 4683            edits.push((selection.start..selection.end, text.clone()));
 4684
 4685            has_adjacent_edits |= next_is_adjacent;
 4686            in_adjacent_group = next_is_adjacent;
 4687        }
 4688
 4689        if all_selections_read_only {
 4690            return;
 4691        }
 4692
 4693        drop(regions);
 4694        drop(snapshot);
 4695
 4696        self.transact(window, cx, |this, window, cx| {
 4697            if clear_linked_edit_ranges {
 4698                this.linked_edit_ranges.clear();
 4699            }
 4700            let initial_buffer_versions =
 4701                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4702
 4703            this.buffer.update(cx, |buffer, cx| {
 4704                if has_adjacent_edits {
 4705                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4706                } else {
 4707                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4708                }
 4709            });
 4710            for (buffer, edits) in linked_edits {
 4711                buffer.update(cx, |buffer, cx| {
 4712                    let snapshot = buffer.snapshot();
 4713                    let edits = edits
 4714                        .into_iter()
 4715                        .map(|(range, text)| {
 4716                            use text::ToPoint as TP;
 4717                            let end_point = TP::to_point(&range.end, &snapshot);
 4718                            let start_point = TP::to_point(&range.start, &snapshot);
 4719                            (start_point..end_point, text)
 4720                        })
 4721                        .sorted_by_key(|(range, _)| range.start);
 4722                    buffer.edit(edits, None, cx);
 4723                })
 4724            }
 4725            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4726            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4727            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4728            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4729                new_anchor_selections,
 4730                &map,
 4731            )
 4732            .zip(new_selection_deltas)
 4733            .map(|(selection, delta)| Selection {
 4734                id: selection.id,
 4735                start: selection.start + delta,
 4736                end: selection.end + delta,
 4737                reversed: selection.reversed,
 4738                goal: SelectionGoal::None,
 4739            })
 4740            .collect::<Vec<_>>();
 4741
 4742            let mut i = 0;
 4743            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4744                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4745                let start = map.buffer_snapshot().anchor_before(position);
 4746                let end = map.buffer_snapshot().anchor_after(position);
 4747                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4748                    match existing_state
 4749                        .range
 4750                        .start
 4751                        .cmp(&start, map.buffer_snapshot())
 4752                    {
 4753                        Ordering::Less => i += 1,
 4754                        Ordering::Greater => break,
 4755                        Ordering::Equal => {
 4756                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4757                                Ordering::Less => i += 1,
 4758                                Ordering::Equal => break,
 4759                                Ordering::Greater => break,
 4760                            }
 4761                        }
 4762                    }
 4763                }
 4764                this.autoclose_regions.insert(
 4765                    i,
 4766                    AutocloseRegion {
 4767                        selection_id,
 4768                        range: start..end,
 4769                        pair,
 4770                    },
 4771                );
 4772            }
 4773
 4774            let had_active_edit_prediction = this.has_active_edit_prediction();
 4775            this.change_selections(
 4776                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4777                window,
 4778                cx,
 4779                |s| s.select(new_selections),
 4780            );
 4781
 4782            if !bracket_inserted
 4783                && let Some(on_type_format_task) =
 4784                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4785            {
 4786                on_type_format_task.detach_and_log_err(cx);
 4787            }
 4788
 4789            let editor_settings = EditorSettings::get_global(cx);
 4790            if bracket_inserted
 4791                && (editor_settings.auto_signature_help
 4792                    || editor_settings.show_signature_help_after_edits)
 4793            {
 4794                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4795            }
 4796
 4797            let trigger_in_words =
 4798                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4799            if this.hard_wrap.is_some() {
 4800                let latest: Range<Point> = this.selections.newest(&map).range();
 4801                if latest.is_empty()
 4802                    && this
 4803                        .buffer()
 4804                        .read(cx)
 4805                        .snapshot(cx)
 4806                        .line_len(MultiBufferRow(latest.start.row))
 4807                        == latest.start.column
 4808                {
 4809                    this.rewrap_impl(
 4810                        RewrapOptions {
 4811                            override_language_settings: true,
 4812                            preserve_existing_whitespace: true,
 4813                        },
 4814                        cx,
 4815                    )
 4816                }
 4817            }
 4818            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4819            refresh_linked_ranges(this, window, cx);
 4820            this.refresh_edit_prediction(true, false, window, cx);
 4821            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4822        });
 4823    }
 4824
 4825    fn find_possible_emoji_shortcode_at_position(
 4826        snapshot: &MultiBufferSnapshot,
 4827        position: Point,
 4828    ) -> Option<String> {
 4829        let mut chars = Vec::new();
 4830        let mut found_colon = false;
 4831        for char in snapshot.reversed_chars_at(position).take(100) {
 4832            // Found a possible emoji shortcode in the middle of the buffer
 4833            if found_colon {
 4834                if char.is_whitespace() {
 4835                    chars.reverse();
 4836                    return Some(chars.iter().collect());
 4837                }
 4838                // If the previous character is not a whitespace, we are in the middle of a word
 4839                // and we only want to complete the shortcode if the word is made up of other emojis
 4840                let mut containing_word = String::new();
 4841                for ch in snapshot
 4842                    .reversed_chars_at(position)
 4843                    .skip(chars.len() + 1)
 4844                    .take(100)
 4845                {
 4846                    if ch.is_whitespace() {
 4847                        break;
 4848                    }
 4849                    containing_word.push(ch);
 4850                }
 4851                let containing_word = containing_word.chars().rev().collect::<String>();
 4852                if util::word_consists_of_emojis(containing_word.as_str()) {
 4853                    chars.reverse();
 4854                    return Some(chars.iter().collect());
 4855                }
 4856            }
 4857
 4858            if char.is_whitespace() || !char.is_ascii() {
 4859                return None;
 4860            }
 4861            if char == ':' {
 4862                found_colon = true;
 4863            } else {
 4864                chars.push(char);
 4865            }
 4866        }
 4867        // Found a possible emoji shortcode at the beginning of the buffer
 4868        chars.reverse();
 4869        Some(chars.iter().collect())
 4870    }
 4871
 4872    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4874        self.transact(window, cx, |this, window, cx| {
 4875            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4876                let selections = this
 4877                    .selections
 4878                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4879                let multi_buffer = this.buffer.read(cx);
 4880                let buffer = multi_buffer.snapshot(cx);
 4881                selections
 4882                    .iter()
 4883                    .map(|selection| {
 4884                        let start_point = selection.start.to_point(&buffer);
 4885                        let mut existing_indent =
 4886                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4887                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4888                        let start = selection.start;
 4889                        let end = selection.end;
 4890                        let selection_is_empty = start == end;
 4891                        let language_scope = buffer.language_scope_at(start);
 4892                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4893                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4894                                &buffer,
 4895                                start..end,
 4896                                language,
 4897                            )
 4898                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4899                                    &buffer,
 4900                                    start..end,
 4901                                );
 4902
 4903                            let mut newline_config = NewlineConfig::Newline {
 4904                                additional_indent: IndentSize::spaces(0),
 4905                                extra_line_additional_indent: if needs_extra_newline {
 4906                                    Some(IndentSize::spaces(0))
 4907                                } else {
 4908                                    None
 4909                                },
 4910                                prevent_auto_indent: false,
 4911                            };
 4912
 4913                            let comment_delimiter = maybe!({
 4914                                if !selection_is_empty {
 4915                                    return None;
 4916                                }
 4917
 4918                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4919                                    return None;
 4920                                }
 4921
 4922                                return comment_delimiter_for_newline(
 4923                                    &start_point,
 4924                                    &buffer,
 4925                                    language,
 4926                                );
 4927                            });
 4928
 4929                            let doc_delimiter = maybe!({
 4930                                if !selection_is_empty {
 4931                                    return None;
 4932                                }
 4933
 4934                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4935                                    return None;
 4936                                }
 4937
 4938                                return documentation_delimiter_for_newline(
 4939                                    &start_point,
 4940                                    &buffer,
 4941                                    language,
 4942                                    &mut newline_config,
 4943                                );
 4944                            });
 4945
 4946                            let list_delimiter = maybe!({
 4947                                if !selection_is_empty {
 4948                                    return None;
 4949                                }
 4950
 4951                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4952                                    return None;
 4953                                }
 4954
 4955                                return list_delimiter_for_newline(
 4956                                    &start_point,
 4957                                    &buffer,
 4958                                    language,
 4959                                    &mut newline_config,
 4960                                );
 4961                            });
 4962
 4963                            (
 4964                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4965                                newline_config,
 4966                            )
 4967                        } else {
 4968                            (
 4969                                None,
 4970                                NewlineConfig::Newline {
 4971                                    additional_indent: IndentSize::spaces(0),
 4972                                    extra_line_additional_indent: None,
 4973                                    prevent_auto_indent: false,
 4974                                },
 4975                            )
 4976                        };
 4977
 4978                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4979                            NewlineConfig::ClearCurrentLine => {
 4980                                let row_start =
 4981                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4982                                (row_start, String::new(), false)
 4983                            }
 4984                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4985                                let row_start =
 4986                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4987                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4988                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4989                                let reduced_indent =
 4990                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4991                                let mut new_text = String::new();
 4992                                new_text.extend(reduced_indent.chars());
 4993                                new_text.push_str(continuation);
 4994                                (row_start, new_text, true)
 4995                            }
 4996                            NewlineConfig::Newline {
 4997                                additional_indent,
 4998                                extra_line_additional_indent,
 4999                                prevent_auto_indent,
 5000                            } => {
 5001                                let capacity_for_delimiter =
 5002                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5003                                let extra_line_len = extra_line_additional_indent
 5004                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 5005                                    .unwrap_or(0);
 5006                                let mut new_text = String::with_capacity(
 5007                                    1 + capacity_for_delimiter
 5008                                        + existing_indent.len as usize
 5009                                        + additional_indent.len as usize
 5010                                        + extra_line_len,
 5011                                );
 5012                                new_text.push('\n');
 5013                                new_text.extend(existing_indent.chars());
 5014                                new_text.extend(additional_indent.chars());
 5015                                if let Some(delimiter) = &delimiter {
 5016                                    new_text.push_str(delimiter);
 5017                                }
 5018                                if let Some(extra_indent) = extra_line_additional_indent {
 5019                                    new_text.push('\n');
 5020                                    new_text.extend(existing_indent.chars());
 5021                                    new_text.extend(extra_indent.chars());
 5022                                }
 5023                                (start, new_text, *prevent_auto_indent)
 5024                            }
 5025                        };
 5026
 5027                        let anchor = buffer.anchor_after(end);
 5028                        let new_selection = selection.map(|_| anchor);
 5029                        (
 5030                            ((edit_start..end, new_text), prevent_auto_indent),
 5031                            (newline_config.has_extra_line(), new_selection),
 5032                        )
 5033                    })
 5034                    .unzip()
 5035            };
 5036
 5037            let mut auto_indent_edits = Vec::new();
 5038            let mut edits = Vec::new();
 5039            for (edit, prevent_auto_indent) in edits_with_flags {
 5040                if prevent_auto_indent {
 5041                    edits.push(edit);
 5042                } else {
 5043                    auto_indent_edits.push(edit);
 5044                }
 5045            }
 5046            if !edits.is_empty() {
 5047                this.edit(edits, cx);
 5048            }
 5049            if !auto_indent_edits.is_empty() {
 5050                this.edit_with_autoindent(auto_indent_edits, cx);
 5051            }
 5052
 5053            let buffer = this.buffer.read(cx).snapshot(cx);
 5054            let new_selections = selection_info
 5055                .into_iter()
 5056                .map(|(extra_newline_inserted, new_selection)| {
 5057                    let mut cursor = new_selection.end.to_point(&buffer);
 5058                    if extra_newline_inserted {
 5059                        cursor.row -= 1;
 5060                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5061                    }
 5062                    new_selection.map(|_| cursor)
 5063                })
 5064                .collect();
 5065
 5066            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5067            this.refresh_edit_prediction(true, false, window, cx);
 5068            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5069                task.detach_and_log_err(cx);
 5070            }
 5071        });
 5072    }
 5073
 5074    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5076
 5077        let buffer = self.buffer.read(cx);
 5078        let snapshot = buffer.snapshot(cx);
 5079
 5080        let mut edits = Vec::new();
 5081        let mut rows = Vec::new();
 5082
 5083        for (rows_inserted, selection) in self
 5084            .selections
 5085            .all_adjusted(&self.display_snapshot(cx))
 5086            .into_iter()
 5087            .enumerate()
 5088        {
 5089            let cursor = selection.head();
 5090            let row = cursor.row;
 5091
 5092            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5093
 5094            let newline = "\n".to_string();
 5095            edits.push((start_of_line..start_of_line, newline));
 5096
 5097            rows.push(row + rows_inserted as u32);
 5098        }
 5099
 5100        self.transact(window, cx, |editor, window, cx| {
 5101            editor.edit(edits, cx);
 5102
 5103            editor.change_selections(Default::default(), window, cx, |s| {
 5104                let mut index = 0;
 5105                s.move_cursors_with(|map, _, _| {
 5106                    let row = rows[index];
 5107                    index += 1;
 5108
 5109                    let point = Point::new(row, 0);
 5110                    let boundary = map.next_line_boundary(point).1;
 5111                    let clipped = map.clip_point(boundary, Bias::Left);
 5112
 5113                    (clipped, SelectionGoal::None)
 5114                });
 5115            });
 5116
 5117            let mut indent_edits = Vec::new();
 5118            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5119            for row in rows {
 5120                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5121                for (row, indent) in indents {
 5122                    if indent.len == 0 {
 5123                        continue;
 5124                    }
 5125
 5126                    let text = match indent.kind {
 5127                        IndentKind::Space => " ".repeat(indent.len as usize),
 5128                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5129                    };
 5130                    let point = Point::new(row.0, 0);
 5131                    indent_edits.push((point..point, text));
 5132                }
 5133            }
 5134            editor.edit(indent_edits, cx);
 5135            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5136                format.detach_and_log_err(cx);
 5137            }
 5138        });
 5139    }
 5140
 5141    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5143
 5144        let buffer = self.buffer.read(cx);
 5145        let snapshot = buffer.snapshot(cx);
 5146
 5147        let mut edits = Vec::new();
 5148        let mut rows = Vec::new();
 5149        let mut rows_inserted = 0;
 5150
 5151        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5152            let cursor = selection.head();
 5153            let row = cursor.row;
 5154
 5155            let point = Point::new(row + 1, 0);
 5156            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5157
 5158            let newline = "\n".to_string();
 5159            edits.push((start_of_line..start_of_line, newline));
 5160
 5161            rows_inserted += 1;
 5162            rows.push(row + rows_inserted);
 5163        }
 5164
 5165        self.transact(window, cx, |editor, window, cx| {
 5166            editor.edit(edits, cx);
 5167
 5168            editor.change_selections(Default::default(), window, cx, |s| {
 5169                let mut index = 0;
 5170                s.move_cursors_with(|map, _, _| {
 5171                    let row = rows[index];
 5172                    index += 1;
 5173
 5174                    let point = Point::new(row, 0);
 5175                    let boundary = map.next_line_boundary(point).1;
 5176                    let clipped = map.clip_point(boundary, Bias::Left);
 5177
 5178                    (clipped, SelectionGoal::None)
 5179                });
 5180            });
 5181
 5182            let mut indent_edits = Vec::new();
 5183            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5184            for row in rows {
 5185                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5186                for (row, indent) in indents {
 5187                    if indent.len == 0 {
 5188                        continue;
 5189                    }
 5190
 5191                    let text = match indent.kind {
 5192                        IndentKind::Space => " ".repeat(indent.len as usize),
 5193                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5194                    };
 5195                    let point = Point::new(row.0, 0);
 5196                    indent_edits.push((point..point, text));
 5197                }
 5198            }
 5199            editor.edit(indent_edits, cx);
 5200            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5201                format.detach_and_log_err(cx);
 5202            }
 5203        });
 5204    }
 5205
 5206    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5207        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5208            original_indent_columns: Vec::new(),
 5209        });
 5210        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5211    }
 5212
 5213    fn insert_with_autoindent_mode(
 5214        &mut self,
 5215        text: &str,
 5216        autoindent_mode: Option<AutoindentMode>,
 5217        window: &mut Window,
 5218        cx: &mut Context<Self>,
 5219    ) {
 5220        if self.read_only(cx) {
 5221            return;
 5222        }
 5223
 5224        let text: Arc<str> = text.into();
 5225        self.transact(window, cx, |this, window, cx| {
 5226            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5227            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5228                let anchors = {
 5229                    let snapshot = buffer.read(cx);
 5230                    old_selections
 5231                        .iter()
 5232                        .map(|s| {
 5233                            let anchor = snapshot.anchor_after(s.head());
 5234                            s.map(|_| anchor)
 5235                        })
 5236                        .collect::<Vec<_>>()
 5237                };
 5238                buffer.edit(
 5239                    old_selections
 5240                        .iter()
 5241                        .map(|s| (s.start..s.end, text.clone())),
 5242                    autoindent_mode,
 5243                    cx,
 5244                );
 5245                anchors
 5246            });
 5247
 5248            this.change_selections(Default::default(), window, cx, |s| {
 5249                s.select_anchors(selection_anchors);
 5250            });
 5251
 5252            cx.notify();
 5253        });
 5254    }
 5255
 5256    fn trigger_completion_on_input(
 5257        &mut self,
 5258        text: &str,
 5259        trigger_in_words: bool,
 5260        window: &mut Window,
 5261        cx: &mut Context<Self>,
 5262    ) {
 5263        let completions_source = self
 5264            .context_menu
 5265            .borrow()
 5266            .as_ref()
 5267            .and_then(|menu| match menu {
 5268                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5269                CodeContextMenu::CodeActions(_) => None,
 5270            });
 5271
 5272        match completions_source {
 5273            Some(CompletionsMenuSource::Words { .. }) => {
 5274                self.open_or_update_completions_menu(
 5275                    Some(CompletionsMenuSource::Words {
 5276                        ignore_threshold: false,
 5277                    }),
 5278                    None,
 5279                    trigger_in_words,
 5280                    window,
 5281                    cx,
 5282                );
 5283            }
 5284            _ => self.open_or_update_completions_menu(
 5285                None,
 5286                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5287                true,
 5288                window,
 5289                cx,
 5290            ),
 5291        }
 5292    }
 5293
 5294    /// If any empty selections is touching the start of its innermost containing autoclose
 5295    /// region, expand it to select the brackets.
 5296    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5297        let selections = self
 5298            .selections
 5299            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5300        let buffer = self.buffer.read(cx).read(cx);
 5301        let new_selections = self
 5302            .selections_with_autoclose_regions(selections, &buffer)
 5303            .map(|(mut selection, region)| {
 5304                if !selection.is_empty() {
 5305                    return selection;
 5306                }
 5307
 5308                if let Some(region) = region {
 5309                    let mut range = region.range.to_offset(&buffer);
 5310                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5311                        range.start -= region.pair.start.len();
 5312                        if buffer.contains_str_at(range.start, &region.pair.start)
 5313                            && buffer.contains_str_at(range.end, &region.pair.end)
 5314                        {
 5315                            range.end += region.pair.end.len();
 5316                            selection.start = range.start;
 5317                            selection.end = range.end;
 5318
 5319                            return selection;
 5320                        }
 5321                    }
 5322                }
 5323
 5324                let always_treat_brackets_as_autoclosed = buffer
 5325                    .language_settings_at(selection.start, cx)
 5326                    .always_treat_brackets_as_autoclosed;
 5327
 5328                if !always_treat_brackets_as_autoclosed {
 5329                    return selection;
 5330                }
 5331
 5332                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5333                    for (pair, enabled) in scope.brackets() {
 5334                        if !enabled || !pair.close {
 5335                            continue;
 5336                        }
 5337
 5338                        if buffer.contains_str_at(selection.start, &pair.end) {
 5339                            let pair_start_len = pair.start.len();
 5340                            if buffer.contains_str_at(
 5341                                selection.start.saturating_sub_usize(pair_start_len),
 5342                                &pair.start,
 5343                            ) {
 5344                                selection.start -= pair_start_len;
 5345                                selection.end += pair.end.len();
 5346
 5347                                return selection;
 5348                            }
 5349                        }
 5350                    }
 5351                }
 5352
 5353                selection
 5354            })
 5355            .collect();
 5356
 5357        drop(buffer);
 5358        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5359            selections.select(new_selections)
 5360        });
 5361    }
 5362
 5363    /// Iterate the given selections, and for each one, find the smallest surrounding
 5364    /// autoclose region. This uses the ordering of the selections and the autoclose
 5365    /// regions to avoid repeated comparisons.
 5366    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5367        &'a self,
 5368        selections: impl IntoIterator<Item = Selection<D>>,
 5369        buffer: &'a MultiBufferSnapshot,
 5370    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5371        let mut i = 0;
 5372        let mut regions = self.autoclose_regions.as_slice();
 5373        selections.into_iter().map(move |selection| {
 5374            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5375
 5376            let mut enclosing = None;
 5377            while let Some(pair_state) = regions.get(i) {
 5378                if pair_state.range.end.to_offset(buffer) < range.start {
 5379                    regions = &regions[i + 1..];
 5380                    i = 0;
 5381                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5382                    break;
 5383                } else {
 5384                    if pair_state.selection_id == selection.id {
 5385                        enclosing = Some(pair_state);
 5386                    }
 5387                    i += 1;
 5388                }
 5389            }
 5390
 5391            (selection, enclosing)
 5392        })
 5393    }
 5394
 5395    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5396    fn invalidate_autoclose_regions(
 5397        &mut self,
 5398        mut selections: &[Selection<Anchor>],
 5399        buffer: &MultiBufferSnapshot,
 5400    ) {
 5401        self.autoclose_regions.retain(|state| {
 5402            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5403                return false;
 5404            }
 5405
 5406            let mut i = 0;
 5407            while let Some(selection) = selections.get(i) {
 5408                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5409                    selections = &selections[1..];
 5410                    continue;
 5411                }
 5412                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5413                    break;
 5414                }
 5415                if selection.id == state.selection_id {
 5416                    return true;
 5417                } else {
 5418                    i += 1;
 5419                }
 5420            }
 5421            false
 5422        });
 5423    }
 5424
 5425    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5426        let offset = position.to_offset(buffer);
 5427        let (word_range, kind) =
 5428            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5429        if offset > word_range.start && kind == Some(CharKind::Word) {
 5430            Some(
 5431                buffer
 5432                    .text_for_range(word_range.start..offset)
 5433                    .collect::<String>(),
 5434            )
 5435        } else {
 5436            None
 5437        }
 5438    }
 5439
 5440    pub fn visible_excerpts(
 5441        &self,
 5442        lsp_related_only: bool,
 5443        cx: &mut Context<Editor>,
 5444    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5445        let project = self.project().cloned();
 5446        let multi_buffer = self.buffer().read(cx);
 5447        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5448        let multi_buffer_visible_start = self
 5449            .scroll_manager
 5450            .anchor()
 5451            .anchor
 5452            .to_point(&multi_buffer_snapshot);
 5453        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5454            multi_buffer_visible_start
 5455                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5456            Bias::Left,
 5457        );
 5458        multi_buffer_snapshot
 5459            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5460            .into_iter()
 5461            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5462            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5463                if !lsp_related_only {
 5464                    return Some((
 5465                        excerpt_id,
 5466                        (
 5467                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5468                            buffer.version().clone(),
 5469                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5470                        ),
 5471                    ));
 5472                }
 5473
 5474                let project = project.as_ref()?.read(cx);
 5475                let buffer_file = project::File::from_dyn(buffer.file())?;
 5476                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5477                let worktree_entry = buffer_worktree
 5478                    .read(cx)
 5479                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5480                if worktree_entry.is_ignored {
 5481                    None
 5482                } else {
 5483                    Some((
 5484                        excerpt_id,
 5485                        (
 5486                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5487                            buffer.version().clone(),
 5488                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5489                        ),
 5490                    ))
 5491                }
 5492            })
 5493            .collect()
 5494    }
 5495
 5496    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5497        TextLayoutDetails {
 5498            text_system: window.text_system().clone(),
 5499            editor_style: self.style.clone().unwrap(),
 5500            rem_size: window.rem_size(),
 5501            scroll_anchor: self.scroll_manager.anchor(),
 5502            visible_rows: self.visible_line_count(),
 5503            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5504        }
 5505    }
 5506
 5507    fn trigger_on_type_formatting(
 5508        &self,
 5509        input: String,
 5510        window: &mut Window,
 5511        cx: &mut Context<Self>,
 5512    ) -> Option<Task<Result<()>>> {
 5513        if input.chars().count() != 1 {
 5514            return None;
 5515        }
 5516
 5517        let project = self.project()?;
 5518        let position = self.selections.newest_anchor().head();
 5519        let (buffer, buffer_position) = self
 5520            .buffer
 5521            .read(cx)
 5522            .text_anchor_for_position(position, cx)?;
 5523
 5524        let settings = language_settings::language_settings(
 5525            buffer
 5526                .read(cx)
 5527                .language_at(buffer_position)
 5528                .map(|l| l.name()),
 5529            buffer.read(cx).file(),
 5530            cx,
 5531        );
 5532        if !settings.use_on_type_format {
 5533            return None;
 5534        }
 5535
 5536        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5537        // hence we do LSP request & edit on host side only — add formats to host's history.
 5538        let push_to_lsp_host_history = true;
 5539        // If this is not the host, append its history with new edits.
 5540        let push_to_client_history = project.read(cx).is_via_collab();
 5541
 5542        let on_type_formatting = project.update(cx, |project, cx| {
 5543            project.on_type_format(
 5544                buffer.clone(),
 5545                buffer_position,
 5546                input,
 5547                push_to_lsp_host_history,
 5548                cx,
 5549            )
 5550        });
 5551        Some(cx.spawn_in(window, async move |editor, cx| {
 5552            if let Some(transaction) = on_type_formatting.await? {
 5553                if push_to_client_history {
 5554                    buffer.update(cx, |buffer, _| {
 5555                        buffer.push_transaction(transaction, Instant::now());
 5556                        buffer.finalize_last_transaction();
 5557                    });
 5558                }
 5559                editor.update(cx, |editor, cx| {
 5560                    editor.refresh_document_highlights(cx);
 5561                })?;
 5562            }
 5563            Ok(())
 5564        }))
 5565    }
 5566
 5567    pub fn show_word_completions(
 5568        &mut self,
 5569        _: &ShowWordCompletions,
 5570        window: &mut Window,
 5571        cx: &mut Context<Self>,
 5572    ) {
 5573        self.open_or_update_completions_menu(
 5574            Some(CompletionsMenuSource::Words {
 5575                ignore_threshold: true,
 5576            }),
 5577            None,
 5578            false,
 5579            window,
 5580            cx,
 5581        );
 5582    }
 5583
 5584    pub fn show_completions(
 5585        &mut self,
 5586        _: &ShowCompletions,
 5587        window: &mut Window,
 5588        cx: &mut Context<Self>,
 5589    ) {
 5590        self.open_or_update_completions_menu(None, None, false, window, cx);
 5591    }
 5592
 5593    fn open_or_update_completions_menu(
 5594        &mut self,
 5595        requested_source: Option<CompletionsMenuSource>,
 5596        trigger: Option<String>,
 5597        trigger_in_words: bool,
 5598        window: &mut Window,
 5599        cx: &mut Context<Self>,
 5600    ) {
 5601        if self.pending_rename.is_some() {
 5602            return;
 5603        }
 5604
 5605        let completions_source = self
 5606            .context_menu
 5607            .borrow()
 5608            .as_ref()
 5609            .and_then(|menu| match menu {
 5610                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5611                CodeContextMenu::CodeActions(_) => None,
 5612            });
 5613
 5614        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5615
 5616        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5617        // inserted and selected. To handle that case, the start of the selection is used so that
 5618        // the menu starts with all choices.
 5619        let position = self
 5620            .selections
 5621            .newest_anchor()
 5622            .start
 5623            .bias_right(&multibuffer_snapshot);
 5624        if position.diff_base_anchor.is_some() {
 5625            return;
 5626        }
 5627        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5628        let Some(buffer) = buffer_position
 5629            .text_anchor
 5630            .buffer_id
 5631            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5632        else {
 5633            return;
 5634        };
 5635        let buffer_snapshot = buffer.read(cx).snapshot();
 5636
 5637        let menu_is_open = matches!(
 5638            self.context_menu.borrow().as_ref(),
 5639            Some(CodeContextMenu::Completions(_))
 5640        );
 5641
 5642        let language = buffer_snapshot
 5643            .language_at(buffer_position.text_anchor)
 5644            .map(|language| language.name());
 5645
 5646        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5647        let completion_settings = language_settings.completions.clone();
 5648
 5649        let show_completions_on_input = self
 5650            .show_completions_on_input_override
 5651            .unwrap_or(language_settings.show_completions_on_input);
 5652        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5653            return;
 5654        }
 5655
 5656        let query: Option<Arc<String>> =
 5657            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5658                .map(|query| query.into());
 5659
 5660        drop(multibuffer_snapshot);
 5661
 5662        // Hide the current completions menu when query is empty. Without this, cached
 5663        // completions from before the trigger char may be reused (#32774).
 5664        if query.is_none() && menu_is_open {
 5665            self.hide_context_menu(window, cx);
 5666        }
 5667
 5668        let mut ignore_word_threshold = false;
 5669        let provider = match requested_source {
 5670            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5671            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5672                ignore_word_threshold = ignore_threshold;
 5673                None
 5674            }
 5675            Some(CompletionsMenuSource::SnippetChoices)
 5676            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5677                log::error!("bug: SnippetChoices requested_source is not handled");
 5678                None
 5679            }
 5680        };
 5681
 5682        let sort_completions = provider
 5683            .as_ref()
 5684            .is_some_and(|provider| provider.sort_completions());
 5685
 5686        let filter_completions = provider
 5687            .as_ref()
 5688            .is_none_or(|provider| provider.filter_completions());
 5689
 5690        let was_snippets_only = matches!(
 5691            completions_source,
 5692            Some(CompletionsMenuSource::SnippetsOnly)
 5693        );
 5694
 5695        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5696            if filter_completions {
 5697                menu.filter(
 5698                    query.clone().unwrap_or_default(),
 5699                    buffer_position.text_anchor,
 5700                    &buffer,
 5701                    provider.clone(),
 5702                    window,
 5703                    cx,
 5704                );
 5705            }
 5706            // When `is_incomplete` is false, no need to re-query completions when the current query
 5707            // is a suffix of the initial query.
 5708            let was_complete = !menu.is_incomplete;
 5709            if was_complete && !was_snippets_only {
 5710                // If the new query is a suffix of the old query (typing more characters) and
 5711                // the previous result was complete, the existing completions can be filtered.
 5712                //
 5713                // Note that snippet completions are always complete.
 5714                let query_matches = match (&menu.initial_query, &query) {
 5715                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5716                    (None, _) => true,
 5717                    _ => false,
 5718                };
 5719                if query_matches {
 5720                    let position_matches = if menu.initial_position == position {
 5721                        true
 5722                    } else {
 5723                        let snapshot = self.buffer.read(cx).read(cx);
 5724                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5725                    };
 5726                    if position_matches {
 5727                        return;
 5728                    }
 5729                }
 5730            }
 5731        };
 5732
 5733        let Anchor {
 5734            excerpt_id: buffer_excerpt_id,
 5735            text_anchor: buffer_position,
 5736            ..
 5737        } = buffer_position;
 5738
 5739        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5740            buffer_snapshot.surrounding_word(buffer_position, None)
 5741        {
 5742            let word_to_exclude = buffer_snapshot
 5743                .text_for_range(word_range.clone())
 5744                .collect::<String>();
 5745            (
 5746                buffer_snapshot.anchor_before(word_range.start)
 5747                    ..buffer_snapshot.anchor_after(buffer_position),
 5748                Some(word_to_exclude),
 5749            )
 5750        } else {
 5751            (buffer_position..buffer_position, None)
 5752        };
 5753
 5754        let show_completion_documentation = buffer_snapshot
 5755            .settings_at(buffer_position, cx)
 5756            .show_completion_documentation;
 5757
 5758        // The document can be large, so stay in reasonable bounds when searching for words,
 5759        // otherwise completion pop-up might be slow to appear.
 5760        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5761        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5762        let min_word_search = buffer_snapshot.clip_point(
 5763            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5764            Bias::Left,
 5765        );
 5766        let max_word_search = buffer_snapshot.clip_point(
 5767            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5768            Bias::Right,
 5769        );
 5770        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5771            ..buffer_snapshot.point_to_offset(max_word_search);
 5772
 5773        let skip_digits = query
 5774            .as_ref()
 5775            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5776
 5777        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5778            trigger.as_ref().is_none_or(|trigger| {
 5779                provider.is_completion_trigger(
 5780                    &buffer,
 5781                    position.text_anchor,
 5782                    trigger,
 5783                    trigger_in_words,
 5784                    cx,
 5785                )
 5786            })
 5787        });
 5788
 5789        let provider_responses = if let Some(provider) = &provider
 5790            && load_provider_completions
 5791        {
 5792            let trigger_character =
 5793                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5794            let completion_context = CompletionContext {
 5795                trigger_kind: match &trigger_character {
 5796                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5797                    None => CompletionTriggerKind::INVOKED,
 5798                },
 5799                trigger_character,
 5800            };
 5801
 5802            provider.completions(
 5803                buffer_excerpt_id,
 5804                &buffer,
 5805                buffer_position,
 5806                completion_context,
 5807                window,
 5808                cx,
 5809            )
 5810        } else {
 5811            Task::ready(Ok(Vec::new()))
 5812        };
 5813
 5814        let load_word_completions = if !self.word_completions_enabled {
 5815            false
 5816        } else if requested_source
 5817            == Some(CompletionsMenuSource::Words {
 5818                ignore_threshold: true,
 5819            })
 5820        {
 5821            true
 5822        } else {
 5823            load_provider_completions
 5824                && completion_settings.words != WordsCompletionMode::Disabled
 5825                && (ignore_word_threshold || {
 5826                    let words_min_length = completion_settings.words_min_length;
 5827                    // check whether word has at least `words_min_length` characters
 5828                    let query_chars = query.iter().flat_map(|q| q.chars());
 5829                    query_chars.take(words_min_length).count() == words_min_length
 5830                })
 5831        };
 5832
 5833        let mut words = if load_word_completions {
 5834            cx.background_spawn({
 5835                let buffer_snapshot = buffer_snapshot.clone();
 5836                async move {
 5837                    buffer_snapshot.words_in_range(WordsQuery {
 5838                        fuzzy_contents: None,
 5839                        range: word_search_range,
 5840                        skip_digits,
 5841                    })
 5842                }
 5843            })
 5844        } else {
 5845            Task::ready(BTreeMap::default())
 5846        };
 5847
 5848        let snippets = if let Some(provider) = &provider
 5849            && provider.show_snippets()
 5850            && let Some(project) = self.project()
 5851        {
 5852            let char_classifier = buffer_snapshot
 5853                .char_classifier_at(buffer_position)
 5854                .scope_context(Some(CharScopeContext::Completion));
 5855            project.update(cx, |project, cx| {
 5856                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5857            })
 5858        } else {
 5859            Task::ready(Ok(CompletionResponse {
 5860                completions: Vec::new(),
 5861                display_options: Default::default(),
 5862                is_incomplete: false,
 5863            }))
 5864        };
 5865
 5866        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5867
 5868        let id = post_inc(&mut self.next_completion_id);
 5869        let task = cx.spawn_in(window, async move |editor, cx| {
 5870            let Ok(()) = editor.update(cx, |this, _| {
 5871                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5872            }) else {
 5873                return;
 5874            };
 5875
 5876            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5877            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5878            let mut completions = Vec::new();
 5879            let mut is_incomplete = false;
 5880            let mut display_options: Option<CompletionDisplayOptions> = None;
 5881            if let Some(provider_responses) = provider_responses.await.log_err()
 5882                && !provider_responses.is_empty()
 5883            {
 5884                for response in provider_responses {
 5885                    completions.extend(response.completions);
 5886                    is_incomplete = is_incomplete || response.is_incomplete;
 5887                    match display_options.as_mut() {
 5888                        None => {
 5889                            display_options = Some(response.display_options);
 5890                        }
 5891                        Some(options) => options.merge(&response.display_options),
 5892                    }
 5893                }
 5894                if completion_settings.words == WordsCompletionMode::Fallback {
 5895                    words = Task::ready(BTreeMap::default());
 5896                }
 5897            }
 5898            let display_options = display_options.unwrap_or_default();
 5899
 5900            let mut words = words.await;
 5901            if let Some(word_to_exclude) = &word_to_exclude {
 5902                words.remove(word_to_exclude);
 5903            }
 5904            for lsp_completion in &completions {
 5905                words.remove(&lsp_completion.new_text);
 5906            }
 5907            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5908                replace_range: word_replace_range.clone(),
 5909                new_text: word.clone(),
 5910                label: CodeLabel::plain(word, None),
 5911                match_start: None,
 5912                snippet_deduplication_key: None,
 5913                icon_path: None,
 5914                documentation: None,
 5915                source: CompletionSource::BufferWord {
 5916                    word_range,
 5917                    resolved: false,
 5918                },
 5919                insert_text_mode: Some(InsertTextMode::AS_IS),
 5920                confirm: None,
 5921            }));
 5922
 5923            completions.extend(
 5924                snippets
 5925                    .await
 5926                    .into_iter()
 5927                    .flat_map(|response| response.completions),
 5928            );
 5929
 5930            let menu = if completions.is_empty() {
 5931                None
 5932            } else {
 5933                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5934                    let languages = editor
 5935                        .workspace
 5936                        .as_ref()
 5937                        .and_then(|(workspace, _)| workspace.upgrade())
 5938                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5939                    let menu = CompletionsMenu::new(
 5940                        id,
 5941                        requested_source.unwrap_or(if load_provider_completions {
 5942                            CompletionsMenuSource::Normal
 5943                        } else {
 5944                            CompletionsMenuSource::SnippetsOnly
 5945                        }),
 5946                        sort_completions,
 5947                        show_completion_documentation,
 5948                        position,
 5949                        query.clone(),
 5950                        is_incomplete,
 5951                        buffer.clone(),
 5952                        completions.into(),
 5953                        editor
 5954                            .context_menu()
 5955                            .borrow_mut()
 5956                            .as_ref()
 5957                            .map(|menu| menu.primary_scroll_handle()),
 5958                        display_options,
 5959                        snippet_sort_order,
 5960                        languages,
 5961                        language,
 5962                        cx,
 5963                    );
 5964
 5965                    let query = if filter_completions { query } else { None };
 5966                    let matches_task = menu.do_async_filtering(
 5967                        query.unwrap_or_default(),
 5968                        buffer_position,
 5969                        &buffer,
 5970                        cx,
 5971                    );
 5972                    (menu, matches_task)
 5973                }) else {
 5974                    return;
 5975                };
 5976
 5977                let matches = matches_task.await;
 5978
 5979                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5980                    // Newer menu already set, so exit.
 5981                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5982                        editor.context_menu.borrow().as_ref()
 5983                        && prev_menu.id > id
 5984                    {
 5985                        return;
 5986                    };
 5987
 5988                    // Only valid to take prev_menu because either the new menu is immediately set
 5989                    // below, or the menu is hidden.
 5990                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5991                        editor.context_menu.borrow_mut().take()
 5992                    {
 5993                        let position_matches =
 5994                            if prev_menu.initial_position == menu.initial_position {
 5995                                true
 5996                            } else {
 5997                                let snapshot = editor.buffer.read(cx).read(cx);
 5998                                prev_menu.initial_position.to_offset(&snapshot)
 5999                                    == menu.initial_position.to_offset(&snapshot)
 6000                            };
 6001                        if position_matches {
 6002                            // Preserve markdown cache before `set_filter_results` because it will
 6003                            // try to populate the documentation cache.
 6004                            menu.preserve_markdown_cache(prev_menu);
 6005                        }
 6006                    };
 6007
 6008                    menu.set_filter_results(matches, provider, window, cx);
 6009                }) else {
 6010                    return;
 6011                };
 6012
 6013                menu.visible().then_some(menu)
 6014            };
 6015
 6016            editor
 6017                .update_in(cx, |editor, window, cx| {
 6018                    if editor.focus_handle.is_focused(window)
 6019                        && let Some(menu) = menu
 6020                    {
 6021                        *editor.context_menu.borrow_mut() =
 6022                            Some(CodeContextMenu::Completions(menu));
 6023
 6024                        crate::hover_popover::hide_hover(editor, cx);
 6025                        if editor.show_edit_predictions_in_menu() {
 6026                            editor.update_visible_edit_prediction(window, cx);
 6027                        } else {
 6028                            editor.discard_edit_prediction(false, cx);
 6029                        }
 6030
 6031                        cx.notify();
 6032                        return;
 6033                    }
 6034
 6035                    if editor.completion_tasks.len() <= 1 {
 6036                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6037                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6038                        // If it was already hidden and we don't show edit predictions in the menu,
 6039                        // we should also show the edit prediction when available.
 6040                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6041                            editor.update_visible_edit_prediction(window, cx);
 6042                        }
 6043                    }
 6044                })
 6045                .ok();
 6046        });
 6047
 6048        self.completion_tasks.push((id, task));
 6049    }
 6050
 6051    #[cfg(feature = "test-support")]
 6052    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6053        let menu = self.context_menu.borrow();
 6054        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6055            let completions = menu.completions.borrow();
 6056            Some(completions.to_vec())
 6057        } else {
 6058            None
 6059        }
 6060    }
 6061
 6062    pub fn with_completions_menu_matching_id<R>(
 6063        &self,
 6064        id: CompletionId,
 6065        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6066    ) -> R {
 6067        let mut context_menu = self.context_menu.borrow_mut();
 6068        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6069            return f(None);
 6070        };
 6071        if completions_menu.id != id {
 6072            return f(None);
 6073        }
 6074        f(Some(completions_menu))
 6075    }
 6076
 6077    pub fn confirm_completion(
 6078        &mut self,
 6079        action: &ConfirmCompletion,
 6080        window: &mut Window,
 6081        cx: &mut Context<Self>,
 6082    ) -> Option<Task<Result<()>>> {
 6083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6084        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6085    }
 6086
 6087    pub fn confirm_completion_insert(
 6088        &mut self,
 6089        _: &ConfirmCompletionInsert,
 6090        window: &mut Window,
 6091        cx: &mut Context<Self>,
 6092    ) -> Option<Task<Result<()>>> {
 6093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6094        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6095    }
 6096
 6097    pub fn confirm_completion_replace(
 6098        &mut self,
 6099        _: &ConfirmCompletionReplace,
 6100        window: &mut Window,
 6101        cx: &mut Context<Self>,
 6102    ) -> Option<Task<Result<()>>> {
 6103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6104        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6105    }
 6106
 6107    pub fn compose_completion(
 6108        &mut self,
 6109        action: &ComposeCompletion,
 6110        window: &mut Window,
 6111        cx: &mut Context<Self>,
 6112    ) -> Option<Task<Result<()>>> {
 6113        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6114        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6115    }
 6116
 6117    fn do_completion(
 6118        &mut self,
 6119        item_ix: Option<usize>,
 6120        intent: CompletionIntent,
 6121        window: &mut Window,
 6122        cx: &mut Context<Editor>,
 6123    ) -> Option<Task<Result<()>>> {
 6124        use language::ToOffset as _;
 6125
 6126        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6127        else {
 6128            return None;
 6129        };
 6130
 6131        let candidate_id = {
 6132            let entries = completions_menu.entries.borrow();
 6133            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6134            if self.show_edit_predictions_in_menu() {
 6135                self.discard_edit_prediction(true, cx);
 6136            }
 6137            mat.candidate_id
 6138        };
 6139
 6140        let completion = completions_menu
 6141            .completions
 6142            .borrow()
 6143            .get(candidate_id)?
 6144            .clone();
 6145        cx.stop_propagation();
 6146
 6147        let buffer_handle = completions_menu.buffer.clone();
 6148
 6149        let CompletionEdit {
 6150            new_text,
 6151            snippet,
 6152            replace_range,
 6153        } = process_completion_for_edit(
 6154            &completion,
 6155            intent,
 6156            &buffer_handle,
 6157            &completions_menu.initial_position.text_anchor,
 6158            cx,
 6159        );
 6160
 6161        let buffer = buffer_handle.read(cx);
 6162        let snapshot = self.buffer.read(cx).snapshot(cx);
 6163        let newest_anchor = self.selections.newest_anchor();
 6164        let replace_range_multibuffer = {
 6165            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6166            excerpt.map_range_from_buffer(replace_range.clone())
 6167        };
 6168        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6169            return None;
 6170        }
 6171
 6172        let old_text = buffer
 6173            .text_for_range(replace_range.clone())
 6174            .collect::<String>();
 6175        let lookbehind = newest_anchor
 6176            .start
 6177            .text_anchor
 6178            .to_offset(buffer)
 6179            .saturating_sub(replace_range.start.0);
 6180        let lookahead = replace_range
 6181            .end
 6182            .0
 6183            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6184        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6185        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6186
 6187        let selections = self
 6188            .selections
 6189            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6190        let mut ranges = Vec::new();
 6191        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6192
 6193        for selection in &selections {
 6194            let range = if selection.id == newest_anchor.id {
 6195                replace_range_multibuffer.clone()
 6196            } else {
 6197                let mut range = selection.range();
 6198
 6199                // if prefix is present, don't duplicate it
 6200                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6201                    range.start = range.start.saturating_sub_usize(lookbehind);
 6202
 6203                    // if suffix is also present, mimic the newest cursor and replace it
 6204                    if selection.id != newest_anchor.id
 6205                        && snapshot.contains_str_at(range.end, suffix)
 6206                    {
 6207                        range.end += lookahead;
 6208                    }
 6209                }
 6210                range
 6211            };
 6212
 6213            ranges.push(range.clone());
 6214
 6215            if !self.linked_edit_ranges.is_empty() {
 6216                let start_anchor = snapshot.anchor_before(range.start);
 6217                let end_anchor = snapshot.anchor_after(range.end);
 6218                if let Some(ranges) = self
 6219                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6220                {
 6221                    for (buffer, edits) in ranges {
 6222                        linked_edits
 6223                            .entry(buffer.clone())
 6224                            .or_default()
 6225                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6226                    }
 6227                }
 6228            }
 6229        }
 6230
 6231        let common_prefix_len = old_text
 6232            .chars()
 6233            .zip(new_text.chars())
 6234            .take_while(|(a, b)| a == b)
 6235            .map(|(a, _)| a.len_utf8())
 6236            .sum::<usize>();
 6237
 6238        cx.emit(EditorEvent::InputHandled {
 6239            utf16_range_to_replace: None,
 6240            text: new_text[common_prefix_len..].into(),
 6241        });
 6242
 6243        self.transact(window, cx, |editor, window, cx| {
 6244            if let Some(mut snippet) = snippet {
 6245                snippet.text = new_text.to_string();
 6246                editor
 6247                    .insert_snippet(&ranges, snippet, window, cx)
 6248                    .log_err();
 6249            } else {
 6250                editor.buffer.update(cx, |multi_buffer, cx| {
 6251                    let auto_indent = match completion.insert_text_mode {
 6252                        Some(InsertTextMode::AS_IS) => None,
 6253                        _ => editor.autoindent_mode.clone(),
 6254                    };
 6255                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6256                    multi_buffer.edit(edits, auto_indent, cx);
 6257                });
 6258            }
 6259            for (buffer, edits) in linked_edits {
 6260                buffer.update(cx, |buffer, cx| {
 6261                    let snapshot = buffer.snapshot();
 6262                    let edits = edits
 6263                        .into_iter()
 6264                        .map(|(range, text)| {
 6265                            use text::ToPoint as TP;
 6266                            let end_point = TP::to_point(&range.end, &snapshot);
 6267                            let start_point = TP::to_point(&range.start, &snapshot);
 6268                            (start_point..end_point, text)
 6269                        })
 6270                        .sorted_by_key(|(range, _)| range.start);
 6271                    buffer.edit(edits, None, cx);
 6272                })
 6273            }
 6274
 6275            editor.refresh_edit_prediction(true, false, window, cx);
 6276        });
 6277        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6278
 6279        let show_new_completions_on_confirm = completion
 6280            .confirm
 6281            .as_ref()
 6282            .is_some_and(|confirm| confirm(intent, window, cx));
 6283        if show_new_completions_on_confirm {
 6284            self.open_or_update_completions_menu(None, None, false, window, cx);
 6285        }
 6286
 6287        let provider = self.completion_provider.as_ref()?;
 6288
 6289        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6290        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6291            let CompletionSource::Lsp {
 6292                lsp_completion,
 6293                server_id,
 6294                ..
 6295            } = &completion.source
 6296            else {
 6297                return None;
 6298            };
 6299            let lsp_command = lsp_completion.command.as_ref()?;
 6300            let available_commands = lsp_store
 6301                .read(cx)
 6302                .lsp_server_capabilities
 6303                .get(server_id)
 6304                .and_then(|server_capabilities| {
 6305                    server_capabilities
 6306                        .execute_command_provider
 6307                        .as_ref()
 6308                        .map(|options| options.commands.as_slice())
 6309                })?;
 6310            if available_commands.contains(&lsp_command.command) {
 6311                Some(CodeAction {
 6312                    server_id: *server_id,
 6313                    range: language::Anchor::MIN..language::Anchor::MIN,
 6314                    lsp_action: LspAction::Command(lsp_command.clone()),
 6315                    resolved: false,
 6316                })
 6317            } else {
 6318                None
 6319            }
 6320        });
 6321
 6322        drop(completion);
 6323        let apply_edits = provider.apply_additional_edits_for_completion(
 6324            buffer_handle.clone(),
 6325            completions_menu.completions.clone(),
 6326            candidate_id,
 6327            true,
 6328            cx,
 6329        );
 6330
 6331        let editor_settings = EditorSettings::get_global(cx);
 6332        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6333            // After the code completion is finished, users often want to know what signatures are needed.
 6334            // so we should automatically call signature_help
 6335            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6336        }
 6337
 6338        Some(cx.spawn_in(window, async move |editor, cx| {
 6339            apply_edits.await?;
 6340
 6341            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6342                let title = command.lsp_action.title().to_owned();
 6343                let project_transaction = lsp_store
 6344                    .update(cx, |lsp_store, cx| {
 6345                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6346                    })
 6347                    .await
 6348                    .context("applying post-completion command")?;
 6349                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6350                    Self::open_project_transaction(
 6351                        &editor,
 6352                        workspace.downgrade(),
 6353                        project_transaction,
 6354                        title,
 6355                        cx,
 6356                    )
 6357                    .await?;
 6358                }
 6359            }
 6360
 6361            Ok(())
 6362        }))
 6363    }
 6364
 6365    pub fn toggle_code_actions(
 6366        &mut self,
 6367        action: &ToggleCodeActions,
 6368        window: &mut Window,
 6369        cx: &mut Context<Self>,
 6370    ) {
 6371        let quick_launch = action.quick_launch;
 6372        let mut context_menu = self.context_menu.borrow_mut();
 6373        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6374            if code_actions.deployed_from == action.deployed_from {
 6375                // Toggle if we're selecting the same one
 6376                *context_menu = None;
 6377                cx.notify();
 6378                return;
 6379            } else {
 6380                // Otherwise, clear it and start a new one
 6381                *context_menu = None;
 6382                cx.notify();
 6383            }
 6384        }
 6385        drop(context_menu);
 6386        let snapshot = self.snapshot(window, cx);
 6387        let deployed_from = action.deployed_from.clone();
 6388        let action = action.clone();
 6389        self.completion_tasks.clear();
 6390        self.discard_edit_prediction(false, cx);
 6391
 6392        let multibuffer_point = match &action.deployed_from {
 6393            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6394                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6395            }
 6396            _ => self
 6397                .selections
 6398                .newest::<Point>(&snapshot.display_snapshot)
 6399                .head(),
 6400        };
 6401        let Some((buffer, buffer_row)) = snapshot
 6402            .buffer_snapshot()
 6403            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6404            .and_then(|(buffer_snapshot, range)| {
 6405                self.buffer()
 6406                    .read(cx)
 6407                    .buffer(buffer_snapshot.remote_id())
 6408                    .map(|buffer| (buffer, range.start.row))
 6409            })
 6410        else {
 6411            return;
 6412        };
 6413        let buffer_id = buffer.read(cx).remote_id();
 6414        let tasks = self
 6415            .tasks
 6416            .get(&(buffer_id, buffer_row))
 6417            .map(|t| Arc::new(t.to_owned()));
 6418
 6419        if !self.focus_handle.is_focused(window) {
 6420            return;
 6421        }
 6422        let project = self.project.clone();
 6423
 6424        let code_actions_task = match deployed_from {
 6425            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6426            _ => self.code_actions(buffer_row, window, cx),
 6427        };
 6428
 6429        let runnable_task = match deployed_from {
 6430            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6431            _ => {
 6432                let mut task_context_task = Task::ready(None);
 6433                if let Some(tasks) = &tasks
 6434                    && let Some(project) = project
 6435                {
 6436                    task_context_task =
 6437                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6438                }
 6439
 6440                cx.spawn_in(window, {
 6441                    let buffer = buffer.clone();
 6442                    async move |editor, cx| {
 6443                        let task_context = task_context_task.await;
 6444
 6445                        let resolved_tasks =
 6446                            tasks
 6447                                .zip(task_context.clone())
 6448                                .map(|(tasks, task_context)| ResolvedTasks {
 6449                                    templates: tasks.resolve(&task_context).collect(),
 6450                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6451                                        multibuffer_point.row,
 6452                                        tasks.column,
 6453                                    )),
 6454                                });
 6455                        let debug_scenarios = editor
 6456                            .update(cx, |editor, cx| {
 6457                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6458                            })?
 6459                            .await;
 6460                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6461                    }
 6462                })
 6463            }
 6464        };
 6465
 6466        cx.spawn_in(window, async move |editor, cx| {
 6467            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6468            let code_actions = code_actions_task.await;
 6469            let spawn_straight_away = quick_launch
 6470                && resolved_tasks
 6471                    .as_ref()
 6472                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6473                && code_actions
 6474                    .as_ref()
 6475                    .is_none_or(|actions| actions.is_empty())
 6476                && debug_scenarios.is_empty();
 6477
 6478            editor.update_in(cx, |editor, window, cx| {
 6479                crate::hover_popover::hide_hover(editor, cx);
 6480                let actions = CodeActionContents::new(
 6481                    resolved_tasks,
 6482                    code_actions,
 6483                    debug_scenarios,
 6484                    task_context.unwrap_or_default(),
 6485                );
 6486
 6487                // Don't show the menu if there are no actions available
 6488                if actions.is_empty() {
 6489                    cx.notify();
 6490                    return Task::ready(Ok(()));
 6491                }
 6492
 6493                *editor.context_menu.borrow_mut() =
 6494                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6495                        buffer,
 6496                        actions,
 6497                        selected_item: Default::default(),
 6498                        scroll_handle: UniformListScrollHandle::default(),
 6499                        deployed_from,
 6500                    }));
 6501                cx.notify();
 6502                if spawn_straight_away
 6503                    && let Some(task) = editor.confirm_code_action(
 6504                        &ConfirmCodeAction { item_ix: Some(0) },
 6505                        window,
 6506                        cx,
 6507                    )
 6508                {
 6509                    return task;
 6510                }
 6511
 6512                Task::ready(Ok(()))
 6513            })
 6514        })
 6515        .detach_and_log_err(cx);
 6516    }
 6517
 6518    fn debug_scenarios(
 6519        &mut self,
 6520        resolved_tasks: &Option<ResolvedTasks>,
 6521        buffer: &Entity<Buffer>,
 6522        cx: &mut App,
 6523    ) -> Task<Vec<task::DebugScenario>> {
 6524        maybe!({
 6525            let project = self.project()?;
 6526            let dap_store = project.read(cx).dap_store();
 6527            let mut scenarios = vec![];
 6528            let resolved_tasks = resolved_tasks.as_ref()?;
 6529            let buffer = buffer.read(cx);
 6530            let language = buffer.language()?;
 6531            let file = buffer.file();
 6532            let debug_adapter = language_settings(language.name().into(), file, cx)
 6533                .debuggers
 6534                .first()
 6535                .map(SharedString::from)
 6536                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6537
 6538            dap_store.update(cx, |dap_store, cx| {
 6539                for (_, task) in &resolved_tasks.templates {
 6540                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6541                        task.original_task().clone(),
 6542                        debug_adapter.clone().into(),
 6543                        task.display_label().to_owned().into(),
 6544                        cx,
 6545                    );
 6546                    scenarios.push(maybe_scenario);
 6547                }
 6548            });
 6549            Some(cx.background_spawn(async move {
 6550                futures::future::join_all(scenarios)
 6551                    .await
 6552                    .into_iter()
 6553                    .flatten()
 6554                    .collect::<Vec<_>>()
 6555            }))
 6556        })
 6557        .unwrap_or_else(|| Task::ready(vec![]))
 6558    }
 6559
 6560    fn code_actions(
 6561        &mut self,
 6562        buffer_row: u32,
 6563        window: &mut Window,
 6564        cx: &mut Context<Self>,
 6565    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6566        let mut task = self.code_actions_task.take();
 6567        cx.spawn_in(window, async move |editor, cx| {
 6568            while let Some(prev_task) = task {
 6569                prev_task.await.log_err();
 6570                task = editor
 6571                    .update(cx, |this, _| this.code_actions_task.take())
 6572                    .ok()?;
 6573            }
 6574
 6575            editor
 6576                .update(cx, |editor, cx| {
 6577                    editor
 6578                        .available_code_actions
 6579                        .clone()
 6580                        .and_then(|(location, code_actions)| {
 6581                            let snapshot = location.buffer.read(cx).snapshot();
 6582                            let point_range = location.range.to_point(&snapshot);
 6583                            let point_range = point_range.start.row..=point_range.end.row;
 6584                            if point_range.contains(&buffer_row) {
 6585                                Some(code_actions)
 6586                            } else {
 6587                                None
 6588                            }
 6589                        })
 6590                })
 6591                .ok()
 6592                .flatten()
 6593        })
 6594    }
 6595
 6596    pub fn confirm_code_action(
 6597        &mut self,
 6598        action: &ConfirmCodeAction,
 6599        window: &mut Window,
 6600        cx: &mut Context<Self>,
 6601    ) -> Option<Task<Result<()>>> {
 6602        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6603
 6604        let actions_menu =
 6605            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6606                menu
 6607            } else {
 6608                return None;
 6609            };
 6610
 6611        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6612        let action = actions_menu.actions.get(action_ix)?;
 6613        let title = action.label();
 6614        let buffer = actions_menu.buffer;
 6615        let workspace = self.workspace()?;
 6616
 6617        match action {
 6618            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6619                workspace.update(cx, |workspace, cx| {
 6620                    workspace.schedule_resolved_task(
 6621                        task_source_kind,
 6622                        resolved_task,
 6623                        false,
 6624                        window,
 6625                        cx,
 6626                    );
 6627
 6628                    Some(Task::ready(Ok(())))
 6629                })
 6630            }
 6631            CodeActionsItem::CodeAction {
 6632                excerpt_id,
 6633                action,
 6634                provider,
 6635            } => {
 6636                let apply_code_action =
 6637                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6638                let workspace = workspace.downgrade();
 6639                Some(cx.spawn_in(window, async move |editor, cx| {
 6640                    let project_transaction = apply_code_action.await?;
 6641                    Self::open_project_transaction(
 6642                        &editor,
 6643                        workspace,
 6644                        project_transaction,
 6645                        title,
 6646                        cx,
 6647                    )
 6648                    .await
 6649                }))
 6650            }
 6651            CodeActionsItem::DebugScenario(scenario) => {
 6652                let context = actions_menu.actions.context;
 6653
 6654                workspace.update(cx, |workspace, cx| {
 6655                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6656                    workspace.start_debug_session(
 6657                        scenario,
 6658                        context,
 6659                        Some(buffer),
 6660                        None,
 6661                        window,
 6662                        cx,
 6663                    );
 6664                });
 6665                Some(Task::ready(Ok(())))
 6666            }
 6667        }
 6668    }
 6669
 6670    fn open_transaction_for_hidden_buffers(
 6671        workspace: Entity<Workspace>,
 6672        transaction: ProjectTransaction,
 6673        title: String,
 6674        window: &mut Window,
 6675        cx: &mut Context<Self>,
 6676    ) {
 6677        if transaction.0.is_empty() {
 6678            return;
 6679        }
 6680
 6681        let edited_buffers_already_open = {
 6682            let other_editors: Vec<Entity<Editor>> = workspace
 6683                .read(cx)
 6684                .panes()
 6685                .iter()
 6686                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6687                .filter(|editor| editor.entity_id() != cx.entity_id())
 6688                .collect();
 6689
 6690            transaction.0.keys().all(|buffer| {
 6691                other_editors.iter().any(|editor| {
 6692                    let multi_buffer = editor.read(cx).buffer();
 6693                    multi_buffer.read(cx).is_singleton()
 6694                        && multi_buffer
 6695                            .read(cx)
 6696                            .as_singleton()
 6697                            .map_or(false, |singleton| {
 6698                                singleton.entity_id() == buffer.entity_id()
 6699                            })
 6700                })
 6701            })
 6702        };
 6703        if !edited_buffers_already_open {
 6704            let workspace = workspace.downgrade();
 6705            cx.defer_in(window, move |_, window, cx| {
 6706                cx.spawn_in(window, async move |editor, cx| {
 6707                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6708                        .await
 6709                        .ok()
 6710                })
 6711                .detach();
 6712            });
 6713        }
 6714    }
 6715
 6716    pub async fn open_project_transaction(
 6717        editor: &WeakEntity<Editor>,
 6718        workspace: WeakEntity<Workspace>,
 6719        transaction: ProjectTransaction,
 6720        title: String,
 6721        cx: &mut AsyncWindowContext,
 6722    ) -> Result<()> {
 6723        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6724        cx.update(|_, cx| {
 6725            entries.sort_unstable_by_key(|(buffer, _)| {
 6726                buffer.read(cx).file().map(|f| f.path().clone())
 6727            });
 6728        })?;
 6729        if entries.is_empty() {
 6730            return Ok(());
 6731        }
 6732
 6733        // If the project transaction's edits are all contained within this editor, then
 6734        // avoid opening a new editor to display them.
 6735
 6736        if let [(buffer, transaction)] = &*entries {
 6737            let excerpt = editor.update(cx, |editor, cx| {
 6738                editor
 6739                    .buffer()
 6740                    .read(cx)
 6741                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6742            })?;
 6743            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6744                && excerpted_buffer == *buffer
 6745            {
 6746                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6747                    let excerpt_range = excerpt_range.to_offset(buffer);
 6748                    buffer
 6749                        .edited_ranges_for_transaction::<usize>(transaction)
 6750                        .all(|range| {
 6751                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6752                        })
 6753                });
 6754
 6755                if all_edits_within_excerpt {
 6756                    return Ok(());
 6757                }
 6758            }
 6759        }
 6760
 6761        let mut ranges_to_highlight = Vec::new();
 6762        let excerpt_buffer = cx.new(|cx| {
 6763            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6764            for (buffer_handle, transaction) in &entries {
 6765                let edited_ranges = buffer_handle
 6766                    .read(cx)
 6767                    .edited_ranges_for_transaction::<Point>(transaction)
 6768                    .collect::<Vec<_>>();
 6769                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6770                    PathKey::for_buffer(buffer_handle, cx),
 6771                    buffer_handle.clone(),
 6772                    edited_ranges,
 6773                    multibuffer_context_lines(cx),
 6774                    cx,
 6775                );
 6776
 6777                ranges_to_highlight.extend(ranges);
 6778            }
 6779            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6780            multibuffer
 6781        });
 6782
 6783        workspace.update_in(cx, |workspace, window, cx| {
 6784            let project = workspace.project().clone();
 6785            let editor =
 6786                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6787            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6788            editor.update(cx, |editor, cx| {
 6789                editor.highlight_background::<Self>(
 6790                    &ranges_to_highlight,
 6791                    |_, theme| theme.colors().editor_highlighted_line_background,
 6792                    cx,
 6793                );
 6794            });
 6795        })?;
 6796
 6797        Ok(())
 6798    }
 6799
 6800    pub fn clear_code_action_providers(&mut self) {
 6801        self.code_action_providers.clear();
 6802        self.available_code_actions.take();
 6803    }
 6804
 6805    pub fn add_code_action_provider(
 6806        &mut self,
 6807        provider: Rc<dyn CodeActionProvider>,
 6808        window: &mut Window,
 6809        cx: &mut Context<Self>,
 6810    ) {
 6811        if self
 6812            .code_action_providers
 6813            .iter()
 6814            .any(|existing_provider| existing_provider.id() == provider.id())
 6815        {
 6816            return;
 6817        }
 6818
 6819        self.code_action_providers.push(provider);
 6820        self.refresh_code_actions(window, cx);
 6821    }
 6822
 6823    pub fn remove_code_action_provider(
 6824        &mut self,
 6825        id: Arc<str>,
 6826        window: &mut Window,
 6827        cx: &mut Context<Self>,
 6828    ) {
 6829        self.code_action_providers
 6830            .retain(|provider| provider.id() != id);
 6831        self.refresh_code_actions(window, cx);
 6832    }
 6833
 6834    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6835        !self.code_action_providers.is_empty()
 6836            && EditorSettings::get_global(cx).toolbar.code_actions
 6837    }
 6838
 6839    pub fn has_available_code_actions(&self) -> bool {
 6840        self.available_code_actions
 6841            .as_ref()
 6842            .is_some_and(|(_, actions)| !actions.is_empty())
 6843    }
 6844
 6845    fn render_inline_code_actions(
 6846        &self,
 6847        icon_size: ui::IconSize,
 6848        display_row: DisplayRow,
 6849        is_active: bool,
 6850        cx: &mut Context<Self>,
 6851    ) -> AnyElement {
 6852        let show_tooltip = !self.context_menu_visible();
 6853        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6854            .icon_size(icon_size)
 6855            .shape(ui::IconButtonShape::Square)
 6856            .icon_color(ui::Color::Hidden)
 6857            .toggle_state(is_active)
 6858            .when(show_tooltip, |this| {
 6859                this.tooltip({
 6860                    let focus_handle = self.focus_handle.clone();
 6861                    move |_window, cx| {
 6862                        Tooltip::for_action_in(
 6863                            "Toggle Code Actions",
 6864                            &ToggleCodeActions {
 6865                                deployed_from: None,
 6866                                quick_launch: false,
 6867                            },
 6868                            &focus_handle,
 6869                            cx,
 6870                        )
 6871                    }
 6872                })
 6873            })
 6874            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6875                window.focus(&editor.focus_handle(cx), cx);
 6876                editor.toggle_code_actions(
 6877                    &crate::actions::ToggleCodeActions {
 6878                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6879                            display_row,
 6880                        )),
 6881                        quick_launch: false,
 6882                    },
 6883                    window,
 6884                    cx,
 6885                );
 6886            }))
 6887            .into_any_element()
 6888    }
 6889
 6890    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6891        &self.context_menu
 6892    }
 6893
 6894    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6895        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6896            cx.background_executor()
 6897                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6898                .await;
 6899
 6900            let (start_buffer, start, _, end, newest_selection) = this
 6901                .update(cx, |this, cx| {
 6902                    let newest_selection = this.selections.newest_anchor().clone();
 6903                    if newest_selection.head().diff_base_anchor.is_some() {
 6904                        return None;
 6905                    }
 6906                    let display_snapshot = this.display_snapshot(cx);
 6907                    let newest_selection_adjusted =
 6908                        this.selections.newest_adjusted(&display_snapshot);
 6909                    let buffer = this.buffer.read(cx);
 6910
 6911                    let (start_buffer, start) =
 6912                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6913                    let (end_buffer, end) =
 6914                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6915
 6916                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6917                })?
 6918                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6919                .context(
 6920                    "Expected selection to lie in a single buffer when refreshing code actions",
 6921                )?;
 6922            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6923                let providers = this.code_action_providers.clone();
 6924                let tasks = this
 6925                    .code_action_providers
 6926                    .iter()
 6927                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6928                    .collect::<Vec<_>>();
 6929                (providers, tasks)
 6930            })?;
 6931
 6932            let mut actions = Vec::new();
 6933            for (provider, provider_actions) in
 6934                providers.into_iter().zip(future::join_all(tasks).await)
 6935            {
 6936                if let Some(provider_actions) = provider_actions.log_err() {
 6937                    actions.extend(provider_actions.into_iter().map(|action| {
 6938                        AvailableCodeAction {
 6939                            excerpt_id: newest_selection.start.excerpt_id,
 6940                            action,
 6941                            provider: provider.clone(),
 6942                        }
 6943                    }));
 6944                }
 6945            }
 6946
 6947            this.update(cx, |this, cx| {
 6948                this.available_code_actions = if actions.is_empty() {
 6949                    None
 6950                } else {
 6951                    Some((
 6952                        Location {
 6953                            buffer: start_buffer,
 6954                            range: start..end,
 6955                        },
 6956                        actions.into(),
 6957                    ))
 6958                };
 6959                cx.notify();
 6960            })
 6961        }));
 6962    }
 6963
 6964    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6965        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6966            self.show_git_blame_inline = false;
 6967
 6968            self.show_git_blame_inline_delay_task =
 6969                Some(cx.spawn_in(window, async move |this, cx| {
 6970                    cx.background_executor().timer(delay).await;
 6971
 6972                    this.update(cx, |this, cx| {
 6973                        this.show_git_blame_inline = true;
 6974                        cx.notify();
 6975                    })
 6976                    .log_err();
 6977                }));
 6978        }
 6979    }
 6980
 6981    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6982        let snapshot = self.snapshot(window, cx);
 6983        let cursor = self
 6984            .selections
 6985            .newest::<Point>(&snapshot.display_snapshot)
 6986            .head();
 6987        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6988        else {
 6989            return;
 6990        };
 6991
 6992        if self.blame.is_none() {
 6993            self.start_git_blame(true, window, cx);
 6994        }
 6995        let Some(blame) = self.blame.as_ref() else {
 6996            return;
 6997        };
 6998
 6999        let row_info = RowInfo {
 7000            buffer_id: Some(buffer.remote_id()),
 7001            buffer_row: Some(point.row),
 7002            ..Default::default()
 7003        };
 7004        let Some((buffer, blame_entry)) = blame
 7005            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7006            .flatten()
 7007        else {
 7008            return;
 7009        };
 7010
 7011        let anchor = self.selections.newest_anchor().head();
 7012        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7013        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7014            self.show_blame_popover(
 7015                buffer,
 7016                &blame_entry,
 7017                position + last_bounds.origin,
 7018                true,
 7019                cx,
 7020            );
 7021        };
 7022    }
 7023
 7024    fn show_blame_popover(
 7025        &mut self,
 7026        buffer: BufferId,
 7027        blame_entry: &BlameEntry,
 7028        position: gpui::Point<Pixels>,
 7029        ignore_timeout: bool,
 7030        cx: &mut Context<Self>,
 7031    ) {
 7032        if let Some(state) = &mut self.inline_blame_popover {
 7033            state.hide_task.take();
 7034        } else {
 7035            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7036            let blame_entry = blame_entry.clone();
 7037            let show_task = cx.spawn(async move |editor, cx| {
 7038                if !ignore_timeout {
 7039                    cx.background_executor()
 7040                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7041                        .await;
 7042                }
 7043                editor
 7044                    .update(cx, |editor, cx| {
 7045                        editor.inline_blame_popover_show_task.take();
 7046                        let Some(blame) = editor.blame.as_ref() else {
 7047                            return;
 7048                        };
 7049                        let blame = blame.read(cx);
 7050                        let details = blame.details_for_entry(buffer, &blame_entry);
 7051                        let markdown = cx.new(|cx| {
 7052                            Markdown::new(
 7053                                details
 7054                                    .as_ref()
 7055                                    .map(|message| message.message.clone())
 7056                                    .unwrap_or_default(),
 7057                                None,
 7058                                None,
 7059                                cx,
 7060                            )
 7061                        });
 7062                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7063                            position,
 7064                            hide_task: None,
 7065                            popover_bounds: None,
 7066                            popover_state: InlineBlamePopoverState {
 7067                                scroll_handle: ScrollHandle::new(),
 7068                                commit_message: details,
 7069                                markdown,
 7070                            },
 7071                            keyboard_grace: ignore_timeout,
 7072                        });
 7073                        cx.notify();
 7074                    })
 7075                    .ok();
 7076            });
 7077            self.inline_blame_popover_show_task = Some(show_task);
 7078        }
 7079    }
 7080
 7081    pub fn has_mouse_context_menu(&self) -> bool {
 7082        self.mouse_context_menu.is_some()
 7083    }
 7084
 7085    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7086        self.inline_blame_popover_show_task.take();
 7087        if let Some(state) = &mut self.inline_blame_popover {
 7088            let hide_task = cx.spawn(async move |editor, cx| {
 7089                if !ignore_timeout {
 7090                    cx.background_executor()
 7091                        .timer(std::time::Duration::from_millis(100))
 7092                        .await;
 7093                }
 7094                editor
 7095                    .update(cx, |editor, cx| {
 7096                        editor.inline_blame_popover.take();
 7097                        cx.notify();
 7098                    })
 7099                    .ok();
 7100            });
 7101            state.hide_task = Some(hide_task);
 7102            true
 7103        } else {
 7104            false
 7105        }
 7106    }
 7107
 7108    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7109        if self.pending_rename.is_some() {
 7110            return None;
 7111        }
 7112
 7113        let provider = self.semantics_provider.clone()?;
 7114        let buffer = self.buffer.read(cx);
 7115        let newest_selection = self.selections.newest_anchor().clone();
 7116        let cursor_position = newest_selection.head();
 7117        let (cursor_buffer, cursor_buffer_position) =
 7118            buffer.text_anchor_for_position(cursor_position, cx)?;
 7119        let (tail_buffer, tail_buffer_position) =
 7120            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7121        if cursor_buffer != tail_buffer {
 7122            return None;
 7123        }
 7124
 7125        let snapshot = cursor_buffer.read(cx).snapshot();
 7126        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7127        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7128        if start_word_range != end_word_range {
 7129            self.document_highlights_task.take();
 7130            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7131            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7132            return None;
 7133        }
 7134
 7135        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7136        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7137            cx.background_executor()
 7138                .timer(Duration::from_millis(debounce))
 7139                .await;
 7140
 7141            let highlights = if let Some(highlights) = cx.update(|cx| {
 7142                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7143            }) {
 7144                highlights.await.log_err()
 7145            } else {
 7146                None
 7147            };
 7148
 7149            if let Some(highlights) = highlights {
 7150                this.update(cx, |this, cx| {
 7151                    if this.pending_rename.is_some() {
 7152                        return;
 7153                    }
 7154
 7155                    let buffer = this.buffer.read(cx);
 7156                    if buffer
 7157                        .text_anchor_for_position(cursor_position, cx)
 7158                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7159                    {
 7160                        return;
 7161                    }
 7162
 7163                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7164                    let mut write_ranges = Vec::new();
 7165                    let mut read_ranges = Vec::new();
 7166                    for highlight in highlights {
 7167                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7168                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7169                        {
 7170                            let start = highlight
 7171                                .range
 7172                                .start
 7173                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7174                            let end = highlight
 7175                                .range
 7176                                .end
 7177                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7178                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7179                                continue;
 7180                            }
 7181
 7182                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7183                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7184                                write_ranges.push(range);
 7185                            } else {
 7186                                read_ranges.push(range);
 7187                            }
 7188                        }
 7189                    }
 7190
 7191                    this.highlight_background::<DocumentHighlightRead>(
 7192                        &read_ranges,
 7193                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7194                        cx,
 7195                    );
 7196                    this.highlight_background::<DocumentHighlightWrite>(
 7197                        &write_ranges,
 7198                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7199                        cx,
 7200                    );
 7201                    cx.notify();
 7202                })
 7203                .log_err();
 7204            }
 7205        }));
 7206        None
 7207    }
 7208
 7209    fn prepare_highlight_query_from_selection(
 7210        &mut self,
 7211        window: &Window,
 7212        cx: &mut Context<Editor>,
 7213    ) -> Option<(String, Range<Anchor>)> {
 7214        if matches!(self.mode, EditorMode::SingleLine) {
 7215            return None;
 7216        }
 7217        if !EditorSettings::get_global(cx).selection_highlight {
 7218            return None;
 7219        }
 7220        if self.selections.count() != 1 || self.selections.line_mode() {
 7221            return None;
 7222        }
 7223        let snapshot = self.snapshot(window, cx);
 7224        let selection = self.selections.newest::<Point>(&snapshot);
 7225        // If the selection spans multiple rows OR it is empty
 7226        if selection.start.row != selection.end.row
 7227            || selection.start.column == selection.end.column
 7228        {
 7229            return None;
 7230        }
 7231        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7232        let query = snapshot
 7233            .buffer_snapshot()
 7234            .text_for_range(selection_anchor_range.clone())
 7235            .collect::<String>();
 7236        if query.trim().is_empty() {
 7237            return None;
 7238        }
 7239        Some((query, selection_anchor_range))
 7240    }
 7241
 7242    #[ztracing::instrument(skip_all)]
 7243    fn update_selection_occurrence_highlights(
 7244        &mut self,
 7245        query_text: String,
 7246        query_range: Range<Anchor>,
 7247        multi_buffer_range_to_query: Range<Point>,
 7248        use_debounce: bool,
 7249        window: &mut Window,
 7250        cx: &mut Context<Editor>,
 7251    ) -> Task<()> {
 7252        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7253        cx.spawn_in(window, async move |editor, cx| {
 7254            if use_debounce {
 7255                cx.background_executor()
 7256                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7257                    .await;
 7258            }
 7259            let match_task = cx.background_spawn(async move {
 7260                let buffer_ranges = multi_buffer_snapshot
 7261                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7262                    .into_iter()
 7263                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7264                let mut match_ranges = Vec::new();
 7265                let Ok(regex) = project::search::SearchQuery::text(
 7266                    query_text.clone(),
 7267                    false,
 7268                    false,
 7269                    false,
 7270                    Default::default(),
 7271                    Default::default(),
 7272                    false,
 7273                    None,
 7274                ) else {
 7275                    return Vec::default();
 7276                };
 7277                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7278                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7279                    match_ranges.extend(
 7280                        regex
 7281                            .search(
 7282                                buffer_snapshot,
 7283                                Some(search_range.start.0..search_range.end.0),
 7284                            )
 7285                            .await
 7286                            .into_iter()
 7287                            .filter_map(|match_range| {
 7288                                let match_start = buffer_snapshot
 7289                                    .anchor_after(search_range.start + match_range.start);
 7290                                let match_end = buffer_snapshot
 7291                                    .anchor_before(search_range.start + match_range.end);
 7292                                let match_anchor_range =
 7293                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7294                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7295                            }),
 7296                    );
 7297                }
 7298                match_ranges
 7299            });
 7300            let match_ranges = match_task.await;
 7301            editor
 7302                .update_in(cx, |editor, _, cx| {
 7303                    if use_debounce {
 7304                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7305                        editor.debounced_selection_highlight_complete = true;
 7306                    } else if editor.debounced_selection_highlight_complete {
 7307                        return;
 7308                    }
 7309                    if !match_ranges.is_empty() {
 7310                        editor.highlight_background::<SelectedTextHighlight>(
 7311                            &match_ranges,
 7312                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7313                            cx,
 7314                        )
 7315                    }
 7316                })
 7317                .log_err();
 7318        })
 7319    }
 7320
 7321    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7322        struct NewlineFold;
 7323        let type_id = std::any::TypeId::of::<NewlineFold>();
 7324        if !self.mode.is_single_line() {
 7325            return;
 7326        }
 7327        let snapshot = self.snapshot(window, cx);
 7328        if snapshot.buffer_snapshot().max_point().row == 0 {
 7329            return;
 7330        }
 7331        let task = cx.background_spawn(async move {
 7332            let new_newlines = snapshot
 7333                .buffer_chars_at(MultiBufferOffset(0))
 7334                .filter_map(|(c, i)| {
 7335                    if c == '\n' {
 7336                        Some(
 7337                            snapshot.buffer_snapshot().anchor_after(i)
 7338                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7339                        )
 7340                    } else {
 7341                        None
 7342                    }
 7343                })
 7344                .collect::<Vec<_>>();
 7345            let existing_newlines = snapshot
 7346                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7347                .filter_map(|fold| {
 7348                    if fold.placeholder.type_tag == Some(type_id) {
 7349                        Some(fold.range.start..fold.range.end)
 7350                    } else {
 7351                        None
 7352                    }
 7353                })
 7354                .collect::<Vec<_>>();
 7355
 7356            (new_newlines, existing_newlines)
 7357        });
 7358        self.folding_newlines = cx.spawn(async move |this, cx| {
 7359            let (new_newlines, existing_newlines) = task.await;
 7360            if new_newlines == existing_newlines {
 7361                return;
 7362            }
 7363            let placeholder = FoldPlaceholder {
 7364                render: Arc::new(move |_, _, cx| {
 7365                    div()
 7366                        .bg(cx.theme().status().hint_background)
 7367                        .border_b_1()
 7368                        .size_full()
 7369                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7370                        .border_color(cx.theme().status().hint)
 7371                        .child("\\n")
 7372                        .into_any()
 7373                }),
 7374                constrain_width: false,
 7375                merge_adjacent: false,
 7376                type_tag: Some(type_id),
 7377            };
 7378            let creases = new_newlines
 7379                .into_iter()
 7380                .map(|range| Crease::simple(range, placeholder.clone()))
 7381                .collect();
 7382            this.update(cx, |this, cx| {
 7383                this.display_map.update(cx, |display_map, cx| {
 7384                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7385                    display_map.fold(creases, cx);
 7386                });
 7387            })
 7388            .ok();
 7389        });
 7390    }
 7391
 7392    #[ztracing::instrument(skip_all)]
 7393    fn refresh_selected_text_highlights(
 7394        &mut self,
 7395        on_buffer_edit: bool,
 7396        window: &mut Window,
 7397        cx: &mut Context<Editor>,
 7398    ) {
 7399        let Some((query_text, query_range)) =
 7400            self.prepare_highlight_query_from_selection(window, cx)
 7401        else {
 7402            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7403            self.quick_selection_highlight_task.take();
 7404            self.debounced_selection_highlight_task.take();
 7405            self.debounced_selection_highlight_complete = false;
 7406            return;
 7407        };
 7408        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7409        let query_changed = self
 7410            .quick_selection_highlight_task
 7411            .as_ref()
 7412            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7413        if query_changed {
 7414            self.debounced_selection_highlight_complete = false;
 7415        }
 7416        if on_buffer_edit || query_changed {
 7417            let multi_buffer_visible_start = self
 7418                .scroll_manager
 7419                .anchor()
 7420                .anchor
 7421                .to_point(&multi_buffer_snapshot);
 7422            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7423                multi_buffer_visible_start
 7424                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7425                Bias::Left,
 7426            );
 7427            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7428            self.quick_selection_highlight_task = Some((
 7429                query_range.clone(),
 7430                self.update_selection_occurrence_highlights(
 7431                    query_text.clone(),
 7432                    query_range.clone(),
 7433                    multi_buffer_visible_range,
 7434                    false,
 7435                    window,
 7436                    cx,
 7437                ),
 7438            ));
 7439        }
 7440        if on_buffer_edit
 7441            || self
 7442                .debounced_selection_highlight_task
 7443                .as_ref()
 7444                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7445        {
 7446            let multi_buffer_start = multi_buffer_snapshot
 7447                .anchor_before(MultiBufferOffset(0))
 7448                .to_point(&multi_buffer_snapshot);
 7449            let multi_buffer_end = multi_buffer_snapshot
 7450                .anchor_after(multi_buffer_snapshot.len())
 7451                .to_point(&multi_buffer_snapshot);
 7452            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7453            self.debounced_selection_highlight_task = Some((
 7454                query_range.clone(),
 7455                self.update_selection_occurrence_highlights(
 7456                    query_text,
 7457                    query_range,
 7458                    multi_buffer_full_range,
 7459                    true,
 7460                    window,
 7461                    cx,
 7462                ),
 7463            ));
 7464        }
 7465    }
 7466
 7467    pub fn refresh_edit_prediction(
 7468        &mut self,
 7469        debounce: bool,
 7470        user_requested: bool,
 7471        window: &mut Window,
 7472        cx: &mut Context<Self>,
 7473    ) -> Option<()> {
 7474        if DisableAiSettings::get_global(cx).disable_ai {
 7475            return None;
 7476        }
 7477
 7478        let provider = self.edit_prediction_provider()?;
 7479        let cursor = self.selections.newest_anchor().head();
 7480        let (buffer, cursor_buffer_position) =
 7481            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7482
 7483        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7484            self.discard_edit_prediction(false, cx);
 7485            return None;
 7486        }
 7487
 7488        self.update_visible_edit_prediction(window, cx);
 7489
 7490        if !user_requested
 7491            && (!self.should_show_edit_predictions()
 7492                || !self.is_focused(window)
 7493                || buffer.read(cx).is_empty())
 7494        {
 7495            self.discard_edit_prediction(false, cx);
 7496            return None;
 7497        }
 7498
 7499        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7500        Some(())
 7501    }
 7502
 7503    fn show_edit_predictions_in_menu(&self) -> bool {
 7504        match self.edit_prediction_settings {
 7505            EditPredictionSettings::Disabled => false,
 7506            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7507        }
 7508    }
 7509
 7510    pub fn edit_predictions_enabled(&self) -> bool {
 7511        match self.edit_prediction_settings {
 7512            EditPredictionSettings::Disabled => false,
 7513            EditPredictionSettings::Enabled { .. } => true,
 7514        }
 7515    }
 7516
 7517    fn edit_prediction_requires_modifier(&self) -> bool {
 7518        match self.edit_prediction_settings {
 7519            EditPredictionSettings::Disabled => false,
 7520            EditPredictionSettings::Enabled {
 7521                preview_requires_modifier,
 7522                ..
 7523            } => preview_requires_modifier,
 7524        }
 7525    }
 7526
 7527    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7528        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7529            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7530            self.discard_edit_prediction(false, cx);
 7531        } else {
 7532            let selection = self.selections.newest_anchor();
 7533            let cursor = selection.head();
 7534
 7535            if let Some((buffer, cursor_buffer_position)) =
 7536                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7537            {
 7538                self.edit_prediction_settings =
 7539                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7540            }
 7541        }
 7542    }
 7543
 7544    fn edit_prediction_settings_at_position(
 7545        &self,
 7546        buffer: &Entity<Buffer>,
 7547        buffer_position: language::Anchor,
 7548        cx: &App,
 7549    ) -> EditPredictionSettings {
 7550        if !self.mode.is_full()
 7551            || !self.show_edit_predictions_override.unwrap_or(true)
 7552            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7553        {
 7554            return EditPredictionSettings::Disabled;
 7555        }
 7556
 7557        let buffer = buffer.read(cx);
 7558
 7559        let file = buffer.file();
 7560
 7561        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7562            return EditPredictionSettings::Disabled;
 7563        };
 7564
 7565        let by_provider = matches!(
 7566            self.menu_edit_predictions_policy,
 7567            MenuEditPredictionsPolicy::ByProvider
 7568        );
 7569
 7570        let show_in_menu = by_provider
 7571            && self
 7572                .edit_prediction_provider
 7573                .as_ref()
 7574                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7575
 7576        let preview_requires_modifier =
 7577            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7578
 7579        EditPredictionSettings::Enabled {
 7580            show_in_menu,
 7581            preview_requires_modifier,
 7582        }
 7583    }
 7584
 7585    fn should_show_edit_predictions(&self) -> bool {
 7586        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7587    }
 7588
 7589    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7590        matches!(
 7591            self.edit_prediction_preview,
 7592            EditPredictionPreview::Active { .. }
 7593        )
 7594    }
 7595
 7596    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7597        let cursor = self.selections.newest_anchor().head();
 7598        if let Some((buffer, cursor_position)) =
 7599            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7600        {
 7601            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7602        } else {
 7603            false
 7604        }
 7605    }
 7606
 7607    pub fn supports_minimap(&self, cx: &App) -> bool {
 7608        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7609    }
 7610
 7611    fn edit_predictions_enabled_in_buffer(
 7612        &self,
 7613        buffer: &Entity<Buffer>,
 7614        buffer_position: language::Anchor,
 7615        cx: &App,
 7616    ) -> bool {
 7617        maybe!({
 7618            if self.read_only(cx) {
 7619                return Some(false);
 7620            }
 7621            let provider = self.edit_prediction_provider()?;
 7622            if !provider.is_enabled(buffer, buffer_position, cx) {
 7623                return Some(false);
 7624            }
 7625            let buffer = buffer.read(cx);
 7626            let Some(file) = buffer.file() else {
 7627                return Some(true);
 7628            };
 7629            let settings = all_language_settings(Some(file), cx);
 7630            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7631        })
 7632        .unwrap_or(false)
 7633    }
 7634
 7635    pub fn show_edit_prediction(
 7636        &mut self,
 7637        _: &ShowEditPrediction,
 7638        window: &mut Window,
 7639        cx: &mut Context<Self>,
 7640    ) {
 7641        if !self.has_active_edit_prediction() {
 7642            self.refresh_edit_prediction(false, true, window, cx);
 7643            return;
 7644        }
 7645
 7646        self.update_visible_edit_prediction(window, cx);
 7647    }
 7648
 7649    pub fn display_cursor_names(
 7650        &mut self,
 7651        _: &DisplayCursorNames,
 7652        window: &mut Window,
 7653        cx: &mut Context<Self>,
 7654    ) {
 7655        self.show_cursor_names(window, cx);
 7656    }
 7657
 7658    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7659        self.show_cursor_names = true;
 7660        cx.notify();
 7661        cx.spawn_in(window, async move |this, cx| {
 7662            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7663            this.update(cx, |this, cx| {
 7664                this.show_cursor_names = false;
 7665                cx.notify()
 7666            })
 7667            .ok()
 7668        })
 7669        .detach();
 7670    }
 7671
 7672    pub fn accept_partial_edit_prediction(
 7673        &mut self,
 7674        granularity: EditPredictionGranularity,
 7675        window: &mut Window,
 7676        cx: &mut Context<Self>,
 7677    ) {
 7678        if self.show_edit_predictions_in_menu() {
 7679            self.hide_context_menu(window, cx);
 7680        }
 7681
 7682        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7683            return;
 7684        };
 7685
 7686        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7687            return;
 7688        }
 7689
 7690        match &active_edit_prediction.completion {
 7691            EditPrediction::MoveWithin { target, .. } => {
 7692                let target = *target;
 7693
 7694                if matches!(granularity, EditPredictionGranularity::Full) {
 7695                    if let Some(position_map) = &self.last_position_map {
 7696                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7697                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7698
 7699                        if is_visible || !self.edit_prediction_requires_modifier() {
 7700                            self.unfold_ranges(&[target..target], true, false, cx);
 7701                            self.change_selections(
 7702                                SelectionEffects::scroll(Autoscroll::newest()),
 7703                                window,
 7704                                cx,
 7705                                |selections| {
 7706                                    selections.select_anchor_ranges([target..target]);
 7707                                },
 7708                            );
 7709                            self.clear_row_highlights::<EditPredictionPreview>();
 7710                            self.edit_prediction_preview
 7711                                .set_previous_scroll_position(None);
 7712                        } else {
 7713                            // Highlight and request scroll
 7714                            self.edit_prediction_preview
 7715                                .set_previous_scroll_position(Some(
 7716                                    position_map.snapshot.scroll_anchor,
 7717                                ));
 7718                            self.highlight_rows::<EditPredictionPreview>(
 7719                                target..target,
 7720                                cx.theme().colors().editor_highlighted_line_background,
 7721                                RowHighlightOptions {
 7722                                    autoscroll: true,
 7723                                    ..Default::default()
 7724                                },
 7725                                cx,
 7726                            );
 7727                            self.request_autoscroll(Autoscroll::fit(), cx);
 7728                        }
 7729                    }
 7730                } else {
 7731                    self.change_selections(
 7732                        SelectionEffects::scroll(Autoscroll::newest()),
 7733                        window,
 7734                        cx,
 7735                        |selections| {
 7736                            selections.select_anchor_ranges([target..target]);
 7737                        },
 7738                    );
 7739                }
 7740            }
 7741            EditPrediction::MoveOutside { snapshot, target } => {
 7742                if let Some(workspace) = self.workspace() {
 7743                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7744                        .detach_and_log_err(cx);
 7745                }
 7746            }
 7747            EditPrediction::Edit { edits, .. } => {
 7748                self.report_edit_prediction_event(
 7749                    active_edit_prediction.completion_id.clone(),
 7750                    true,
 7751                    cx,
 7752                );
 7753
 7754                match granularity {
 7755                    EditPredictionGranularity::Full => {
 7756                        if let Some(provider) = self.edit_prediction_provider() {
 7757                            provider.accept(cx);
 7758                        }
 7759
 7760                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7761                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7762                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7763
 7764                        self.buffer.update(cx, |buffer, cx| {
 7765                            buffer.edit(edits.iter().cloned(), None, cx)
 7766                        });
 7767
 7768                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7769                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7770                        });
 7771
 7772                        let selections = self.selections.disjoint_anchors_arc();
 7773                        if let Some(transaction_id_now) =
 7774                            self.buffer.read(cx).last_transaction_id(cx)
 7775                        {
 7776                            if transaction_id_prev != Some(transaction_id_now) {
 7777                                self.selection_history
 7778                                    .insert_transaction(transaction_id_now, selections);
 7779                            }
 7780                        }
 7781
 7782                        self.update_visible_edit_prediction(window, cx);
 7783                        if self.active_edit_prediction.is_none() {
 7784                            self.refresh_edit_prediction(true, true, window, cx);
 7785                        }
 7786                        cx.notify();
 7787                    }
 7788                    _ => {
 7789                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7790                        let cursor_offset = self
 7791                            .selections
 7792                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7793                            .head();
 7794
 7795                        let insertion = edits.iter().find_map(|(range, text)| {
 7796                            let range = range.to_offset(&snapshot);
 7797                            if range.is_empty() && range.start == cursor_offset {
 7798                                Some(text)
 7799                            } else {
 7800                                None
 7801                            }
 7802                        });
 7803
 7804                        if let Some(text) = insertion {
 7805                            let text_to_insert = match granularity {
 7806                                EditPredictionGranularity::Word => {
 7807                                    let mut partial = text
 7808                                        .chars()
 7809                                        .by_ref()
 7810                                        .take_while(|c| c.is_alphabetic())
 7811                                        .collect::<String>();
 7812                                    if partial.is_empty() {
 7813                                        partial = text
 7814                                            .chars()
 7815                                            .by_ref()
 7816                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7817                                            .collect::<String>();
 7818                                    }
 7819                                    partial
 7820                                }
 7821                                EditPredictionGranularity::Line => {
 7822                                    if let Some(line) = text.split_inclusive('\n').next() {
 7823                                        line.to_string()
 7824                                    } else {
 7825                                        text.to_string()
 7826                                    }
 7827                                }
 7828                                EditPredictionGranularity::Full => unreachable!(),
 7829                            };
 7830
 7831                            cx.emit(EditorEvent::InputHandled {
 7832                                utf16_range_to_replace: None,
 7833                                text: text_to_insert.clone().into(),
 7834                            });
 7835
 7836                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7837                            self.refresh_edit_prediction(true, true, window, cx);
 7838                            cx.notify();
 7839                        } else {
 7840                            self.accept_partial_edit_prediction(
 7841                                EditPredictionGranularity::Full,
 7842                                window,
 7843                                cx,
 7844                            );
 7845                        }
 7846                    }
 7847                }
 7848            }
 7849        }
 7850
 7851        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7852    }
 7853
 7854    pub fn accept_next_word_edit_prediction(
 7855        &mut self,
 7856        _: &AcceptNextWordEditPrediction,
 7857        window: &mut Window,
 7858        cx: &mut Context<Self>,
 7859    ) {
 7860        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7861    }
 7862
 7863    pub fn accept_next_line_edit_prediction(
 7864        &mut self,
 7865        _: &AcceptNextLineEditPrediction,
 7866        window: &mut Window,
 7867        cx: &mut Context<Self>,
 7868    ) {
 7869        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7870    }
 7871
 7872    pub fn accept_edit_prediction(
 7873        &mut self,
 7874        _: &AcceptEditPrediction,
 7875        window: &mut Window,
 7876        cx: &mut Context<Self>,
 7877    ) {
 7878        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7879    }
 7880
 7881    fn discard_edit_prediction(
 7882        &mut self,
 7883        should_report_edit_prediction_event: bool,
 7884        cx: &mut Context<Self>,
 7885    ) -> bool {
 7886        if should_report_edit_prediction_event {
 7887            let completion_id = self
 7888                .active_edit_prediction
 7889                .as_ref()
 7890                .and_then(|active_completion| active_completion.completion_id.clone());
 7891
 7892            self.report_edit_prediction_event(completion_id, false, cx);
 7893        }
 7894
 7895        if let Some(provider) = self.edit_prediction_provider() {
 7896            provider.discard(cx);
 7897        }
 7898
 7899        self.take_active_edit_prediction(cx)
 7900    }
 7901
 7902    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7903        let Some(provider) = self.edit_prediction_provider() else {
 7904            return;
 7905        };
 7906
 7907        let Some((_, buffer, _)) = self
 7908            .buffer
 7909            .read(cx)
 7910            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7911        else {
 7912            return;
 7913        };
 7914
 7915        let extension = buffer
 7916            .read(cx)
 7917            .file()
 7918            .and_then(|file| Some(file.path().extension()?.to_string()));
 7919
 7920        let event_type = match accepted {
 7921            true => "Edit Prediction Accepted",
 7922            false => "Edit Prediction Discarded",
 7923        };
 7924        telemetry::event!(
 7925            event_type,
 7926            provider = provider.name(),
 7927            prediction_id = id,
 7928            suggestion_accepted = accepted,
 7929            file_extension = extension,
 7930        );
 7931    }
 7932
 7933    fn open_editor_at_anchor(
 7934        snapshot: &language::BufferSnapshot,
 7935        target: language::Anchor,
 7936        workspace: &Entity<Workspace>,
 7937        window: &mut Window,
 7938        cx: &mut App,
 7939    ) -> Task<Result<()>> {
 7940        workspace.update(cx, |workspace, cx| {
 7941            let path = snapshot.file().map(|file| file.full_path(cx));
 7942            let Some(path) =
 7943                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7944            else {
 7945                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7946            };
 7947            let target = text::ToPoint::to_point(&target, snapshot);
 7948            let item = workspace.open_path(path, None, true, window, cx);
 7949            window.spawn(cx, async move |cx| {
 7950                let Some(editor) = item.await?.downcast::<Editor>() else {
 7951                    return Ok(());
 7952                };
 7953                editor
 7954                    .update_in(cx, |editor, window, cx| {
 7955                        editor.go_to_singleton_buffer_point(target, window, cx);
 7956                    })
 7957                    .ok();
 7958                anyhow::Ok(())
 7959            })
 7960        })
 7961    }
 7962
 7963    pub fn has_active_edit_prediction(&self) -> bool {
 7964        self.active_edit_prediction.is_some()
 7965    }
 7966
 7967    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7968        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7969            return false;
 7970        };
 7971
 7972        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7973        self.clear_highlights::<EditPredictionHighlight>(cx);
 7974        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7975        true
 7976    }
 7977
 7978    /// Returns true when we're displaying the edit prediction popover below the cursor
 7979    /// like we are not previewing and the LSP autocomplete menu is visible
 7980    /// or we are in `when_holding_modifier` mode.
 7981    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7982        if self.edit_prediction_preview_is_active()
 7983            || !self.show_edit_predictions_in_menu()
 7984            || !self.edit_predictions_enabled()
 7985        {
 7986            return false;
 7987        }
 7988
 7989        if self.has_visible_completions_menu() {
 7990            return true;
 7991        }
 7992
 7993        has_completion && self.edit_prediction_requires_modifier()
 7994    }
 7995
 7996    fn handle_modifiers_changed(
 7997        &mut self,
 7998        modifiers: Modifiers,
 7999        position_map: &PositionMap,
 8000        window: &mut Window,
 8001        cx: &mut Context<Self>,
 8002    ) {
 8003        // Ensure that the edit prediction preview is updated, even when not
 8004        // enabled, if there's an active edit prediction preview.
 8005        if self.show_edit_predictions_in_menu()
 8006            || matches!(
 8007                self.edit_prediction_preview,
 8008                EditPredictionPreview::Active { .. }
 8009            )
 8010        {
 8011            self.update_edit_prediction_preview(&modifiers, window, cx);
 8012        }
 8013
 8014        self.update_selection_mode(&modifiers, position_map, window, cx);
 8015
 8016        let mouse_position = window.mouse_position();
 8017        if !position_map.text_hitbox.is_hovered(window) {
 8018            return;
 8019        }
 8020
 8021        self.update_hovered_link(
 8022            position_map.point_for_position(mouse_position),
 8023            &position_map.snapshot,
 8024            modifiers,
 8025            window,
 8026            cx,
 8027        )
 8028    }
 8029
 8030    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8031        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8032            MultiCursorModifier::Alt => modifiers.secondary(),
 8033            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8034        }
 8035    }
 8036
 8037    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8038        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8039            MultiCursorModifier::Alt => modifiers.alt,
 8040            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8041        }
 8042    }
 8043
 8044    fn columnar_selection_mode(
 8045        modifiers: &Modifiers,
 8046        cx: &mut Context<Self>,
 8047    ) -> Option<ColumnarMode> {
 8048        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8049            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8050                Some(ColumnarMode::FromMouse)
 8051            } else if Self::is_alt_pressed(modifiers, cx) {
 8052                Some(ColumnarMode::FromSelection)
 8053            } else {
 8054                None
 8055            }
 8056        } else {
 8057            None
 8058        }
 8059    }
 8060
 8061    fn update_selection_mode(
 8062        &mut self,
 8063        modifiers: &Modifiers,
 8064        position_map: &PositionMap,
 8065        window: &mut Window,
 8066        cx: &mut Context<Self>,
 8067    ) {
 8068        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8069            return;
 8070        };
 8071        if self.selections.pending_anchor().is_none() {
 8072            return;
 8073        }
 8074
 8075        let mouse_position = window.mouse_position();
 8076        let point_for_position = position_map.point_for_position(mouse_position);
 8077        let position = point_for_position.previous_valid;
 8078
 8079        self.select(
 8080            SelectPhase::BeginColumnar {
 8081                position,
 8082                reset: false,
 8083                mode,
 8084                goal_column: point_for_position.exact_unclipped.column(),
 8085            },
 8086            window,
 8087            cx,
 8088        );
 8089    }
 8090
 8091    fn update_edit_prediction_preview(
 8092        &mut self,
 8093        modifiers: &Modifiers,
 8094        window: &mut Window,
 8095        cx: &mut Context<Self>,
 8096    ) {
 8097        let mut modifiers_held = false;
 8098
 8099        // Check bindings for all granularities.
 8100        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8101        let granularities = [
 8102            EditPredictionGranularity::Full,
 8103            EditPredictionGranularity::Line,
 8104            EditPredictionGranularity::Word,
 8105        ];
 8106
 8107        for granularity in granularities {
 8108            if let Some(keystroke) = self
 8109                .accept_edit_prediction_keybind(granularity, window, cx)
 8110                .keystroke()
 8111            {
 8112                modifiers_held = modifiers_held
 8113                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8114            }
 8115        }
 8116
 8117        if modifiers_held {
 8118            if matches!(
 8119                self.edit_prediction_preview,
 8120                EditPredictionPreview::Inactive { .. }
 8121            ) {
 8122                self.edit_prediction_preview = EditPredictionPreview::Active {
 8123                    previous_scroll_position: None,
 8124                    since: Instant::now(),
 8125                };
 8126
 8127                self.update_visible_edit_prediction(window, cx);
 8128                cx.notify();
 8129            }
 8130        } else if let EditPredictionPreview::Active {
 8131            previous_scroll_position,
 8132            since,
 8133        } = self.edit_prediction_preview
 8134        {
 8135            if let (Some(previous_scroll_position), Some(position_map)) =
 8136                (previous_scroll_position, self.last_position_map.as_ref())
 8137            {
 8138                self.set_scroll_position(
 8139                    previous_scroll_position
 8140                        .scroll_position(&position_map.snapshot.display_snapshot),
 8141                    window,
 8142                    cx,
 8143                );
 8144            }
 8145
 8146            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8147                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8148            };
 8149            self.clear_row_highlights::<EditPredictionPreview>();
 8150            self.update_visible_edit_prediction(window, cx);
 8151            cx.notify();
 8152        }
 8153    }
 8154
 8155    fn update_visible_edit_prediction(
 8156        &mut self,
 8157        _window: &mut Window,
 8158        cx: &mut Context<Self>,
 8159    ) -> Option<()> {
 8160        if DisableAiSettings::get_global(cx).disable_ai {
 8161            return None;
 8162        }
 8163
 8164        if self.ime_transaction.is_some() {
 8165            self.discard_edit_prediction(false, cx);
 8166            return None;
 8167        }
 8168
 8169        let selection = self.selections.newest_anchor();
 8170        let cursor = selection.head();
 8171        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8172        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8173        let excerpt_id = cursor.excerpt_id;
 8174
 8175        let show_in_menu = self.show_edit_predictions_in_menu();
 8176        let completions_menu_has_precedence = !show_in_menu
 8177            && (self.context_menu.borrow().is_some()
 8178                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8179
 8180        if completions_menu_has_precedence
 8181            || !offset_selection.is_empty()
 8182            || self
 8183                .active_edit_prediction
 8184                .as_ref()
 8185                .is_some_and(|completion| {
 8186                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8187                        return false;
 8188                    };
 8189                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8190                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8191                    !invalidation_range.contains(&offset_selection.head())
 8192                })
 8193        {
 8194            self.discard_edit_prediction(false, cx);
 8195            return None;
 8196        }
 8197
 8198        self.take_active_edit_prediction(cx);
 8199        let Some(provider) = self.edit_prediction_provider() else {
 8200            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8201            return None;
 8202        };
 8203
 8204        let (buffer, cursor_buffer_position) =
 8205            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8206
 8207        self.edit_prediction_settings =
 8208            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8209
 8210        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8211
 8212        if self.edit_prediction_indent_conflict {
 8213            let cursor_point = cursor.to_point(&multibuffer);
 8214            let mut suggested_indent = None;
 8215            multibuffer.suggested_indents_callback(
 8216                cursor_point.row..cursor_point.row + 1,
 8217                |_, indent| {
 8218                    suggested_indent = Some(indent);
 8219                    ControlFlow::Break(())
 8220                },
 8221                cx,
 8222            );
 8223
 8224            if let Some(indent) = suggested_indent
 8225                && indent.len == cursor_point.column
 8226            {
 8227                self.edit_prediction_indent_conflict = false;
 8228            }
 8229        }
 8230
 8231        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8232
 8233        let (completion_id, edits, edit_preview) = match edit_prediction {
 8234            edit_prediction_types::EditPrediction::Local {
 8235                id,
 8236                edits,
 8237                edit_preview,
 8238            } => (id, edits, edit_preview),
 8239            edit_prediction_types::EditPrediction::Jump {
 8240                id,
 8241                snapshot,
 8242                target,
 8243            } => {
 8244                if let Some(provider) = &self.edit_prediction_provider {
 8245                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 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            if let Some(provider) = &self.edit_prediction_provider {
 8303                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8304            }
 8305            invalidation_row_range =
 8306                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8307            let target = first_edit_start;
 8308            EditPrediction::MoveWithin { target, snapshot }
 8309        } else {
 8310            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8311                && !self.edit_predictions_hidden_for_vim_mode;
 8312
 8313            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8314                if provider.show_tab_accept_marker() {
 8315                    EditDisplayMode::TabAccept
 8316                } else {
 8317                    EditDisplayMode::Inline
 8318                }
 8319            } else {
 8320                EditDisplayMode::DiffPopover
 8321            };
 8322
 8323            if show_completions_in_buffer {
 8324                if let Some(provider) = &self.edit_prediction_provider {
 8325                    let suggestion_display_type = match display_mode {
 8326                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8327                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8328                            SuggestionDisplayType::GhostText
 8329                        }
 8330                    };
 8331                    provider.provider.did_show(suggestion_display_type, cx);
 8332                }
 8333                if edits
 8334                    .iter()
 8335                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8336                {
 8337                    let mut inlays = Vec::new();
 8338                    for (range, new_text) in &edits {
 8339                        let inlay = Inlay::edit_prediction(
 8340                            post_inc(&mut self.next_inlay_id),
 8341                            range.start,
 8342                            new_text.as_ref(),
 8343                        );
 8344                        inlay_ids.push(inlay.id);
 8345                        inlays.push(inlay);
 8346                    }
 8347
 8348                    self.splice_inlays(&[], inlays, cx);
 8349                } else {
 8350                    let background_color = cx.theme().status().deleted_background;
 8351                    self.highlight_text::<EditPredictionHighlight>(
 8352                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8353                        HighlightStyle {
 8354                            background_color: Some(background_color),
 8355                            ..Default::default()
 8356                        },
 8357                        cx,
 8358                    );
 8359                }
 8360            }
 8361
 8362            invalidation_row_range = edit_start_row..edit_end_row;
 8363
 8364            EditPrediction::Edit {
 8365                edits,
 8366                edit_preview,
 8367                display_mode,
 8368                snapshot,
 8369            }
 8370        };
 8371
 8372        let invalidation_range = multibuffer
 8373            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8374            ..multibuffer.anchor_after(Point::new(
 8375                invalidation_row_range.end,
 8376                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8377            ));
 8378
 8379        self.stale_edit_prediction_in_menu = None;
 8380        self.active_edit_prediction = Some(EditPredictionState {
 8381            inlay_ids,
 8382            completion,
 8383            completion_id,
 8384            invalidation_range: Some(invalidation_range),
 8385        });
 8386
 8387        cx.notify();
 8388
 8389        Some(())
 8390    }
 8391
 8392    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8393        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8394    }
 8395
 8396    fn clear_tasks(&mut self) {
 8397        self.tasks.clear()
 8398    }
 8399
 8400    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8401        if self.tasks.insert(key, value).is_some() {
 8402            // This case should hopefully be rare, but just in case...
 8403            log::error!(
 8404                "multiple different run targets found on a single line, only the last target will be rendered"
 8405            )
 8406        }
 8407    }
 8408
 8409    /// Get all display points of breakpoints that will be rendered within editor
 8410    ///
 8411    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8412    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8413    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8414    fn active_breakpoints(
 8415        &self,
 8416        range: Range<DisplayRow>,
 8417        window: &mut Window,
 8418        cx: &mut Context<Self>,
 8419    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8420        let mut breakpoint_display_points = HashMap::default();
 8421
 8422        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8423            return breakpoint_display_points;
 8424        };
 8425
 8426        let snapshot = self.snapshot(window, cx);
 8427
 8428        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8429        let Some(project) = self.project() else {
 8430            return breakpoint_display_points;
 8431        };
 8432
 8433        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8434            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8435
 8436        for (buffer_snapshot, range, excerpt_id) in
 8437            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8438        {
 8439            let Some(buffer) = project
 8440                .read(cx)
 8441                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8442            else {
 8443                continue;
 8444            };
 8445            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8446                &buffer,
 8447                Some(
 8448                    buffer_snapshot.anchor_before(range.start)
 8449                        ..buffer_snapshot.anchor_after(range.end),
 8450                ),
 8451                buffer_snapshot,
 8452                cx,
 8453            );
 8454            for (breakpoint, state) in breakpoints {
 8455                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8456                let position = multi_buffer_anchor
 8457                    .to_point(&multi_buffer_snapshot)
 8458                    .to_display_point(&snapshot);
 8459
 8460                breakpoint_display_points.insert(
 8461                    position.row(),
 8462                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8463                );
 8464            }
 8465        }
 8466
 8467        breakpoint_display_points
 8468    }
 8469
 8470    fn breakpoint_context_menu(
 8471        &self,
 8472        anchor: Anchor,
 8473        window: &mut Window,
 8474        cx: &mut Context<Self>,
 8475    ) -> Entity<ui::ContextMenu> {
 8476        let weak_editor = cx.weak_entity();
 8477        let focus_handle = self.focus_handle(cx);
 8478
 8479        let row = self
 8480            .buffer
 8481            .read(cx)
 8482            .snapshot(cx)
 8483            .summary_for_anchor::<Point>(&anchor)
 8484            .row;
 8485
 8486        let breakpoint = self
 8487            .breakpoint_at_row(row, window, cx)
 8488            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8489
 8490        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8491            "Edit Log Breakpoint"
 8492        } else {
 8493            "Set Log Breakpoint"
 8494        };
 8495
 8496        let condition_breakpoint_msg = if breakpoint
 8497            .as_ref()
 8498            .is_some_and(|bp| bp.1.condition.is_some())
 8499        {
 8500            "Edit Condition Breakpoint"
 8501        } else {
 8502            "Set Condition Breakpoint"
 8503        };
 8504
 8505        let hit_condition_breakpoint_msg = if breakpoint
 8506            .as_ref()
 8507            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8508        {
 8509            "Edit Hit Condition Breakpoint"
 8510        } else {
 8511            "Set Hit Condition Breakpoint"
 8512        };
 8513
 8514        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8515            "Unset Breakpoint"
 8516        } else {
 8517            "Set Breakpoint"
 8518        };
 8519
 8520        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8521
 8522        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8523            BreakpointState::Enabled => Some("Disable"),
 8524            BreakpointState::Disabled => Some("Enable"),
 8525        });
 8526
 8527        let (anchor, breakpoint) =
 8528            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8529
 8530        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8531            menu.on_blur_subscription(Subscription::new(|| {}))
 8532                .context(focus_handle)
 8533                .when(run_to_cursor, |this| {
 8534                    let weak_editor = weak_editor.clone();
 8535                    this.entry("Run to cursor", None, move |window, cx| {
 8536                        weak_editor
 8537                            .update(cx, |editor, cx| {
 8538                                editor.change_selections(
 8539                                    SelectionEffects::no_scroll(),
 8540                                    window,
 8541                                    cx,
 8542                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8543                                );
 8544                            })
 8545                            .ok();
 8546
 8547                        window.dispatch_action(Box::new(RunToCursor), cx);
 8548                    })
 8549                    .separator()
 8550                })
 8551                .when_some(toggle_state_msg, |this, msg| {
 8552                    this.entry(msg, None, {
 8553                        let weak_editor = weak_editor.clone();
 8554                        let breakpoint = breakpoint.clone();
 8555                        move |_window, cx| {
 8556                            weak_editor
 8557                                .update(cx, |this, cx| {
 8558                                    this.edit_breakpoint_at_anchor(
 8559                                        anchor,
 8560                                        breakpoint.as_ref().clone(),
 8561                                        BreakpointEditAction::InvertState,
 8562                                        cx,
 8563                                    );
 8564                                })
 8565                                .log_err();
 8566                        }
 8567                    })
 8568                })
 8569                .entry(set_breakpoint_msg, None, {
 8570                    let weak_editor = weak_editor.clone();
 8571                    let breakpoint = breakpoint.clone();
 8572                    move |_window, cx| {
 8573                        weak_editor
 8574                            .update(cx, |this, cx| {
 8575                                this.edit_breakpoint_at_anchor(
 8576                                    anchor,
 8577                                    breakpoint.as_ref().clone(),
 8578                                    BreakpointEditAction::Toggle,
 8579                                    cx,
 8580                                );
 8581                            })
 8582                            .log_err();
 8583                    }
 8584                })
 8585                .entry(log_breakpoint_msg, None, {
 8586                    let breakpoint = breakpoint.clone();
 8587                    let weak_editor = weak_editor.clone();
 8588                    move |window, cx| {
 8589                        weak_editor
 8590                            .update(cx, |this, cx| {
 8591                                this.add_edit_breakpoint_block(
 8592                                    anchor,
 8593                                    breakpoint.as_ref(),
 8594                                    BreakpointPromptEditAction::Log,
 8595                                    window,
 8596                                    cx,
 8597                                );
 8598                            })
 8599                            .log_err();
 8600                    }
 8601                })
 8602                .entry(condition_breakpoint_msg, None, {
 8603                    let breakpoint = breakpoint.clone();
 8604                    let weak_editor = weak_editor.clone();
 8605                    move |window, cx| {
 8606                        weak_editor
 8607                            .update(cx, |this, cx| {
 8608                                this.add_edit_breakpoint_block(
 8609                                    anchor,
 8610                                    breakpoint.as_ref(),
 8611                                    BreakpointPromptEditAction::Condition,
 8612                                    window,
 8613                                    cx,
 8614                                );
 8615                            })
 8616                            .log_err();
 8617                    }
 8618                })
 8619                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8620                    weak_editor
 8621                        .update(cx, |this, cx| {
 8622                            this.add_edit_breakpoint_block(
 8623                                anchor,
 8624                                breakpoint.as_ref(),
 8625                                BreakpointPromptEditAction::HitCondition,
 8626                                window,
 8627                                cx,
 8628                            );
 8629                        })
 8630                        .log_err();
 8631                })
 8632        })
 8633    }
 8634
 8635    fn render_breakpoint(
 8636        &self,
 8637        position: Anchor,
 8638        row: DisplayRow,
 8639        breakpoint: &Breakpoint,
 8640        state: Option<BreakpointSessionState>,
 8641        cx: &mut Context<Self>,
 8642    ) -> IconButton {
 8643        let is_rejected = state.is_some_and(|s| !s.verified);
 8644        // Is it a breakpoint that shows up when hovering over gutter?
 8645        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8646            (false, false),
 8647            |PhantomBreakpointIndicator {
 8648                 is_active,
 8649                 display_row,
 8650                 collides_with_existing_breakpoint,
 8651             }| {
 8652                (
 8653                    is_active && display_row == row,
 8654                    collides_with_existing_breakpoint,
 8655                )
 8656            },
 8657        );
 8658
 8659        let (color, icon) = {
 8660            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8661                (false, false) => ui::IconName::DebugBreakpoint,
 8662                (true, false) => ui::IconName::DebugLogBreakpoint,
 8663                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8664                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8665            };
 8666
 8667            let theme_colors = cx.theme().colors();
 8668
 8669            let color = if is_phantom {
 8670                if collides_with_existing {
 8671                    Color::Custom(
 8672                        theme_colors
 8673                            .debugger_accent
 8674                            .blend(theme_colors.text.opacity(0.6)),
 8675                    )
 8676                } else {
 8677                    Color::Hint
 8678                }
 8679            } else if is_rejected {
 8680                Color::Disabled
 8681            } else {
 8682                Color::Debugger
 8683            };
 8684
 8685            (color, icon)
 8686        };
 8687
 8688        let breakpoint = Arc::from(breakpoint.clone());
 8689
 8690        let alt_as_text = gpui::Keystroke {
 8691            modifiers: Modifiers::secondary_key(),
 8692            ..Default::default()
 8693        };
 8694        let primary_action_text = if breakpoint.is_disabled() {
 8695            "Enable breakpoint"
 8696        } else if is_phantom && !collides_with_existing {
 8697            "Set breakpoint"
 8698        } else {
 8699            "Unset breakpoint"
 8700        };
 8701        let focus_handle = self.focus_handle.clone();
 8702
 8703        let meta = if is_rejected {
 8704            SharedString::from("No executable code is associated with this line.")
 8705        } else if collides_with_existing && !breakpoint.is_disabled() {
 8706            SharedString::from(format!(
 8707                "{alt_as_text}-click to disable,\nright-click for more options."
 8708            ))
 8709        } else {
 8710            SharedString::from("Right-click for more options.")
 8711        };
 8712        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8713            .icon_size(IconSize::XSmall)
 8714            .size(ui::ButtonSize::None)
 8715            .when(is_rejected, |this| {
 8716                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8717            })
 8718            .icon_color(color)
 8719            .style(ButtonStyle::Transparent)
 8720            .on_click(cx.listener({
 8721                move |editor, event: &ClickEvent, window, cx| {
 8722                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8723                        BreakpointEditAction::InvertState
 8724                    } else {
 8725                        BreakpointEditAction::Toggle
 8726                    };
 8727
 8728                    window.focus(&editor.focus_handle(cx), cx);
 8729                    editor.edit_breakpoint_at_anchor(
 8730                        position,
 8731                        breakpoint.as_ref().clone(),
 8732                        edit_action,
 8733                        cx,
 8734                    );
 8735                }
 8736            }))
 8737            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8738                editor.set_breakpoint_context_menu(
 8739                    row,
 8740                    Some(position),
 8741                    event.position(),
 8742                    window,
 8743                    cx,
 8744                );
 8745            }))
 8746            .tooltip(move |_window, cx| {
 8747                Tooltip::with_meta_in(
 8748                    primary_action_text,
 8749                    Some(&ToggleBreakpoint),
 8750                    meta.clone(),
 8751                    &focus_handle,
 8752                    cx,
 8753                )
 8754            })
 8755    }
 8756
 8757    fn build_tasks_context(
 8758        project: &Entity<Project>,
 8759        buffer: &Entity<Buffer>,
 8760        buffer_row: u32,
 8761        tasks: &Arc<RunnableTasks>,
 8762        cx: &mut Context<Self>,
 8763    ) -> Task<Option<task::TaskContext>> {
 8764        let position = Point::new(buffer_row, tasks.column);
 8765        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8766        let location = Location {
 8767            buffer: buffer.clone(),
 8768            range: range_start..range_start,
 8769        };
 8770        // Fill in the environmental variables from the tree-sitter captures
 8771        let mut captured_task_variables = TaskVariables::default();
 8772        for (capture_name, value) in tasks.extra_variables.clone() {
 8773            captured_task_variables.insert(
 8774                task::VariableName::Custom(capture_name.into()),
 8775                value.clone(),
 8776            );
 8777        }
 8778        project.update(cx, |project, cx| {
 8779            project.task_store().update(cx, |task_store, cx| {
 8780                task_store.task_context_for_location(captured_task_variables, location, cx)
 8781            })
 8782        })
 8783    }
 8784
 8785    pub fn spawn_nearest_task(
 8786        &mut self,
 8787        action: &SpawnNearestTask,
 8788        window: &mut Window,
 8789        cx: &mut Context<Self>,
 8790    ) {
 8791        let Some((workspace, _)) = self.workspace.clone() else {
 8792            return;
 8793        };
 8794        let Some(project) = self.project.clone() else {
 8795            return;
 8796        };
 8797
 8798        // Try to find a closest, enclosing node using tree-sitter that has a task
 8799        let Some((buffer, buffer_row, tasks)) = self
 8800            .find_enclosing_node_task(cx)
 8801            // Or find the task that's closest in row-distance.
 8802            .or_else(|| self.find_closest_task(cx))
 8803        else {
 8804            return;
 8805        };
 8806
 8807        let reveal_strategy = action.reveal;
 8808        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8809        cx.spawn_in(window, async move |_, cx| {
 8810            let context = task_context.await?;
 8811            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8812
 8813            let resolved = &mut resolved_task.resolved;
 8814            resolved.reveal = reveal_strategy;
 8815
 8816            workspace
 8817                .update_in(cx, |workspace, window, cx| {
 8818                    workspace.schedule_resolved_task(
 8819                        task_source_kind,
 8820                        resolved_task,
 8821                        false,
 8822                        window,
 8823                        cx,
 8824                    );
 8825                })
 8826                .ok()
 8827        })
 8828        .detach();
 8829    }
 8830
 8831    fn find_closest_task(
 8832        &mut self,
 8833        cx: &mut Context<Self>,
 8834    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8835        let cursor_row = self
 8836            .selections
 8837            .newest_adjusted(&self.display_snapshot(cx))
 8838            .head()
 8839            .row;
 8840
 8841        let ((buffer_id, row), tasks) = self
 8842            .tasks
 8843            .iter()
 8844            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8845
 8846        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8847        let tasks = Arc::new(tasks.to_owned());
 8848        Some((buffer, *row, tasks))
 8849    }
 8850
 8851    fn find_enclosing_node_task(
 8852        &mut self,
 8853        cx: &mut Context<Self>,
 8854    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8855        let snapshot = self.buffer.read(cx).snapshot(cx);
 8856        let offset = self
 8857            .selections
 8858            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8859            .head();
 8860        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8861        let offset = excerpt.map_offset_to_buffer(offset);
 8862        let buffer_id = excerpt.buffer().remote_id();
 8863
 8864        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8865        let mut cursor = layer.node().walk();
 8866
 8867        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8868            if cursor.node().end_byte() == offset.0 {
 8869                cursor.goto_next_sibling();
 8870            }
 8871        }
 8872
 8873        // Ascend to the smallest ancestor that contains the range and has a task.
 8874        loop {
 8875            let node = cursor.node();
 8876            let node_range = node.byte_range();
 8877            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8878
 8879            // Check if this node contains our offset
 8880            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8881                // If it contains offset, check for task
 8882                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8883                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8884                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8885                }
 8886            }
 8887
 8888            if !cursor.goto_parent() {
 8889                break;
 8890            }
 8891        }
 8892        None
 8893    }
 8894
 8895    fn render_run_indicator(
 8896        &self,
 8897        _style: &EditorStyle,
 8898        is_active: bool,
 8899        row: DisplayRow,
 8900        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8901        cx: &mut Context<Self>,
 8902    ) -> IconButton {
 8903        let color = Color::Muted;
 8904        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8905
 8906        IconButton::new(
 8907            ("run_indicator", row.0 as usize),
 8908            ui::IconName::PlayOutlined,
 8909        )
 8910        .shape(ui::IconButtonShape::Square)
 8911        .icon_size(IconSize::XSmall)
 8912        .icon_color(color)
 8913        .toggle_state(is_active)
 8914        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8915            let quick_launch = match e {
 8916                ClickEvent::Keyboard(_) => true,
 8917                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8918            };
 8919
 8920            window.focus(&editor.focus_handle(cx), cx);
 8921            editor.toggle_code_actions(
 8922                &ToggleCodeActions {
 8923                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8924                    quick_launch,
 8925                },
 8926                window,
 8927                cx,
 8928            );
 8929        }))
 8930        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8931            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8932        }))
 8933    }
 8934
 8935    pub fn context_menu_visible(&self) -> bool {
 8936        !self.edit_prediction_preview_is_active()
 8937            && self
 8938                .context_menu
 8939                .borrow()
 8940                .as_ref()
 8941                .is_some_and(|menu| menu.visible())
 8942    }
 8943
 8944    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8945        self.context_menu
 8946            .borrow()
 8947            .as_ref()
 8948            .map(|menu| menu.origin())
 8949    }
 8950
 8951    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8952        self.context_menu_options = Some(options);
 8953    }
 8954
 8955    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8956    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8957
 8958    fn render_edit_prediction_popover(
 8959        &mut self,
 8960        text_bounds: &Bounds<Pixels>,
 8961        content_origin: gpui::Point<Pixels>,
 8962        right_margin: Pixels,
 8963        editor_snapshot: &EditorSnapshot,
 8964        visible_row_range: Range<DisplayRow>,
 8965        scroll_top: ScrollOffset,
 8966        scroll_bottom: ScrollOffset,
 8967        line_layouts: &[LineWithInvisibles],
 8968        line_height: Pixels,
 8969        scroll_position: gpui::Point<ScrollOffset>,
 8970        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8971        newest_selection_head: Option<DisplayPoint>,
 8972        editor_width: Pixels,
 8973        style: &EditorStyle,
 8974        window: &mut Window,
 8975        cx: &mut App,
 8976    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8977        if self.mode().is_minimap() {
 8978            return None;
 8979        }
 8980        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8981
 8982        if self.edit_prediction_visible_in_cursor_popover(true) {
 8983            return None;
 8984        }
 8985
 8986        match &active_edit_prediction.completion {
 8987            EditPrediction::MoveWithin { target, .. } => {
 8988                let target_display_point = target.to_display_point(editor_snapshot);
 8989
 8990                if self.edit_prediction_requires_modifier() {
 8991                    if !self.edit_prediction_preview_is_active() {
 8992                        return None;
 8993                    }
 8994
 8995                    self.render_edit_prediction_modifier_jump_popover(
 8996                        text_bounds,
 8997                        content_origin,
 8998                        visible_row_range,
 8999                        line_layouts,
 9000                        line_height,
 9001                        scroll_pixel_position,
 9002                        newest_selection_head,
 9003                        target_display_point,
 9004                        window,
 9005                        cx,
 9006                    )
 9007                } else {
 9008                    self.render_edit_prediction_eager_jump_popover(
 9009                        text_bounds,
 9010                        content_origin,
 9011                        editor_snapshot,
 9012                        visible_row_range,
 9013                        scroll_top,
 9014                        scroll_bottom,
 9015                        line_height,
 9016                        scroll_pixel_position,
 9017                        target_display_point,
 9018                        editor_width,
 9019                        window,
 9020                        cx,
 9021                    )
 9022                }
 9023            }
 9024            EditPrediction::Edit {
 9025                display_mode: EditDisplayMode::Inline,
 9026                ..
 9027            } => None,
 9028            EditPrediction::Edit {
 9029                display_mode: EditDisplayMode::TabAccept,
 9030                edits,
 9031                ..
 9032            } => {
 9033                let range = &edits.first()?.0;
 9034                let target_display_point = range.end.to_display_point(editor_snapshot);
 9035
 9036                self.render_edit_prediction_end_of_line_popover(
 9037                    "Accept",
 9038                    editor_snapshot,
 9039                    visible_row_range,
 9040                    target_display_point,
 9041                    line_height,
 9042                    scroll_pixel_position,
 9043                    content_origin,
 9044                    editor_width,
 9045                    window,
 9046                    cx,
 9047                )
 9048            }
 9049            EditPrediction::Edit {
 9050                edits,
 9051                edit_preview,
 9052                display_mode: EditDisplayMode::DiffPopover,
 9053                snapshot,
 9054            } => self.render_edit_prediction_diff_popover(
 9055                text_bounds,
 9056                content_origin,
 9057                right_margin,
 9058                editor_snapshot,
 9059                visible_row_range,
 9060                line_layouts,
 9061                line_height,
 9062                scroll_position,
 9063                scroll_pixel_position,
 9064                newest_selection_head,
 9065                editor_width,
 9066                style,
 9067                edits,
 9068                edit_preview,
 9069                snapshot,
 9070                window,
 9071                cx,
 9072            ),
 9073            EditPrediction::MoveOutside { snapshot, .. } => {
 9074                let mut element = self
 9075                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9076                    .into_any();
 9077
 9078                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9079                let origin_x = text_bounds.size.width - size.width - px(30.);
 9080                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9081                element.prepaint_at(origin, window, cx);
 9082
 9083                Some((element, origin))
 9084            }
 9085        }
 9086    }
 9087
 9088    fn render_edit_prediction_modifier_jump_popover(
 9089        &mut self,
 9090        text_bounds: &Bounds<Pixels>,
 9091        content_origin: gpui::Point<Pixels>,
 9092        visible_row_range: Range<DisplayRow>,
 9093        line_layouts: &[LineWithInvisibles],
 9094        line_height: Pixels,
 9095        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9096        newest_selection_head: Option<DisplayPoint>,
 9097        target_display_point: DisplayPoint,
 9098        window: &mut Window,
 9099        cx: &mut App,
 9100    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9101        let scrolled_content_origin =
 9102            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9103
 9104        const SCROLL_PADDING_Y: Pixels = px(12.);
 9105
 9106        if target_display_point.row() < visible_row_range.start {
 9107            return self.render_edit_prediction_scroll_popover(
 9108                |_| SCROLL_PADDING_Y,
 9109                IconName::ArrowUp,
 9110                visible_row_range,
 9111                line_layouts,
 9112                newest_selection_head,
 9113                scrolled_content_origin,
 9114                window,
 9115                cx,
 9116            );
 9117        } else if target_display_point.row() >= visible_row_range.end {
 9118            return self.render_edit_prediction_scroll_popover(
 9119                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9120                IconName::ArrowDown,
 9121                visible_row_range,
 9122                line_layouts,
 9123                newest_selection_head,
 9124                scrolled_content_origin,
 9125                window,
 9126                cx,
 9127            );
 9128        }
 9129
 9130        const POLE_WIDTH: Pixels = px(2.);
 9131
 9132        let line_layout =
 9133            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9134        let target_column = target_display_point.column() as usize;
 9135
 9136        let target_x = line_layout.x_for_index(target_column);
 9137        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9138            - scroll_pixel_position.y;
 9139
 9140        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9141
 9142        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9143        border_color.l += 0.001;
 9144
 9145        let mut element = v_flex()
 9146            .items_end()
 9147            .when(flag_on_right, |el| el.items_start())
 9148            .child(if flag_on_right {
 9149                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9150                    .rounded_bl(px(0.))
 9151                    .rounded_tl(px(0.))
 9152                    .border_l_2()
 9153                    .border_color(border_color)
 9154            } else {
 9155                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9156                    .rounded_br(px(0.))
 9157                    .rounded_tr(px(0.))
 9158                    .border_r_2()
 9159                    .border_color(border_color)
 9160            })
 9161            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9162            .into_any();
 9163
 9164        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9165
 9166        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9167            - point(
 9168                if flag_on_right {
 9169                    POLE_WIDTH
 9170                } else {
 9171                    size.width - POLE_WIDTH
 9172                },
 9173                size.height - line_height,
 9174            );
 9175
 9176        origin.x = origin.x.max(content_origin.x);
 9177
 9178        element.prepaint_at(origin, window, cx);
 9179
 9180        Some((element, origin))
 9181    }
 9182
 9183    fn render_edit_prediction_scroll_popover(
 9184        &mut self,
 9185        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9186        scroll_icon: IconName,
 9187        visible_row_range: Range<DisplayRow>,
 9188        line_layouts: &[LineWithInvisibles],
 9189        newest_selection_head: Option<DisplayPoint>,
 9190        scrolled_content_origin: gpui::Point<Pixels>,
 9191        window: &mut Window,
 9192        cx: &mut App,
 9193    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9194        let mut element = self
 9195            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9196            .into_any();
 9197
 9198        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9199
 9200        let cursor = newest_selection_head?;
 9201        let cursor_row_layout =
 9202            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9203        let cursor_column = cursor.column() as usize;
 9204
 9205        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9206
 9207        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9208
 9209        element.prepaint_at(origin, window, cx);
 9210        Some((element, origin))
 9211    }
 9212
 9213    fn render_edit_prediction_eager_jump_popover(
 9214        &mut self,
 9215        text_bounds: &Bounds<Pixels>,
 9216        content_origin: gpui::Point<Pixels>,
 9217        editor_snapshot: &EditorSnapshot,
 9218        visible_row_range: Range<DisplayRow>,
 9219        scroll_top: ScrollOffset,
 9220        scroll_bottom: ScrollOffset,
 9221        line_height: Pixels,
 9222        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9223        target_display_point: DisplayPoint,
 9224        editor_width: Pixels,
 9225        window: &mut Window,
 9226        cx: &mut App,
 9227    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9228        if target_display_point.row().as_f64() < scroll_top {
 9229            let mut element = self
 9230                .render_edit_prediction_line_popover(
 9231                    "Jump to Edit",
 9232                    Some(IconName::ArrowUp),
 9233                    window,
 9234                    cx,
 9235                )
 9236                .into_any();
 9237
 9238            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9239            let offset = point(
 9240                (text_bounds.size.width - size.width) / 2.,
 9241                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9242            );
 9243
 9244            let origin = text_bounds.origin + offset;
 9245            element.prepaint_at(origin, window, cx);
 9246            Some((element, origin))
 9247        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9248            let mut element = self
 9249                .render_edit_prediction_line_popover(
 9250                    "Jump to Edit",
 9251                    Some(IconName::ArrowDown),
 9252                    window,
 9253                    cx,
 9254                )
 9255                .into_any();
 9256
 9257            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9258            let offset = point(
 9259                (text_bounds.size.width - size.width) / 2.,
 9260                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9261            );
 9262
 9263            let origin = text_bounds.origin + offset;
 9264            element.prepaint_at(origin, window, cx);
 9265            Some((element, origin))
 9266        } else {
 9267            self.render_edit_prediction_end_of_line_popover(
 9268                "Jump to Edit",
 9269                editor_snapshot,
 9270                visible_row_range,
 9271                target_display_point,
 9272                line_height,
 9273                scroll_pixel_position,
 9274                content_origin,
 9275                editor_width,
 9276                window,
 9277                cx,
 9278            )
 9279        }
 9280    }
 9281
 9282    fn render_edit_prediction_end_of_line_popover(
 9283        self: &mut Editor,
 9284        label: &'static str,
 9285        editor_snapshot: &EditorSnapshot,
 9286        visible_row_range: Range<DisplayRow>,
 9287        target_display_point: DisplayPoint,
 9288        line_height: Pixels,
 9289        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9290        content_origin: gpui::Point<Pixels>,
 9291        editor_width: Pixels,
 9292        window: &mut Window,
 9293        cx: &mut App,
 9294    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9295        let target_line_end = DisplayPoint::new(
 9296            target_display_point.row(),
 9297            editor_snapshot.line_len(target_display_point.row()),
 9298        );
 9299
 9300        let mut element = self
 9301            .render_edit_prediction_line_popover(label, None, window, cx)
 9302            .into_any();
 9303
 9304        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9305
 9306        let line_origin =
 9307            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9308
 9309        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9310        let mut origin = start_point
 9311            + line_origin
 9312            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9313        origin.x = origin.x.max(content_origin.x);
 9314
 9315        let max_x = content_origin.x + editor_width - size.width;
 9316
 9317        if origin.x > max_x {
 9318            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9319
 9320            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9321                origin.y += offset;
 9322                IconName::ArrowUp
 9323            } else {
 9324                origin.y -= offset;
 9325                IconName::ArrowDown
 9326            };
 9327
 9328            element = self
 9329                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9330                .into_any();
 9331
 9332            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9333
 9334            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9335        }
 9336
 9337        element.prepaint_at(origin, window, cx);
 9338        Some((element, origin))
 9339    }
 9340
 9341    fn render_edit_prediction_diff_popover(
 9342        self: &Editor,
 9343        text_bounds: &Bounds<Pixels>,
 9344        content_origin: gpui::Point<Pixels>,
 9345        right_margin: Pixels,
 9346        editor_snapshot: &EditorSnapshot,
 9347        visible_row_range: Range<DisplayRow>,
 9348        line_layouts: &[LineWithInvisibles],
 9349        line_height: Pixels,
 9350        scroll_position: gpui::Point<ScrollOffset>,
 9351        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9352        newest_selection_head: Option<DisplayPoint>,
 9353        editor_width: Pixels,
 9354        style: &EditorStyle,
 9355        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9356        edit_preview: &Option<language::EditPreview>,
 9357        snapshot: &language::BufferSnapshot,
 9358        window: &mut Window,
 9359        cx: &mut App,
 9360    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9361        let edit_start = edits
 9362            .first()
 9363            .unwrap()
 9364            .0
 9365            .start
 9366            .to_display_point(editor_snapshot);
 9367        let edit_end = edits
 9368            .last()
 9369            .unwrap()
 9370            .0
 9371            .end
 9372            .to_display_point(editor_snapshot);
 9373
 9374        let is_visible = visible_row_range.contains(&edit_start.row())
 9375            || visible_row_range.contains(&edit_end.row());
 9376        if !is_visible {
 9377            return None;
 9378        }
 9379
 9380        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9381            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9382        } else {
 9383            // Fallback for providers without edit_preview
 9384            crate::edit_prediction_fallback_text(edits, cx)
 9385        };
 9386
 9387        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9388        let line_count = highlighted_edits.text.lines().count();
 9389
 9390        const BORDER_WIDTH: Pixels = px(1.);
 9391
 9392        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9393        let has_keybind = keybind.is_some();
 9394
 9395        let mut element = h_flex()
 9396            .items_start()
 9397            .child(
 9398                h_flex()
 9399                    .bg(cx.theme().colors().editor_background)
 9400                    .border(BORDER_WIDTH)
 9401                    .shadow_xs()
 9402                    .border_color(cx.theme().colors().border)
 9403                    .rounded_l_lg()
 9404                    .when(line_count > 1, |el| el.rounded_br_lg())
 9405                    .pr_1()
 9406                    .child(styled_text),
 9407            )
 9408            .child(
 9409                h_flex()
 9410                    .h(line_height + BORDER_WIDTH * 2.)
 9411                    .px_1p5()
 9412                    .gap_1()
 9413                    // Workaround: For some reason, there's a gap if we don't do this
 9414                    .ml(-BORDER_WIDTH)
 9415                    .shadow(vec![gpui::BoxShadow {
 9416                        color: gpui::black().opacity(0.05),
 9417                        offset: point(px(1.), px(1.)),
 9418                        blur_radius: px(2.),
 9419                        spread_radius: px(0.),
 9420                    }])
 9421                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9422                    .border(BORDER_WIDTH)
 9423                    .border_color(cx.theme().colors().border)
 9424                    .rounded_r_lg()
 9425                    .id("edit_prediction_diff_popover_keybind")
 9426                    .when(!has_keybind, |el| {
 9427                        let status_colors = cx.theme().status();
 9428
 9429                        el.bg(status_colors.error_background)
 9430                            .border_color(status_colors.error.opacity(0.6))
 9431                            .child(Icon::new(IconName::Info).color(Color::Error))
 9432                            .cursor_default()
 9433                            .hoverable_tooltip(move |_window, cx| {
 9434                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9435                            })
 9436                    })
 9437                    .children(keybind),
 9438            )
 9439            .into_any();
 9440
 9441        let longest_row =
 9442            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9443        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9444            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9445        } else {
 9446            layout_line(
 9447                longest_row,
 9448                editor_snapshot,
 9449                style,
 9450                editor_width,
 9451                |_| false,
 9452                window,
 9453                cx,
 9454            )
 9455            .width
 9456        };
 9457
 9458        let viewport_bounds =
 9459            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9460                right: -right_margin,
 9461                ..Default::default()
 9462            });
 9463
 9464        let x_after_longest = Pixels::from(
 9465            ScrollPixelOffset::from(
 9466                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9467            ) - scroll_pixel_position.x,
 9468        );
 9469
 9470        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9471
 9472        // Fully visible if it can be displayed within the window (allow overlapping other
 9473        // panes). However, this is only allowed if the popover starts within text_bounds.
 9474        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9475            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9476
 9477        let mut origin = if can_position_to_the_right {
 9478            point(
 9479                x_after_longest,
 9480                text_bounds.origin.y
 9481                    + Pixels::from(
 9482                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9483                            - scroll_pixel_position.y,
 9484                    ),
 9485            )
 9486        } else {
 9487            let cursor_row = newest_selection_head.map(|head| head.row());
 9488            let above_edit = edit_start
 9489                .row()
 9490                .0
 9491                .checked_sub(line_count as u32)
 9492                .map(DisplayRow);
 9493            let below_edit = Some(edit_end.row() + 1);
 9494            let above_cursor =
 9495                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9496            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9497
 9498            // Place the edit popover adjacent to the edit if there is a location
 9499            // available that is onscreen and does not obscure the cursor. Otherwise,
 9500            // place it adjacent to the cursor.
 9501            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9502                .into_iter()
 9503                .flatten()
 9504                .find(|&start_row| {
 9505                    let end_row = start_row + line_count as u32;
 9506                    visible_row_range.contains(&start_row)
 9507                        && visible_row_range.contains(&end_row)
 9508                        && cursor_row
 9509                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9510                })?;
 9511
 9512            content_origin
 9513                + point(
 9514                    Pixels::from(-scroll_pixel_position.x),
 9515                    Pixels::from(
 9516                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9517                    ),
 9518                )
 9519        };
 9520
 9521        origin.x -= BORDER_WIDTH;
 9522
 9523        window.defer_draw(element, origin, 1);
 9524
 9525        // Do not return an element, since it will already be drawn due to defer_draw.
 9526        None
 9527    }
 9528
 9529    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9530        px(30.)
 9531    }
 9532
 9533    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9534        if self.read_only(cx) {
 9535            cx.theme().players().read_only()
 9536        } else {
 9537            self.style.as_ref().unwrap().local_player
 9538        }
 9539    }
 9540
 9541    fn render_edit_prediction_accept_keybind(
 9542        &self,
 9543        window: &mut Window,
 9544        cx: &mut App,
 9545    ) -> Option<AnyElement> {
 9546        let accept_binding =
 9547            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9548        let accept_keystroke = accept_binding.keystroke()?;
 9549
 9550        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9551
 9552        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9553            Color::Accent
 9554        } else {
 9555            Color::Muted
 9556        };
 9557
 9558        h_flex()
 9559            .px_0p5()
 9560            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9561            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9562            .text_size(TextSize::XSmall.rems(cx))
 9563            .child(h_flex().children(ui::render_modifiers(
 9564                accept_keystroke.modifiers(),
 9565                PlatformStyle::platform(),
 9566                Some(modifiers_color),
 9567                Some(IconSize::XSmall.rems().into()),
 9568                true,
 9569            )))
 9570            .when(is_platform_style_mac, |parent| {
 9571                parent.child(accept_keystroke.key().to_string())
 9572            })
 9573            .when(!is_platform_style_mac, |parent| {
 9574                parent.child(
 9575                    Key::new(
 9576                        util::capitalize(accept_keystroke.key()),
 9577                        Some(Color::Default),
 9578                    )
 9579                    .size(Some(IconSize::XSmall.rems().into())),
 9580                )
 9581            })
 9582            .into_any()
 9583            .into()
 9584    }
 9585
 9586    fn render_edit_prediction_line_popover(
 9587        &self,
 9588        label: impl Into<SharedString>,
 9589        icon: Option<IconName>,
 9590        window: &mut Window,
 9591        cx: &mut App,
 9592    ) -> Stateful<Div> {
 9593        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9594
 9595        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9596        let has_keybind = keybind.is_some();
 9597
 9598        h_flex()
 9599            .id("ep-line-popover")
 9600            .py_0p5()
 9601            .pl_1()
 9602            .pr(padding_right)
 9603            .gap_1()
 9604            .rounded_md()
 9605            .border_1()
 9606            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9607            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9608            .shadow_xs()
 9609            .when(!has_keybind, |el| {
 9610                let status_colors = cx.theme().status();
 9611
 9612                el.bg(status_colors.error_background)
 9613                    .border_color(status_colors.error.opacity(0.6))
 9614                    .pl_2()
 9615                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9616                    .cursor_default()
 9617                    .hoverable_tooltip(move |_window, cx| {
 9618                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9619                    })
 9620            })
 9621            .children(keybind)
 9622            .child(
 9623                Label::new(label)
 9624                    .size(LabelSize::Small)
 9625                    .when(!has_keybind, |el| {
 9626                        el.color(cx.theme().status().error.into()).strikethrough()
 9627                    }),
 9628            )
 9629            .when(!has_keybind, |el| {
 9630                el.child(
 9631                    h_flex().ml_1().child(
 9632                        Icon::new(IconName::Info)
 9633                            .size(IconSize::Small)
 9634                            .color(cx.theme().status().error.into()),
 9635                    ),
 9636                )
 9637            })
 9638            .when_some(icon, |element, icon| {
 9639                element.child(
 9640                    div()
 9641                        .mt(px(1.5))
 9642                        .child(Icon::new(icon).size(IconSize::Small)),
 9643                )
 9644            })
 9645    }
 9646
 9647    fn render_edit_prediction_jump_outside_popover(
 9648        &self,
 9649        snapshot: &BufferSnapshot,
 9650        window: &mut Window,
 9651        cx: &mut App,
 9652    ) -> Stateful<Div> {
 9653        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9654        let has_keybind = keybind.is_some();
 9655
 9656        let file_name = snapshot
 9657            .file()
 9658            .map(|file| SharedString::new(file.file_name(cx)))
 9659            .unwrap_or(SharedString::new_static("untitled"));
 9660
 9661        h_flex()
 9662            .id("ep-jump-outside-popover")
 9663            .py_1()
 9664            .px_2()
 9665            .gap_1()
 9666            .rounded_md()
 9667            .border_1()
 9668            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9669            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9670            .shadow_xs()
 9671            .when(!has_keybind, |el| {
 9672                let status_colors = cx.theme().status();
 9673
 9674                el.bg(status_colors.error_background)
 9675                    .border_color(status_colors.error.opacity(0.6))
 9676                    .pl_2()
 9677                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9678                    .cursor_default()
 9679                    .hoverable_tooltip(move |_window, cx| {
 9680                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9681                    })
 9682            })
 9683            .children(keybind)
 9684            .child(
 9685                Label::new(file_name)
 9686                    .size(LabelSize::Small)
 9687                    .buffer_font(cx)
 9688                    .when(!has_keybind, |el| {
 9689                        el.color(cx.theme().status().error.into()).strikethrough()
 9690                    }),
 9691            )
 9692            .when(!has_keybind, |el| {
 9693                el.child(
 9694                    h_flex().ml_1().child(
 9695                        Icon::new(IconName::Info)
 9696                            .size(IconSize::Small)
 9697                            .color(cx.theme().status().error.into()),
 9698                    ),
 9699                )
 9700            })
 9701            .child(
 9702                div()
 9703                    .mt(px(1.5))
 9704                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9705            )
 9706    }
 9707
 9708    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9709        let accent_color = cx.theme().colors().text_accent;
 9710        let editor_bg_color = cx.theme().colors().editor_background;
 9711        editor_bg_color.blend(accent_color.opacity(0.1))
 9712    }
 9713
 9714    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9715        let accent_color = cx.theme().colors().text_accent;
 9716        let editor_bg_color = cx.theme().colors().editor_background;
 9717        editor_bg_color.blend(accent_color.opacity(0.6))
 9718    }
 9719    fn get_prediction_provider_icon_name(
 9720        provider: &Option<RegisteredEditPredictionDelegate>,
 9721    ) -> IconName {
 9722        match provider {
 9723            Some(provider) => match provider.provider.name() {
 9724                "copilot" => IconName::Copilot,
 9725                "supermaven" => IconName::Supermaven,
 9726                _ => IconName::ZedPredict,
 9727            },
 9728            None => IconName::ZedPredict,
 9729        }
 9730    }
 9731
 9732    fn render_edit_prediction_cursor_popover(
 9733        &self,
 9734        min_width: Pixels,
 9735        max_width: Pixels,
 9736        cursor_point: Point,
 9737        style: &EditorStyle,
 9738        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9739        _window: &Window,
 9740        cx: &mut Context<Editor>,
 9741    ) -> Option<AnyElement> {
 9742        let provider = self.edit_prediction_provider.as_ref()?;
 9743        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9744
 9745        let is_refreshing = provider.provider.is_refreshing(cx);
 9746
 9747        fn pending_completion_container(icon: IconName) -> Div {
 9748            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9749        }
 9750
 9751        let completion = match &self.active_edit_prediction {
 9752            Some(prediction) => {
 9753                if !self.has_visible_completions_menu() {
 9754                    const RADIUS: Pixels = px(6.);
 9755                    const BORDER_WIDTH: Pixels = px(1.);
 9756
 9757                    return Some(
 9758                        h_flex()
 9759                            .elevation_2(cx)
 9760                            .border(BORDER_WIDTH)
 9761                            .border_color(cx.theme().colors().border)
 9762                            .when(accept_keystroke.is_none(), |el| {
 9763                                el.border_color(cx.theme().status().error)
 9764                            })
 9765                            .rounded(RADIUS)
 9766                            .rounded_tl(px(0.))
 9767                            .overflow_hidden()
 9768                            .child(div().px_1p5().child(match &prediction.completion {
 9769                                EditPrediction::MoveWithin { target, snapshot } => {
 9770                                    use text::ToPoint as _;
 9771                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9772                                    {
 9773                                        Icon::new(IconName::ZedPredictDown)
 9774                                    } else {
 9775                                        Icon::new(IconName::ZedPredictUp)
 9776                                    }
 9777                                }
 9778                                EditPrediction::MoveOutside { .. } => {
 9779                                    // TODO [zeta2] custom icon for external jump?
 9780                                    Icon::new(provider_icon)
 9781                                }
 9782                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9783                            }))
 9784                            .child(
 9785                                h_flex()
 9786                                    .gap_1()
 9787                                    .py_1()
 9788                                    .px_2()
 9789                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9790                                    .border_l_1()
 9791                                    .border_color(cx.theme().colors().border)
 9792                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9793                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9794                                        el.child(
 9795                                            Label::new("Hold")
 9796                                                .size(LabelSize::Small)
 9797                                                .when(accept_keystroke.is_none(), |el| {
 9798                                                    el.strikethrough()
 9799                                                })
 9800                                                .line_height_style(LineHeightStyle::UiLabel),
 9801                                        )
 9802                                    })
 9803                                    .id("edit_prediction_cursor_popover_keybind")
 9804                                    .when(accept_keystroke.is_none(), |el| {
 9805                                        let status_colors = cx.theme().status();
 9806
 9807                                        el.bg(status_colors.error_background)
 9808                                            .border_color(status_colors.error.opacity(0.6))
 9809                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9810                                            .cursor_default()
 9811                                            .hoverable_tooltip(move |_window, cx| {
 9812                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9813                                                    .into()
 9814                                            })
 9815                                    })
 9816                                    .when_some(
 9817                                        accept_keystroke.as_ref(),
 9818                                        |el, accept_keystroke| {
 9819                                            el.child(h_flex().children(ui::render_modifiers(
 9820                                                accept_keystroke.modifiers(),
 9821                                                PlatformStyle::platform(),
 9822                                                Some(Color::Default),
 9823                                                Some(IconSize::XSmall.rems().into()),
 9824                                                false,
 9825                                            )))
 9826                                        },
 9827                                    ),
 9828                            )
 9829                            .into_any(),
 9830                    );
 9831                }
 9832
 9833                self.render_edit_prediction_cursor_popover_preview(
 9834                    prediction,
 9835                    cursor_point,
 9836                    style,
 9837                    cx,
 9838                )?
 9839            }
 9840
 9841            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9842                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9843                    stale_completion,
 9844                    cursor_point,
 9845                    style,
 9846                    cx,
 9847                )?,
 9848
 9849                None => pending_completion_container(provider_icon)
 9850                    .child(Label::new("...").size(LabelSize::Small)),
 9851            },
 9852
 9853            None => pending_completion_container(provider_icon)
 9854                .child(Label::new("...").size(LabelSize::Small)),
 9855        };
 9856
 9857        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9858            completion
 9859                .with_animation(
 9860                    "loading-completion",
 9861                    Animation::new(Duration::from_secs(2))
 9862                        .repeat()
 9863                        .with_easing(pulsating_between(0.4, 0.8)),
 9864                    |label, delta| label.opacity(delta),
 9865                )
 9866                .into_any_element()
 9867        } else {
 9868            completion.into_any_element()
 9869        };
 9870
 9871        let has_completion = self.active_edit_prediction.is_some();
 9872
 9873        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9874        Some(
 9875            h_flex()
 9876                .min_w(min_width)
 9877                .max_w(max_width)
 9878                .flex_1()
 9879                .elevation_2(cx)
 9880                .border_color(cx.theme().colors().border)
 9881                .child(
 9882                    div()
 9883                        .flex_1()
 9884                        .py_1()
 9885                        .px_2()
 9886                        .overflow_hidden()
 9887                        .child(completion),
 9888                )
 9889                .when_some(accept_keystroke, |el, accept_keystroke| {
 9890                    if !accept_keystroke.modifiers().modified() {
 9891                        return el;
 9892                    }
 9893
 9894                    el.child(
 9895                        h_flex()
 9896                            .h_full()
 9897                            .border_l_1()
 9898                            .rounded_r_lg()
 9899                            .border_color(cx.theme().colors().border)
 9900                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9901                            .gap_1()
 9902                            .py_1()
 9903                            .px_2()
 9904                            .child(
 9905                                h_flex()
 9906                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9907                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9908                                    .child(h_flex().children(ui::render_modifiers(
 9909                                        accept_keystroke.modifiers(),
 9910                                        PlatformStyle::platform(),
 9911                                        Some(if !has_completion {
 9912                                            Color::Muted
 9913                                        } else {
 9914                                            Color::Default
 9915                                        }),
 9916                                        None,
 9917                                        false,
 9918                                    ))),
 9919                            )
 9920                            .child(Label::new("Preview").into_any_element())
 9921                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9922                    )
 9923                })
 9924                .into_any(),
 9925        )
 9926    }
 9927
 9928    fn render_edit_prediction_cursor_popover_preview(
 9929        &self,
 9930        completion: &EditPredictionState,
 9931        cursor_point: Point,
 9932        style: &EditorStyle,
 9933        cx: &mut Context<Editor>,
 9934    ) -> Option<Div> {
 9935        use text::ToPoint as _;
 9936
 9937        fn render_relative_row_jump(
 9938            prefix: impl Into<String>,
 9939            current_row: u32,
 9940            target_row: u32,
 9941        ) -> Div {
 9942            let (row_diff, arrow) = if target_row < current_row {
 9943                (current_row - target_row, IconName::ArrowUp)
 9944            } else {
 9945                (target_row - current_row, IconName::ArrowDown)
 9946            };
 9947
 9948            h_flex()
 9949                .child(
 9950                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9951                        .color(Color::Muted)
 9952                        .size(LabelSize::Small),
 9953                )
 9954                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9955        }
 9956
 9957        let supports_jump = self
 9958            .edit_prediction_provider
 9959            .as_ref()
 9960            .map(|provider| provider.provider.supports_jump_to_edit())
 9961            .unwrap_or(true);
 9962
 9963        match &completion.completion {
 9964            EditPrediction::MoveWithin {
 9965                target, snapshot, ..
 9966            } => {
 9967                if !supports_jump {
 9968                    return None;
 9969                }
 9970
 9971                Some(
 9972                    h_flex()
 9973                        .px_2()
 9974                        .gap_2()
 9975                        .flex_1()
 9976                        .child(
 9977                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9978                                Icon::new(IconName::ZedPredictDown)
 9979                            } else {
 9980                                Icon::new(IconName::ZedPredictUp)
 9981                            },
 9982                        )
 9983                        .child(Label::new("Jump to Edit")),
 9984                )
 9985            }
 9986            EditPrediction::MoveOutside { snapshot, .. } => {
 9987                let file_name = snapshot
 9988                    .file()
 9989                    .map(|file| file.file_name(cx))
 9990                    .unwrap_or("untitled");
 9991                Some(
 9992                    h_flex()
 9993                        .px_2()
 9994                        .gap_2()
 9995                        .flex_1()
 9996                        .child(Icon::new(IconName::ZedPredict))
 9997                        .child(Label::new(format!("Jump to {file_name}"))),
 9998                )
 9999            }
10000            EditPrediction::Edit {
10001                edits,
10002                edit_preview,
10003                snapshot,
10004                display_mode: _,
10005            } => {
10006                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10007
10008                let (highlighted_edits, has_more_lines) =
10009                    if let Some(edit_preview) = edit_preview.as_ref() {
10010                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10011                            .first_line_preview()
10012                    } else {
10013                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10014                    };
10015
10016                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10017                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10018
10019                let preview = h_flex()
10020                    .gap_1()
10021                    .min_w_16()
10022                    .child(styled_text)
10023                    .when(has_more_lines, |parent| parent.child(""));
10024
10025                let left = if supports_jump && first_edit_row != cursor_point.row {
10026                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10027                        .into_any_element()
10028                } else {
10029                    let icon_name =
10030                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10031                    Icon::new(icon_name).into_any_element()
10032                };
10033
10034                Some(
10035                    h_flex()
10036                        .h_full()
10037                        .flex_1()
10038                        .gap_2()
10039                        .pr_1()
10040                        .overflow_x_hidden()
10041                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10042                        .child(left)
10043                        .child(preview),
10044                )
10045            }
10046        }
10047    }
10048
10049    pub fn render_context_menu(
10050        &mut self,
10051        max_height_in_lines: u32,
10052        window: &mut Window,
10053        cx: &mut Context<Editor>,
10054    ) -> Option<AnyElement> {
10055        let menu = self.context_menu.borrow();
10056        let menu = menu.as_ref()?;
10057        if !menu.visible() {
10058            return None;
10059        };
10060        self.style
10061            .as_ref()
10062            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10063    }
10064
10065    fn render_context_menu_aside(
10066        &mut self,
10067        max_size: Size<Pixels>,
10068        window: &mut Window,
10069        cx: &mut Context<Editor>,
10070    ) -> Option<AnyElement> {
10071        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10072            if menu.visible() {
10073                menu.render_aside(max_size, window, cx)
10074            } else {
10075                None
10076            }
10077        })
10078    }
10079
10080    fn hide_context_menu(
10081        &mut self,
10082        window: &mut Window,
10083        cx: &mut Context<Self>,
10084    ) -> Option<CodeContextMenu> {
10085        cx.notify();
10086        self.completion_tasks.clear();
10087        let context_menu = self.context_menu.borrow_mut().take();
10088        self.stale_edit_prediction_in_menu.take();
10089        self.update_visible_edit_prediction(window, cx);
10090        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10091            && let Some(completion_provider) = &self.completion_provider
10092        {
10093            completion_provider.selection_changed(None, window, cx);
10094        }
10095        context_menu
10096    }
10097
10098    fn show_snippet_choices(
10099        &mut self,
10100        choices: &Vec<String>,
10101        selection: Range<Anchor>,
10102        cx: &mut Context<Self>,
10103    ) {
10104        let Some((_, buffer, _)) = self
10105            .buffer()
10106            .read(cx)
10107            .excerpt_containing(selection.start, cx)
10108        else {
10109            return;
10110        };
10111        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10112        else {
10113            return;
10114        };
10115        if buffer != end_buffer {
10116            log::error!("expected anchor range to have matching buffer IDs");
10117            return;
10118        }
10119
10120        let id = post_inc(&mut self.next_completion_id);
10121        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10122        let mut context_menu = self.context_menu.borrow_mut();
10123        let old_menu = context_menu.take();
10124        *context_menu = Some(CodeContextMenu::Completions(
10125            CompletionsMenu::new_snippet_choices(
10126                id,
10127                true,
10128                choices,
10129                selection,
10130                buffer,
10131                old_menu.map(|menu| menu.primary_scroll_handle()),
10132                snippet_sort_order,
10133            ),
10134        ));
10135    }
10136
10137    pub fn insert_snippet(
10138        &mut self,
10139        insertion_ranges: &[Range<MultiBufferOffset>],
10140        snippet: Snippet,
10141        window: &mut Window,
10142        cx: &mut Context<Self>,
10143    ) -> Result<()> {
10144        struct Tabstop<T> {
10145            is_end_tabstop: bool,
10146            ranges: Vec<Range<T>>,
10147            choices: Option<Vec<String>>,
10148        }
10149
10150        let tabstops = self.buffer.update(cx, |buffer, cx| {
10151            let snippet_text: Arc<str> = snippet.text.clone().into();
10152            let edits = insertion_ranges
10153                .iter()
10154                .cloned()
10155                .map(|range| (range, snippet_text.clone()));
10156            let autoindent_mode = AutoindentMode::Block {
10157                original_indent_columns: Vec::new(),
10158            };
10159            buffer.edit(edits, Some(autoindent_mode), cx);
10160
10161            let snapshot = &*buffer.read(cx);
10162            let snippet = &snippet;
10163            snippet
10164                .tabstops
10165                .iter()
10166                .map(|tabstop| {
10167                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10168                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10169                    });
10170                    let mut tabstop_ranges = tabstop
10171                        .ranges
10172                        .iter()
10173                        .flat_map(|tabstop_range| {
10174                            let mut delta = 0_isize;
10175                            insertion_ranges.iter().map(move |insertion_range| {
10176                                let insertion_start = insertion_range.start + delta;
10177                                delta += snippet.text.len() as isize
10178                                    - (insertion_range.end - insertion_range.start) as isize;
10179
10180                                let start =
10181                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10182                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10183                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10184                            })
10185                        })
10186                        .collect::<Vec<_>>();
10187                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10188
10189                    Tabstop {
10190                        is_end_tabstop,
10191                        ranges: tabstop_ranges,
10192                        choices: tabstop.choices.clone(),
10193                    }
10194                })
10195                .collect::<Vec<_>>()
10196        });
10197        if let Some(tabstop) = tabstops.first() {
10198            self.change_selections(Default::default(), window, cx, |s| {
10199                // Reverse order so that the first range is the newest created selection.
10200                // Completions will use it and autoscroll will prioritize it.
10201                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10202            });
10203
10204            if let Some(choices) = &tabstop.choices
10205                && let Some(selection) = tabstop.ranges.first()
10206            {
10207                self.show_snippet_choices(choices, selection.clone(), cx)
10208            }
10209
10210            // If we're already at the last tabstop and it's at the end of the snippet,
10211            // we're done, we don't need to keep the state around.
10212            if !tabstop.is_end_tabstop {
10213                let choices = tabstops
10214                    .iter()
10215                    .map(|tabstop| tabstop.choices.clone())
10216                    .collect();
10217
10218                let ranges = tabstops
10219                    .into_iter()
10220                    .map(|tabstop| tabstop.ranges)
10221                    .collect::<Vec<_>>();
10222
10223                self.snippet_stack.push(SnippetState {
10224                    active_index: 0,
10225                    ranges,
10226                    choices,
10227                });
10228            }
10229
10230            // Check whether the just-entered snippet ends with an auto-closable bracket.
10231            if self.autoclose_regions.is_empty() {
10232                let snapshot = self.buffer.read(cx).snapshot(cx);
10233                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10234                    let selection_head = selection.head();
10235                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10236                        continue;
10237                    };
10238
10239                    let mut bracket_pair = None;
10240                    let max_lookup_length = scope
10241                        .brackets()
10242                        .map(|(pair, _)| {
10243                            pair.start
10244                                .as_str()
10245                                .chars()
10246                                .count()
10247                                .max(pair.end.as_str().chars().count())
10248                        })
10249                        .max();
10250                    if let Some(max_lookup_length) = max_lookup_length {
10251                        let next_text = snapshot
10252                            .chars_at(selection_head)
10253                            .take(max_lookup_length)
10254                            .collect::<String>();
10255                        let prev_text = snapshot
10256                            .reversed_chars_at(selection_head)
10257                            .take(max_lookup_length)
10258                            .collect::<String>();
10259
10260                        for (pair, enabled) in scope.brackets() {
10261                            if enabled
10262                                && pair.close
10263                                && prev_text.starts_with(pair.start.as_str())
10264                                && next_text.starts_with(pair.end.as_str())
10265                            {
10266                                bracket_pair = Some(pair.clone());
10267                                break;
10268                            }
10269                        }
10270                    }
10271
10272                    if let Some(pair) = bracket_pair {
10273                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10274                        let autoclose_enabled =
10275                            self.use_autoclose && snapshot_settings.use_autoclose;
10276                        if autoclose_enabled {
10277                            let start = snapshot.anchor_after(selection_head);
10278                            let end = snapshot.anchor_after(selection_head);
10279                            self.autoclose_regions.push(AutocloseRegion {
10280                                selection_id: selection.id,
10281                                range: start..end,
10282                                pair,
10283                            });
10284                        }
10285                    }
10286                }
10287            }
10288        }
10289        Ok(())
10290    }
10291
10292    pub fn move_to_next_snippet_tabstop(
10293        &mut self,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) -> bool {
10297        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10298    }
10299
10300    pub fn move_to_prev_snippet_tabstop(
10301        &mut self,
10302        window: &mut Window,
10303        cx: &mut Context<Self>,
10304    ) -> bool {
10305        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10306    }
10307
10308    pub fn move_to_snippet_tabstop(
10309        &mut self,
10310        bias: Bias,
10311        window: &mut Window,
10312        cx: &mut Context<Self>,
10313    ) -> bool {
10314        if let Some(mut snippet) = self.snippet_stack.pop() {
10315            match bias {
10316                Bias::Left => {
10317                    if snippet.active_index > 0 {
10318                        snippet.active_index -= 1;
10319                    } else {
10320                        self.snippet_stack.push(snippet);
10321                        return false;
10322                    }
10323                }
10324                Bias::Right => {
10325                    if snippet.active_index + 1 < snippet.ranges.len() {
10326                        snippet.active_index += 1;
10327                    } else {
10328                        self.snippet_stack.push(snippet);
10329                        return false;
10330                    }
10331                }
10332            }
10333            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10334                self.change_selections(Default::default(), window, cx, |s| {
10335                    // Reverse order so that the first range is the newest created selection.
10336                    // Completions will use it and autoscroll will prioritize it.
10337                    s.select_ranges(current_ranges.iter().rev().cloned())
10338                });
10339
10340                if let Some(choices) = &snippet.choices[snippet.active_index]
10341                    && let Some(selection) = current_ranges.first()
10342                {
10343                    self.show_snippet_choices(choices, selection.clone(), cx);
10344                }
10345
10346                // If snippet state is not at the last tabstop, push it back on the stack
10347                if snippet.active_index + 1 < snippet.ranges.len() {
10348                    self.snippet_stack.push(snippet);
10349                }
10350                return true;
10351            }
10352        }
10353
10354        false
10355    }
10356
10357    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10358        self.transact(window, cx, |this, window, cx| {
10359            this.select_all(&SelectAll, window, cx);
10360            this.insert("", window, cx);
10361        });
10362    }
10363
10364    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10365        if self.read_only(cx) {
10366            return;
10367        }
10368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10369        self.transact(window, cx, |this, window, cx| {
10370            this.select_autoclose_pair(window, cx);
10371
10372            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10373
10374            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10375            if !this.linked_edit_ranges.is_empty() {
10376                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10377                let snapshot = this.buffer.read(cx).snapshot(cx);
10378
10379                for selection in selections.iter() {
10380                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10381                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10382                    if selection_start.buffer_id != selection_end.buffer_id {
10383                        continue;
10384                    }
10385                    if let Some(ranges) =
10386                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10387                    {
10388                        for (buffer, entries) in ranges {
10389                            linked_ranges.entry(buffer).or_default().extend(entries);
10390                        }
10391                    }
10392                }
10393            }
10394
10395            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10396            for selection in &mut selections {
10397                if selection.is_empty() {
10398                    let old_head = selection.head();
10399                    let mut new_head =
10400                        movement::left(&display_map, old_head.to_display_point(&display_map))
10401                            .to_point(&display_map);
10402                    if let Some((buffer, line_buffer_range)) = display_map
10403                        .buffer_snapshot()
10404                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10405                    {
10406                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10407                        let indent_len = match indent_size.kind {
10408                            IndentKind::Space => {
10409                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10410                            }
10411                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10412                        };
10413                        if old_head.column <= indent_size.len && old_head.column > 0 {
10414                            let indent_len = indent_len.get();
10415                            new_head = cmp::min(
10416                                new_head,
10417                                MultiBufferPoint::new(
10418                                    old_head.row,
10419                                    ((old_head.column - 1) / indent_len) * indent_len,
10420                                ),
10421                            );
10422                        }
10423                    }
10424
10425                    selection.set_head(new_head, SelectionGoal::None);
10426                }
10427            }
10428
10429            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10430            this.insert("", window, cx);
10431            let empty_str: Arc<str> = Arc::from("");
10432            for (buffer, edits) in linked_ranges {
10433                let snapshot = buffer.read(cx).snapshot();
10434                use text::ToPoint as TP;
10435
10436                let edits = edits
10437                    .into_iter()
10438                    .map(|range| {
10439                        let end_point = TP::to_point(&range.end, &snapshot);
10440                        let mut start_point = TP::to_point(&range.start, &snapshot);
10441
10442                        if end_point == start_point {
10443                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10444                                .saturating_sub(1);
10445                            start_point =
10446                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10447                        };
10448
10449                        (start_point..end_point, empty_str.clone())
10450                    })
10451                    .sorted_by_key(|(range, _)| range.start)
10452                    .collect::<Vec<_>>();
10453                buffer.update(cx, |this, cx| {
10454                    this.edit(edits, None, cx);
10455                })
10456            }
10457            this.refresh_edit_prediction(true, false, window, cx);
10458            refresh_linked_ranges(this, window, cx);
10459        });
10460    }
10461
10462    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10463        if self.read_only(cx) {
10464            return;
10465        }
10466        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10467        self.transact(window, cx, |this, window, cx| {
10468            this.change_selections(Default::default(), window, cx, |s| {
10469                s.move_with(|map, selection| {
10470                    if selection.is_empty() {
10471                        let cursor = movement::right(map, selection.head());
10472                        selection.end = cursor;
10473                        selection.reversed = true;
10474                        selection.goal = SelectionGoal::None;
10475                    }
10476                })
10477            });
10478            this.insert("", window, cx);
10479            this.refresh_edit_prediction(true, false, window, cx);
10480        });
10481    }
10482
10483    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10484        if self.mode.is_single_line() {
10485            cx.propagate();
10486            return;
10487        }
10488
10489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10490        if self.move_to_prev_snippet_tabstop(window, cx) {
10491            return;
10492        }
10493        self.outdent(&Outdent, window, cx);
10494    }
10495
10496    pub fn next_snippet_tabstop(
10497        &mut self,
10498        _: &NextSnippetTabstop,
10499        window: &mut Window,
10500        cx: &mut Context<Self>,
10501    ) {
10502        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10503            cx.propagate();
10504            return;
10505        }
10506
10507        if self.move_to_next_snippet_tabstop(window, cx) {
10508            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10509            return;
10510        }
10511        cx.propagate();
10512    }
10513
10514    pub fn previous_snippet_tabstop(
10515        &mut self,
10516        _: &PreviousSnippetTabstop,
10517        window: &mut Window,
10518        cx: &mut Context<Self>,
10519    ) {
10520        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10521            cx.propagate();
10522            return;
10523        }
10524
10525        if self.move_to_prev_snippet_tabstop(window, cx) {
10526            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10527            return;
10528        }
10529        cx.propagate();
10530    }
10531
10532    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10533        if self.mode.is_single_line() {
10534            cx.propagate();
10535            return;
10536        }
10537
10538        if self.move_to_next_snippet_tabstop(window, cx) {
10539            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10540            return;
10541        }
10542        if self.read_only(cx) {
10543            return;
10544        }
10545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10546        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10547        let buffer = self.buffer.read(cx);
10548        let snapshot = buffer.snapshot(cx);
10549        let rows_iter = selections.iter().map(|s| s.head().row);
10550        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10551
10552        let has_some_cursor_in_whitespace = selections
10553            .iter()
10554            .filter(|selection| selection.is_empty())
10555            .any(|selection| {
10556                let cursor = selection.head();
10557                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10558                cursor.column < current_indent.len
10559            });
10560
10561        let mut edits = Vec::new();
10562        let mut prev_edited_row = 0;
10563        let mut row_delta = 0;
10564        for selection in &mut selections {
10565            if selection.start.row != prev_edited_row {
10566                row_delta = 0;
10567            }
10568            prev_edited_row = selection.end.row;
10569
10570            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10571            if selection.is_empty() {
10572                let cursor = selection.head();
10573                let settings = buffer.language_settings_at(cursor, cx);
10574                if settings.indent_list_on_tab {
10575                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10576                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10577                            row_delta = Self::indent_selection(
10578                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10579                            );
10580                            continue;
10581                        }
10582                    }
10583                }
10584            }
10585
10586            // If the selection is non-empty, then increase the indentation of the selected lines.
10587            if !selection.is_empty() {
10588                row_delta =
10589                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10590                continue;
10591            }
10592
10593            let cursor = selection.head();
10594            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10595            if let Some(suggested_indent) =
10596                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10597            {
10598                // Don't do anything if already at suggested indent
10599                // and there is any other cursor which is not
10600                if has_some_cursor_in_whitespace
10601                    && cursor.column == current_indent.len
10602                    && current_indent.len == suggested_indent.len
10603                {
10604                    continue;
10605                }
10606
10607                // Adjust line and move cursor to suggested indent
10608                // if cursor is not at suggested indent
10609                if cursor.column < suggested_indent.len
10610                    && cursor.column <= current_indent.len
10611                    && current_indent.len <= suggested_indent.len
10612                {
10613                    selection.start = Point::new(cursor.row, suggested_indent.len);
10614                    selection.end = selection.start;
10615                    if row_delta == 0 {
10616                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10617                            cursor.row,
10618                            current_indent,
10619                            suggested_indent,
10620                        ));
10621                        row_delta = suggested_indent.len - current_indent.len;
10622                    }
10623                    continue;
10624                }
10625
10626                // If current indent is more than suggested indent
10627                // only move cursor to current indent and skip indent
10628                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10629                    selection.start = Point::new(cursor.row, current_indent.len);
10630                    selection.end = selection.start;
10631                    continue;
10632                }
10633            }
10634
10635            // Otherwise, insert a hard or soft tab.
10636            let settings = buffer.language_settings_at(cursor, cx);
10637            let tab_size = if settings.hard_tabs {
10638                IndentSize::tab()
10639            } else {
10640                let tab_size = settings.tab_size.get();
10641                let indent_remainder = snapshot
10642                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10643                    .flat_map(str::chars)
10644                    .fold(row_delta % tab_size, |counter: u32, c| {
10645                        if c == '\t' {
10646                            0
10647                        } else {
10648                            (counter + 1) % tab_size
10649                        }
10650                    });
10651
10652                let chars_to_next_tab_stop = tab_size - indent_remainder;
10653                IndentSize::spaces(chars_to_next_tab_stop)
10654            };
10655            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10656            selection.end = selection.start;
10657            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10658            row_delta += tab_size.len;
10659        }
10660
10661        self.transact(window, cx, |this, window, cx| {
10662            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10663            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10664            this.refresh_edit_prediction(true, false, window, cx);
10665        });
10666    }
10667
10668    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10669        if self.read_only(cx) {
10670            return;
10671        }
10672        if self.mode.is_single_line() {
10673            cx.propagate();
10674            return;
10675        }
10676
10677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10678        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10679        let mut prev_edited_row = 0;
10680        let mut row_delta = 0;
10681        let mut edits = Vec::new();
10682        let buffer = self.buffer.read(cx);
10683        let snapshot = buffer.snapshot(cx);
10684        for selection in &mut selections {
10685            if selection.start.row != prev_edited_row {
10686                row_delta = 0;
10687            }
10688            prev_edited_row = selection.end.row;
10689
10690            row_delta =
10691                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10692        }
10693
10694        self.transact(window, cx, |this, window, cx| {
10695            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10696            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10697        });
10698    }
10699
10700    fn indent_selection(
10701        buffer: &MultiBuffer,
10702        snapshot: &MultiBufferSnapshot,
10703        selection: &mut Selection<Point>,
10704        edits: &mut Vec<(Range<Point>, String)>,
10705        delta_for_start_row: u32,
10706        cx: &App,
10707    ) -> u32 {
10708        let settings = buffer.language_settings_at(selection.start, cx);
10709        let tab_size = settings.tab_size.get();
10710        let indent_kind = if settings.hard_tabs {
10711            IndentKind::Tab
10712        } else {
10713            IndentKind::Space
10714        };
10715        let mut start_row = selection.start.row;
10716        let mut end_row = selection.end.row + 1;
10717
10718        // If a selection ends at the beginning of a line, don't indent
10719        // that last line.
10720        if selection.end.column == 0 && selection.end.row > selection.start.row {
10721            end_row -= 1;
10722        }
10723
10724        // Avoid re-indenting a row that has already been indented by a
10725        // previous selection, but still update this selection's column
10726        // to reflect that indentation.
10727        if delta_for_start_row > 0 {
10728            start_row += 1;
10729            selection.start.column += delta_for_start_row;
10730            if selection.end.row == selection.start.row {
10731                selection.end.column += delta_for_start_row;
10732            }
10733        }
10734
10735        let mut delta_for_end_row = 0;
10736        let has_multiple_rows = start_row + 1 != end_row;
10737        for row in start_row..end_row {
10738            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10739            let indent_delta = match (current_indent.kind, indent_kind) {
10740                (IndentKind::Space, IndentKind::Space) => {
10741                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10742                    IndentSize::spaces(columns_to_next_tab_stop)
10743                }
10744                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10745                (_, IndentKind::Tab) => IndentSize::tab(),
10746            };
10747
10748            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10749                0
10750            } else {
10751                selection.start.column
10752            };
10753            let row_start = Point::new(row, start);
10754            edits.push((
10755                row_start..row_start,
10756                indent_delta.chars().collect::<String>(),
10757            ));
10758
10759            // Update this selection's endpoints to reflect the indentation.
10760            if row == selection.start.row {
10761                selection.start.column += indent_delta.len;
10762            }
10763            if row == selection.end.row {
10764                selection.end.column += indent_delta.len;
10765                delta_for_end_row = indent_delta.len;
10766            }
10767        }
10768
10769        if selection.start.row == selection.end.row {
10770            delta_for_start_row + delta_for_end_row
10771        } else {
10772            delta_for_end_row
10773        }
10774    }
10775
10776    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10777        if self.read_only(cx) {
10778            return;
10779        }
10780        if self.mode.is_single_line() {
10781            cx.propagate();
10782            return;
10783        }
10784
10785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10786        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10787        let selections = self.selections.all::<Point>(&display_map);
10788        let mut deletion_ranges = Vec::new();
10789        let mut last_outdent = None;
10790        {
10791            let buffer = self.buffer.read(cx);
10792            let snapshot = buffer.snapshot(cx);
10793            for selection in &selections {
10794                let settings = buffer.language_settings_at(selection.start, cx);
10795                let tab_size = settings.tab_size.get();
10796                let mut rows = selection.spanned_rows(false, &display_map);
10797
10798                // Avoid re-outdenting a row that has already been outdented by a
10799                // previous selection.
10800                if let Some(last_row) = last_outdent
10801                    && last_row == rows.start
10802                {
10803                    rows.start = rows.start.next_row();
10804                }
10805                let has_multiple_rows = rows.len() > 1;
10806                for row in rows.iter_rows() {
10807                    let indent_size = snapshot.indent_size_for_line(row);
10808                    if indent_size.len > 0 {
10809                        let deletion_len = match indent_size.kind {
10810                            IndentKind::Space => {
10811                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10812                                if columns_to_prev_tab_stop == 0 {
10813                                    tab_size
10814                                } else {
10815                                    columns_to_prev_tab_stop
10816                                }
10817                            }
10818                            IndentKind::Tab => 1,
10819                        };
10820                        let start = if has_multiple_rows
10821                            || deletion_len > selection.start.column
10822                            || indent_size.len < selection.start.column
10823                        {
10824                            0
10825                        } else {
10826                            selection.start.column - deletion_len
10827                        };
10828                        deletion_ranges.push(
10829                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10830                        );
10831                        last_outdent = Some(row);
10832                    }
10833                }
10834            }
10835        }
10836
10837        self.transact(window, cx, |this, window, cx| {
10838            this.buffer.update(cx, |buffer, cx| {
10839                let empty_str: Arc<str> = Arc::default();
10840                buffer.edit(
10841                    deletion_ranges
10842                        .into_iter()
10843                        .map(|range| (range, empty_str.clone())),
10844                    None,
10845                    cx,
10846                );
10847            });
10848            let selections = this
10849                .selections
10850                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10851            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10852        });
10853    }
10854
10855    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10856        if self.read_only(cx) {
10857            return;
10858        }
10859        if self.mode.is_single_line() {
10860            cx.propagate();
10861            return;
10862        }
10863
10864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10865        let selections = self
10866            .selections
10867            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10868            .into_iter()
10869            .map(|s| s.range());
10870
10871        self.transact(window, cx, |this, window, cx| {
10872            this.buffer.update(cx, |buffer, cx| {
10873                buffer.autoindent_ranges(selections, cx);
10874            });
10875            let selections = this
10876                .selections
10877                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10878            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10879        });
10880    }
10881
10882    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10885        let selections = self.selections.all::<Point>(&display_map);
10886
10887        let mut new_cursors = Vec::new();
10888        let mut edit_ranges = Vec::new();
10889        let mut selections = selections.iter().peekable();
10890        while let Some(selection) = selections.next() {
10891            let mut rows = selection.spanned_rows(false, &display_map);
10892
10893            // Accumulate contiguous regions of rows that we want to delete.
10894            while let Some(next_selection) = selections.peek() {
10895                let next_rows = next_selection.spanned_rows(false, &display_map);
10896                if next_rows.start <= rows.end {
10897                    rows.end = next_rows.end;
10898                    selections.next().unwrap();
10899                } else {
10900                    break;
10901                }
10902            }
10903
10904            let buffer = display_map.buffer_snapshot();
10905            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10906            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10907                // If there's a line after the range, delete the \n from the end of the row range
10908                (
10909                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10910                    rows.end,
10911                )
10912            } else {
10913                // If there isn't a line after the range, delete the \n from the line before the
10914                // start of the row range
10915                edit_start = edit_start.saturating_sub_usize(1);
10916                (buffer.len(), rows.start.previous_row())
10917            };
10918
10919            let text_layout_details = self.text_layout_details(window);
10920            let x = display_map.x_for_display_point(
10921                selection.head().to_display_point(&display_map),
10922                &text_layout_details,
10923            );
10924            let row = Point::new(target_row.0, 0)
10925                .to_display_point(&display_map)
10926                .row();
10927            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10928
10929            new_cursors.push((
10930                selection.id,
10931                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10932                SelectionGoal::None,
10933            ));
10934            edit_ranges.push(edit_start..edit_end);
10935        }
10936
10937        self.transact(window, cx, |this, window, cx| {
10938            let buffer = this.buffer.update(cx, |buffer, cx| {
10939                let empty_str: Arc<str> = Arc::default();
10940                buffer.edit(
10941                    edit_ranges
10942                        .into_iter()
10943                        .map(|range| (range, empty_str.clone())),
10944                    None,
10945                    cx,
10946                );
10947                buffer.snapshot(cx)
10948            });
10949            let new_selections = new_cursors
10950                .into_iter()
10951                .map(|(id, cursor, goal)| {
10952                    let cursor = cursor.to_point(&buffer);
10953                    Selection {
10954                        id,
10955                        start: cursor,
10956                        end: cursor,
10957                        reversed: false,
10958                        goal,
10959                    }
10960                })
10961                .collect();
10962
10963            this.change_selections(Default::default(), window, cx, |s| {
10964                s.select(new_selections);
10965            });
10966        });
10967    }
10968
10969    pub fn join_lines_impl(
10970        &mut self,
10971        insert_whitespace: bool,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) {
10975        if self.read_only(cx) {
10976            return;
10977        }
10978        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10979        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10980            let start = MultiBufferRow(selection.start.row);
10981            // Treat single line selections as if they include the next line. Otherwise this action
10982            // would do nothing for single line selections individual cursors.
10983            let end = if selection.start.row == selection.end.row {
10984                MultiBufferRow(selection.start.row + 1)
10985            } else {
10986                MultiBufferRow(selection.end.row)
10987            };
10988
10989            if let Some(last_row_range) = row_ranges.last_mut()
10990                && start <= last_row_range.end
10991            {
10992                last_row_range.end = end;
10993                continue;
10994            }
10995            row_ranges.push(start..end);
10996        }
10997
10998        let snapshot = self.buffer.read(cx).snapshot(cx);
10999        let mut cursor_positions = Vec::new();
11000        for row_range in &row_ranges {
11001            let anchor = snapshot.anchor_before(Point::new(
11002                row_range.end.previous_row().0,
11003                snapshot.line_len(row_range.end.previous_row()),
11004            ));
11005            cursor_positions.push(anchor..anchor);
11006        }
11007
11008        self.transact(window, cx, |this, window, cx| {
11009            for row_range in row_ranges.into_iter().rev() {
11010                for row in row_range.iter_rows().rev() {
11011                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11012                    let next_line_row = row.next_row();
11013                    let indent = snapshot.indent_size_for_line(next_line_row);
11014                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11015
11016                    let replace =
11017                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11018                            " "
11019                        } else {
11020                            ""
11021                        };
11022
11023                    this.buffer.update(cx, |buffer, cx| {
11024                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11025                    });
11026                }
11027            }
11028
11029            this.change_selections(Default::default(), window, cx, |s| {
11030                s.select_anchor_ranges(cursor_positions)
11031            });
11032        });
11033    }
11034
11035    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11037        self.join_lines_impl(true, window, cx);
11038    }
11039
11040    pub fn sort_lines_case_sensitive(
11041        &mut self,
11042        _: &SortLinesCaseSensitive,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11047    }
11048
11049    pub fn sort_lines_by_length(
11050        &mut self,
11051        _: &SortLinesByLength,
11052        window: &mut Window,
11053        cx: &mut Context<Self>,
11054    ) {
11055        self.manipulate_immutable_lines(window, cx, |lines| {
11056            lines.sort_by_key(|&line| line.chars().count())
11057        })
11058    }
11059
11060    pub fn sort_lines_case_insensitive(
11061        &mut self,
11062        _: &SortLinesCaseInsensitive,
11063        window: &mut Window,
11064        cx: &mut Context<Self>,
11065    ) {
11066        self.manipulate_immutable_lines(window, cx, |lines| {
11067            lines.sort_by_key(|line| line.to_lowercase())
11068        })
11069    }
11070
11071    pub fn unique_lines_case_insensitive(
11072        &mut self,
11073        _: &UniqueLinesCaseInsensitive,
11074        window: &mut Window,
11075        cx: &mut Context<Self>,
11076    ) {
11077        self.manipulate_immutable_lines(window, cx, |lines| {
11078            let mut seen = HashSet::default();
11079            lines.retain(|line| seen.insert(line.to_lowercase()));
11080        })
11081    }
11082
11083    pub fn unique_lines_case_sensitive(
11084        &mut self,
11085        _: &UniqueLinesCaseSensitive,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) {
11089        self.manipulate_immutable_lines(window, cx, |lines| {
11090            let mut seen = HashSet::default();
11091            lines.retain(|line| seen.insert(*line));
11092        })
11093    }
11094
11095    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11096        let snapshot = self.buffer.read(cx).snapshot(cx);
11097        for selection in self.selections.disjoint_anchors_arc().iter() {
11098            if snapshot
11099                .language_at(selection.start)
11100                .and_then(|lang| lang.config().wrap_characters.as_ref())
11101                .is_some()
11102            {
11103                return true;
11104            }
11105        }
11106        false
11107    }
11108
11109    fn wrap_selections_in_tag(
11110        &mut self,
11111        _: &WrapSelectionsInTag,
11112        window: &mut Window,
11113        cx: &mut Context<Self>,
11114    ) {
11115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11116
11117        let snapshot = self.buffer.read(cx).snapshot(cx);
11118
11119        let mut edits = Vec::new();
11120        let mut boundaries = Vec::new();
11121
11122        for selection in self
11123            .selections
11124            .all_adjusted(&self.display_snapshot(cx))
11125            .iter()
11126        {
11127            let Some(wrap_config) = snapshot
11128                .language_at(selection.start)
11129                .and_then(|lang| lang.config().wrap_characters.clone())
11130            else {
11131                continue;
11132            };
11133
11134            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11135            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11136
11137            let start_before = snapshot.anchor_before(selection.start);
11138            let end_after = snapshot.anchor_after(selection.end);
11139
11140            edits.push((start_before..start_before, open_tag));
11141            edits.push((end_after..end_after, close_tag));
11142
11143            boundaries.push((
11144                start_before,
11145                end_after,
11146                wrap_config.start_prefix.len(),
11147                wrap_config.end_suffix.len(),
11148            ));
11149        }
11150
11151        if edits.is_empty() {
11152            return;
11153        }
11154
11155        self.transact(window, cx, |this, window, cx| {
11156            let buffer = this.buffer.update(cx, |buffer, cx| {
11157                buffer.edit(edits, None, cx);
11158                buffer.snapshot(cx)
11159            });
11160
11161            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11162            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11163                boundaries.into_iter()
11164            {
11165                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11166                let close_offset = end_after
11167                    .to_offset(&buffer)
11168                    .saturating_sub_usize(end_suffix_len);
11169                new_selections.push(open_offset..open_offset);
11170                new_selections.push(close_offset..close_offset);
11171            }
11172
11173            this.change_selections(Default::default(), window, cx, |s| {
11174                s.select_ranges(new_selections);
11175            });
11176
11177            this.request_autoscroll(Autoscroll::fit(), cx);
11178        });
11179    }
11180
11181    pub fn toggle_read_only(
11182        &mut self,
11183        _: &workspace::ToggleReadOnlyFile,
11184        _: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11188            buffer.update(cx, |buffer, cx| {
11189                buffer.set_capability(
11190                    match buffer.capability() {
11191                        Capability::ReadWrite => Capability::Read,
11192                        Capability::Read => Capability::ReadWrite,
11193                        Capability::ReadOnly => Capability::ReadOnly,
11194                    },
11195                    cx,
11196                );
11197            })
11198        }
11199    }
11200
11201    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11202        let Some(project) = self.project.clone() else {
11203            return;
11204        };
11205        self.reload(project, window, cx)
11206            .detach_and_notify_err(window, cx);
11207    }
11208
11209    pub fn restore_file(
11210        &mut self,
11211        _: &::git::RestoreFile,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11216        let mut buffer_ids = HashSet::default();
11217        let snapshot = self.buffer().read(cx).snapshot(cx);
11218        for selection in self
11219            .selections
11220            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11221        {
11222            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11223        }
11224
11225        let buffer = self.buffer().read(cx);
11226        let ranges = buffer_ids
11227            .into_iter()
11228            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11229            .collect::<Vec<_>>();
11230
11231        self.restore_hunks_in_ranges(ranges, window, cx);
11232    }
11233
11234    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11236        let selections = self
11237            .selections
11238            .all(&self.display_snapshot(cx))
11239            .into_iter()
11240            .map(|s| s.range())
11241            .collect();
11242        self.restore_hunks_in_ranges(selections, window, cx);
11243    }
11244
11245    pub fn restore_hunks_in_ranges(
11246        &mut self,
11247        ranges: Vec<Range<Point>>,
11248        window: &mut Window,
11249        cx: &mut Context<Editor>,
11250    ) {
11251        let mut revert_changes = HashMap::default();
11252        let chunk_by = self
11253            .snapshot(window, cx)
11254            .hunks_for_ranges(ranges)
11255            .into_iter()
11256            .chunk_by(|hunk| hunk.buffer_id);
11257        for (buffer_id, hunks) in &chunk_by {
11258            let hunks = hunks.collect::<Vec<_>>();
11259            for hunk in &hunks {
11260                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11261            }
11262            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11263        }
11264        drop(chunk_by);
11265        if !revert_changes.is_empty() {
11266            self.transact(window, cx, |editor, window, cx| {
11267                editor.restore(revert_changes, window, cx);
11268            });
11269        }
11270    }
11271
11272    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11273        if let Some(status) = self
11274            .addons
11275            .iter()
11276            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11277        {
11278            return Some(status);
11279        }
11280        self.project
11281            .as_ref()?
11282            .read(cx)
11283            .status_for_buffer_id(buffer_id, cx)
11284    }
11285
11286    pub fn open_active_item_in_terminal(
11287        &mut self,
11288        _: &OpenInTerminal,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11293            let project_path = buffer.read(cx).project_path(cx)?;
11294            let project = self.project()?.read(cx);
11295            let entry = project.entry_for_path(&project_path, cx)?;
11296            let parent = match &entry.canonical_path {
11297                Some(canonical_path) => canonical_path.to_path_buf(),
11298                None => project.absolute_path(&project_path, cx)?,
11299            }
11300            .parent()?
11301            .to_path_buf();
11302            Some(parent)
11303        }) {
11304            window.dispatch_action(
11305                OpenTerminal {
11306                    working_directory,
11307                    local: false,
11308                }
11309                .boxed_clone(),
11310                cx,
11311            );
11312        }
11313    }
11314
11315    fn set_breakpoint_context_menu(
11316        &mut self,
11317        display_row: DisplayRow,
11318        position: Option<Anchor>,
11319        clicked_point: gpui::Point<Pixels>,
11320        window: &mut Window,
11321        cx: &mut Context<Self>,
11322    ) {
11323        let source = self
11324            .buffer
11325            .read(cx)
11326            .snapshot(cx)
11327            .anchor_before(Point::new(display_row.0, 0u32));
11328
11329        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11330
11331        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11332            self,
11333            source,
11334            clicked_point,
11335            context_menu,
11336            window,
11337            cx,
11338        );
11339    }
11340
11341    fn add_edit_breakpoint_block(
11342        &mut self,
11343        anchor: Anchor,
11344        breakpoint: &Breakpoint,
11345        edit_action: BreakpointPromptEditAction,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        let weak_editor = cx.weak_entity();
11350        let bp_prompt = cx.new(|cx| {
11351            BreakpointPromptEditor::new(
11352                weak_editor,
11353                anchor,
11354                breakpoint.clone(),
11355                edit_action,
11356                window,
11357                cx,
11358            )
11359        });
11360
11361        let height = bp_prompt.update(cx, |this, cx| {
11362            this.prompt
11363                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11364        });
11365        let cloned_prompt = bp_prompt.clone();
11366        let blocks = vec![BlockProperties {
11367            style: BlockStyle::Sticky,
11368            placement: BlockPlacement::Above(anchor),
11369            height: Some(height),
11370            render: Arc::new(move |cx| {
11371                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11372                cloned_prompt.clone().into_any_element()
11373            }),
11374            priority: 0,
11375        }];
11376
11377        let focus_handle = bp_prompt.focus_handle(cx);
11378        window.focus(&focus_handle, cx);
11379
11380        let block_ids = self.insert_blocks(blocks, None, cx);
11381        bp_prompt.update(cx, |prompt, _| {
11382            prompt.add_block_ids(block_ids);
11383        });
11384    }
11385
11386    pub(crate) fn breakpoint_at_row(
11387        &self,
11388        row: u32,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) -> Option<(Anchor, Breakpoint)> {
11392        let snapshot = self.snapshot(window, cx);
11393        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11394
11395        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11396    }
11397
11398    pub(crate) fn breakpoint_at_anchor(
11399        &self,
11400        breakpoint_position: Anchor,
11401        snapshot: &EditorSnapshot,
11402        cx: &mut Context<Self>,
11403    ) -> Option<(Anchor, Breakpoint)> {
11404        let buffer = self
11405            .buffer
11406            .read(cx)
11407            .buffer_for_anchor(breakpoint_position, cx)?;
11408
11409        let enclosing_excerpt = breakpoint_position.excerpt_id;
11410        let buffer_snapshot = buffer.read(cx).snapshot();
11411
11412        let row = buffer_snapshot
11413            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11414            .row;
11415
11416        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11417        let anchor_end = snapshot
11418            .buffer_snapshot()
11419            .anchor_after(Point::new(row, line_len));
11420
11421        self.breakpoint_store
11422            .as_ref()?
11423            .read_with(cx, |breakpoint_store, cx| {
11424                breakpoint_store
11425                    .breakpoints(
11426                        &buffer,
11427                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11428                        &buffer_snapshot,
11429                        cx,
11430                    )
11431                    .next()
11432                    .and_then(|(bp, _)| {
11433                        let breakpoint_row = buffer_snapshot
11434                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11435                            .row;
11436
11437                        if breakpoint_row == row {
11438                            snapshot
11439                                .buffer_snapshot()
11440                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11441                                .map(|position| (position, bp.bp.clone()))
11442                        } else {
11443                            None
11444                        }
11445                    })
11446            })
11447    }
11448
11449    pub fn edit_log_breakpoint(
11450        &mut self,
11451        _: &EditLogBreakpoint,
11452        window: &mut Window,
11453        cx: &mut Context<Self>,
11454    ) {
11455        if self.breakpoint_store.is_none() {
11456            return;
11457        }
11458
11459        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11460            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11461                message: None,
11462                state: BreakpointState::Enabled,
11463                condition: None,
11464                hit_condition: None,
11465            });
11466
11467            self.add_edit_breakpoint_block(
11468                anchor,
11469                &breakpoint,
11470                BreakpointPromptEditAction::Log,
11471                window,
11472                cx,
11473            );
11474        }
11475    }
11476
11477    fn breakpoints_at_cursors(
11478        &self,
11479        window: &mut Window,
11480        cx: &mut Context<Self>,
11481    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11482        let snapshot = self.snapshot(window, cx);
11483        let cursors = self
11484            .selections
11485            .disjoint_anchors_arc()
11486            .iter()
11487            .map(|selection| {
11488                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11489
11490                let breakpoint_position = self
11491                    .breakpoint_at_row(cursor_position.row, window, cx)
11492                    .map(|bp| bp.0)
11493                    .unwrap_or_else(|| {
11494                        snapshot
11495                            .display_snapshot
11496                            .buffer_snapshot()
11497                            .anchor_after(Point::new(cursor_position.row, 0))
11498                    });
11499
11500                let breakpoint = self
11501                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11502                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11503
11504                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11505            })
11506            // 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.
11507            .collect::<HashMap<Anchor, _>>();
11508
11509        cursors.into_iter().collect()
11510    }
11511
11512    pub fn enable_breakpoint(
11513        &mut self,
11514        _: &crate::actions::EnableBreakpoint,
11515        window: &mut Window,
11516        cx: &mut Context<Self>,
11517    ) {
11518        if self.breakpoint_store.is_none() {
11519            return;
11520        }
11521
11522        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11523            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11524                continue;
11525            };
11526            self.edit_breakpoint_at_anchor(
11527                anchor,
11528                breakpoint,
11529                BreakpointEditAction::InvertState,
11530                cx,
11531            );
11532        }
11533    }
11534
11535    pub fn disable_breakpoint(
11536        &mut self,
11537        _: &crate::actions::DisableBreakpoint,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        if self.breakpoint_store.is_none() {
11542            return;
11543        }
11544
11545        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11546            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11547                continue;
11548            };
11549            self.edit_breakpoint_at_anchor(
11550                anchor,
11551                breakpoint,
11552                BreakpointEditAction::InvertState,
11553                cx,
11554            );
11555        }
11556    }
11557
11558    pub fn toggle_breakpoint(
11559        &mut self,
11560        _: &crate::actions::ToggleBreakpoint,
11561        window: &mut Window,
11562        cx: &mut Context<Self>,
11563    ) {
11564        if self.breakpoint_store.is_none() {
11565            return;
11566        }
11567
11568        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11569            if let Some(breakpoint) = breakpoint {
11570                self.edit_breakpoint_at_anchor(
11571                    anchor,
11572                    breakpoint,
11573                    BreakpointEditAction::Toggle,
11574                    cx,
11575                );
11576            } else {
11577                self.edit_breakpoint_at_anchor(
11578                    anchor,
11579                    Breakpoint::new_standard(),
11580                    BreakpointEditAction::Toggle,
11581                    cx,
11582                );
11583            }
11584        }
11585    }
11586
11587    pub fn edit_breakpoint_at_anchor(
11588        &mut self,
11589        breakpoint_position: Anchor,
11590        breakpoint: Breakpoint,
11591        edit_action: BreakpointEditAction,
11592        cx: &mut Context<Self>,
11593    ) {
11594        let Some(breakpoint_store) = &self.breakpoint_store else {
11595            return;
11596        };
11597
11598        let Some(buffer) = self
11599            .buffer
11600            .read(cx)
11601            .buffer_for_anchor(breakpoint_position, cx)
11602        else {
11603            return;
11604        };
11605
11606        breakpoint_store.update(cx, |breakpoint_store, cx| {
11607            breakpoint_store.toggle_breakpoint(
11608                buffer,
11609                BreakpointWithPosition {
11610                    position: breakpoint_position.text_anchor,
11611                    bp: breakpoint,
11612                },
11613                edit_action,
11614                cx,
11615            );
11616        });
11617
11618        cx.notify();
11619    }
11620
11621    #[cfg(any(test, feature = "test-support"))]
11622    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11623        self.breakpoint_store.clone()
11624    }
11625
11626    pub fn prepare_restore_change(
11627        &self,
11628        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11629        hunk: &MultiBufferDiffHunk,
11630        cx: &mut App,
11631    ) -> Option<()> {
11632        if hunk.is_created_file() {
11633            return None;
11634        }
11635        let buffer = self.buffer.read(cx);
11636        let diff = buffer.diff_for(hunk.buffer_id)?;
11637        let buffer = buffer.buffer(hunk.buffer_id)?;
11638        let buffer = buffer.read(cx);
11639        let original_text = diff
11640            .read(cx)
11641            .base_text(cx)
11642            .as_rope()
11643            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11644        let buffer_snapshot = buffer.snapshot();
11645        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11646        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11647            probe
11648                .0
11649                .start
11650                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11651                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11652        }) {
11653            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11654            Some(())
11655        } else {
11656            None
11657        }
11658    }
11659
11660    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11661        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11662    }
11663
11664    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11665        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11666    }
11667
11668    pub fn rotate_selections_forward(
11669        &mut self,
11670        _: &RotateSelectionsForward,
11671        window: &mut Window,
11672        cx: &mut Context<Self>,
11673    ) {
11674        self.rotate_selections(window, cx, false)
11675    }
11676
11677    pub fn rotate_selections_backward(
11678        &mut self,
11679        _: &RotateSelectionsBackward,
11680        window: &mut Window,
11681        cx: &mut Context<Self>,
11682    ) {
11683        self.rotate_selections(window, cx, true)
11684    }
11685
11686    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11688        let display_snapshot = self.display_snapshot(cx);
11689        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11690
11691        if selections.len() < 2 {
11692            return;
11693        }
11694
11695        let (edits, new_selections) = {
11696            let buffer = self.buffer.read(cx).read(cx);
11697            let has_selections = selections.iter().any(|s| !s.is_empty());
11698            if has_selections {
11699                let mut selected_texts: Vec<String> = selections
11700                    .iter()
11701                    .map(|selection| {
11702                        buffer
11703                            .text_for_range(selection.start..selection.end)
11704                            .collect()
11705                    })
11706                    .collect();
11707
11708                if reverse {
11709                    selected_texts.rotate_left(1);
11710                } else {
11711                    selected_texts.rotate_right(1);
11712                }
11713
11714                let mut offset_delta: i64 = 0;
11715                let mut new_selections = Vec::new();
11716                let edits: Vec<_> = selections
11717                    .iter()
11718                    .zip(selected_texts.iter())
11719                    .map(|(selection, new_text)| {
11720                        let old_len = (selection.end.0 - selection.start.0) as i64;
11721                        let new_len = new_text.len() as i64;
11722                        let adjusted_start =
11723                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11724                        let adjusted_end =
11725                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11726
11727                        new_selections.push(Selection {
11728                            id: selection.id,
11729                            start: adjusted_start,
11730                            end: adjusted_end,
11731                            reversed: selection.reversed,
11732                            goal: selection.goal,
11733                        });
11734
11735                        offset_delta += new_len - old_len;
11736                        (selection.start..selection.end, new_text.clone())
11737                    })
11738                    .collect();
11739                (edits, new_selections)
11740            } else {
11741                let mut all_rows: Vec<u32> = selections
11742                    .iter()
11743                    .map(|selection| buffer.offset_to_point(selection.start).row)
11744                    .collect();
11745                all_rows.sort_unstable();
11746                all_rows.dedup();
11747
11748                if all_rows.len() < 2 {
11749                    return;
11750                }
11751
11752                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11753                    .iter()
11754                    .map(|&row| {
11755                        let start = Point::new(row, 0);
11756                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11757                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11758                    })
11759                    .collect();
11760
11761                let mut line_texts: Vec<String> = line_ranges
11762                    .iter()
11763                    .map(|range| buffer.text_for_range(range.clone()).collect())
11764                    .collect();
11765
11766                if reverse {
11767                    line_texts.rotate_left(1);
11768                } else {
11769                    line_texts.rotate_right(1);
11770                }
11771
11772                let edits = line_ranges
11773                    .iter()
11774                    .zip(line_texts.iter())
11775                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11776                    .collect();
11777
11778                let num_rows = all_rows.len();
11779                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11780                    .iter()
11781                    .enumerate()
11782                    .map(|(i, &row)| (row, i))
11783                    .collect();
11784
11785                // Compute new line start offsets after rotation (handles CRLF)
11786                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11787                let first_line_start = line_ranges[0].start.0;
11788                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11789                for text in line_texts.iter().take(num_rows - 1) {
11790                    let prev_start = *new_line_starts.last().unwrap();
11791                    new_line_starts.push(prev_start + text.len() + newline_len);
11792                }
11793
11794                let new_selections = selections
11795                    .iter()
11796                    .map(|selection| {
11797                        let point = buffer.offset_to_point(selection.start);
11798                        let old_index = row_to_index[&point.row];
11799                        let new_index = if reverse {
11800                            (old_index + num_rows - 1) % num_rows
11801                        } else {
11802                            (old_index + 1) % num_rows
11803                        };
11804                        let new_offset =
11805                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11806                        Selection {
11807                            id: selection.id,
11808                            start: new_offset,
11809                            end: new_offset,
11810                            reversed: selection.reversed,
11811                            goal: selection.goal,
11812                        }
11813                    })
11814                    .collect();
11815
11816                (edits, new_selections)
11817            }
11818        };
11819
11820        self.transact(window, cx, |this, window, cx| {
11821            this.buffer.update(cx, |buffer, cx| {
11822                buffer.edit(edits, None, cx);
11823            });
11824            this.change_selections(Default::default(), window, cx, |s| {
11825                s.select(new_selections);
11826            });
11827        });
11828    }
11829
11830    fn manipulate_lines<M>(
11831        &mut self,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834        mut manipulate: M,
11835    ) where
11836        M: FnMut(&str) -> LineManipulationResult,
11837    {
11838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11839
11840        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11841        let buffer = self.buffer.read(cx).snapshot(cx);
11842
11843        let mut edits = Vec::new();
11844
11845        let selections = self.selections.all::<Point>(&display_map);
11846        let mut selections = selections.iter().peekable();
11847        let mut contiguous_row_selections = Vec::new();
11848        let mut new_selections = Vec::new();
11849        let mut added_lines = 0;
11850        let mut removed_lines = 0;
11851
11852        while let Some(selection) = selections.next() {
11853            let (start_row, end_row) = consume_contiguous_rows(
11854                &mut contiguous_row_selections,
11855                selection,
11856                &display_map,
11857                &mut selections,
11858            );
11859
11860            let start_point = Point::new(start_row.0, 0);
11861            let end_point = Point::new(
11862                end_row.previous_row().0,
11863                buffer.line_len(end_row.previous_row()),
11864            );
11865            let text = buffer
11866                .text_for_range(start_point..end_point)
11867                .collect::<String>();
11868
11869            let LineManipulationResult {
11870                new_text,
11871                line_count_before,
11872                line_count_after,
11873            } = manipulate(&text);
11874
11875            edits.push((start_point..end_point, new_text));
11876
11877            // Selections must change based on added and removed line count
11878            let start_row =
11879                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11880            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11881            new_selections.push(Selection {
11882                id: selection.id,
11883                start: start_row,
11884                end: end_row,
11885                goal: SelectionGoal::None,
11886                reversed: selection.reversed,
11887            });
11888
11889            if line_count_after > line_count_before {
11890                added_lines += line_count_after - line_count_before;
11891            } else if line_count_before > line_count_after {
11892                removed_lines += line_count_before - line_count_after;
11893            }
11894        }
11895
11896        self.transact(window, cx, |this, window, cx| {
11897            let buffer = this.buffer.update(cx, |buffer, cx| {
11898                buffer.edit(edits, None, cx);
11899                buffer.snapshot(cx)
11900            });
11901
11902            // Recalculate offsets on newly edited buffer
11903            let new_selections = new_selections
11904                .iter()
11905                .map(|s| {
11906                    let start_point = Point::new(s.start.0, 0);
11907                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11908                    Selection {
11909                        id: s.id,
11910                        start: buffer.point_to_offset(start_point),
11911                        end: buffer.point_to_offset(end_point),
11912                        goal: s.goal,
11913                        reversed: s.reversed,
11914                    }
11915                })
11916                .collect();
11917
11918            this.change_selections(Default::default(), window, cx, |s| {
11919                s.select(new_selections);
11920            });
11921
11922            this.request_autoscroll(Autoscroll::fit(), cx);
11923        });
11924    }
11925
11926    fn manipulate_immutable_lines<Fn>(
11927        &mut self,
11928        window: &mut Window,
11929        cx: &mut Context<Self>,
11930        mut callback: Fn,
11931    ) where
11932        Fn: FnMut(&mut Vec<&str>),
11933    {
11934        self.manipulate_lines(window, cx, |text| {
11935            let mut lines: Vec<&str> = text.split('\n').collect();
11936            let line_count_before = lines.len();
11937
11938            callback(&mut lines);
11939
11940            LineManipulationResult {
11941                new_text: lines.join("\n"),
11942                line_count_before,
11943                line_count_after: lines.len(),
11944            }
11945        });
11946    }
11947
11948    fn manipulate_mutable_lines<Fn>(
11949        &mut self,
11950        window: &mut Window,
11951        cx: &mut Context<Self>,
11952        mut callback: Fn,
11953    ) where
11954        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11955    {
11956        self.manipulate_lines(window, cx, |text| {
11957            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11958            let line_count_before = lines.len();
11959
11960            callback(&mut lines);
11961
11962            LineManipulationResult {
11963                new_text: lines.join("\n"),
11964                line_count_before,
11965                line_count_after: lines.len(),
11966            }
11967        });
11968    }
11969
11970    pub fn convert_indentation_to_spaces(
11971        &mut self,
11972        _: &ConvertIndentationToSpaces,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        let settings = self.buffer.read(cx).language_settings(cx);
11977        let tab_size = settings.tab_size.get() as usize;
11978
11979        self.manipulate_mutable_lines(window, cx, |lines| {
11980            // Allocates a reasonably sized scratch buffer once for the whole loop
11981            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11982            // Avoids recomputing spaces that could be inserted many times
11983            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11984                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11985                .collect();
11986
11987            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11988                let mut chars = line.as_ref().chars();
11989                let mut col = 0;
11990                let mut changed = false;
11991
11992                for ch in chars.by_ref() {
11993                    match ch {
11994                        ' ' => {
11995                            reindented_line.push(' ');
11996                            col += 1;
11997                        }
11998                        '\t' => {
11999                            // \t are converted to spaces depending on the current column
12000                            let spaces_len = tab_size - (col % tab_size);
12001                            reindented_line.extend(&space_cache[spaces_len - 1]);
12002                            col += spaces_len;
12003                            changed = true;
12004                        }
12005                        _ => {
12006                            // If we dont append before break, the character is consumed
12007                            reindented_line.push(ch);
12008                            break;
12009                        }
12010                    }
12011                }
12012
12013                if !changed {
12014                    reindented_line.clear();
12015                    continue;
12016                }
12017                // Append the rest of the line and replace old reference with new one
12018                reindented_line.extend(chars);
12019                *line = Cow::Owned(reindented_line.clone());
12020                reindented_line.clear();
12021            }
12022        });
12023    }
12024
12025    pub fn convert_indentation_to_tabs(
12026        &mut self,
12027        _: &ConvertIndentationToTabs,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        let settings = self.buffer.read(cx).language_settings(cx);
12032        let tab_size = settings.tab_size.get() as usize;
12033
12034        self.manipulate_mutable_lines(window, cx, |lines| {
12035            // Allocates a reasonably sized buffer once for the whole loop
12036            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12037            // Avoids recomputing spaces that could be inserted many times
12038            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12039                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12040                .collect();
12041
12042            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12043                let mut chars = line.chars();
12044                let mut spaces_count = 0;
12045                let mut first_non_indent_char = None;
12046                let mut changed = false;
12047
12048                for ch in chars.by_ref() {
12049                    match ch {
12050                        ' ' => {
12051                            // Keep track of spaces. Append \t when we reach tab_size
12052                            spaces_count += 1;
12053                            changed = true;
12054                            if spaces_count == tab_size {
12055                                reindented_line.push('\t');
12056                                spaces_count = 0;
12057                            }
12058                        }
12059                        '\t' => {
12060                            reindented_line.push('\t');
12061                            spaces_count = 0;
12062                        }
12063                        _ => {
12064                            // Dont append it yet, we might have remaining spaces
12065                            first_non_indent_char = Some(ch);
12066                            break;
12067                        }
12068                    }
12069                }
12070
12071                if !changed {
12072                    reindented_line.clear();
12073                    continue;
12074                }
12075                // Remaining spaces that didn't make a full tab stop
12076                if spaces_count > 0 {
12077                    reindented_line.extend(&space_cache[spaces_count - 1]);
12078                }
12079                // If we consume an extra character that was not indentation, add it back
12080                if let Some(extra_char) = first_non_indent_char {
12081                    reindented_line.push(extra_char);
12082                }
12083                // Append the rest of the line and replace old reference with new one
12084                reindented_line.extend(chars);
12085                *line = Cow::Owned(reindented_line.clone());
12086                reindented_line.clear();
12087            }
12088        });
12089    }
12090
12091    pub fn convert_to_upper_case(
12092        &mut self,
12093        _: &ConvertToUpperCase,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        self.manipulate_text(window, cx, |text| text.to_uppercase())
12098    }
12099
12100    pub fn convert_to_lower_case(
12101        &mut self,
12102        _: &ConvertToLowerCase,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.manipulate_text(window, cx, |text| text.to_lowercase())
12107    }
12108
12109    pub fn convert_to_title_case(
12110        &mut self,
12111        _: &ConvertToTitleCase,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        self.manipulate_text(window, cx, |text| {
12116            text.split('\n')
12117                .map(|line| line.to_case(Case::Title))
12118                .join("\n")
12119        })
12120    }
12121
12122    pub fn convert_to_snake_case(
12123        &mut self,
12124        _: &ConvertToSnakeCase,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12129    }
12130
12131    pub fn convert_to_kebab_case(
12132        &mut self,
12133        _: &ConvertToKebabCase,
12134        window: &mut Window,
12135        cx: &mut Context<Self>,
12136    ) {
12137        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12138    }
12139
12140    pub fn convert_to_upper_camel_case(
12141        &mut self,
12142        _: &ConvertToUpperCamelCase,
12143        window: &mut Window,
12144        cx: &mut Context<Self>,
12145    ) {
12146        self.manipulate_text(window, cx, |text| {
12147            text.split('\n')
12148                .map(|line| line.to_case(Case::UpperCamel))
12149                .join("\n")
12150        })
12151    }
12152
12153    pub fn convert_to_lower_camel_case(
12154        &mut self,
12155        _: &ConvertToLowerCamelCase,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12160    }
12161
12162    pub fn convert_to_opposite_case(
12163        &mut self,
12164        _: &ConvertToOppositeCase,
12165        window: &mut Window,
12166        cx: &mut Context<Self>,
12167    ) {
12168        self.manipulate_text(window, cx, |text| {
12169            text.chars()
12170                .fold(String::with_capacity(text.len()), |mut t, c| {
12171                    if c.is_uppercase() {
12172                        t.extend(c.to_lowercase());
12173                    } else {
12174                        t.extend(c.to_uppercase());
12175                    }
12176                    t
12177                })
12178        })
12179    }
12180
12181    pub fn convert_to_sentence_case(
12182        &mut self,
12183        _: &ConvertToSentenceCase,
12184        window: &mut Window,
12185        cx: &mut Context<Self>,
12186    ) {
12187        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12188    }
12189
12190    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12191        self.manipulate_text(window, cx, |text| {
12192            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12193            if has_upper_case_characters {
12194                text.to_lowercase()
12195            } else {
12196                text.to_uppercase()
12197            }
12198        })
12199    }
12200
12201    pub fn convert_to_rot13(
12202        &mut self,
12203        _: &ConvertToRot13,
12204        window: &mut Window,
12205        cx: &mut Context<Self>,
12206    ) {
12207        self.manipulate_text(window, cx, |text| {
12208            text.chars()
12209                .map(|c| match c {
12210                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12211                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12212                    _ => c,
12213                })
12214                .collect()
12215        })
12216    }
12217
12218    pub fn convert_to_rot47(
12219        &mut self,
12220        _: &ConvertToRot47,
12221        window: &mut Window,
12222        cx: &mut Context<Self>,
12223    ) {
12224        self.manipulate_text(window, cx, |text| {
12225            text.chars()
12226                .map(|c| {
12227                    let code_point = c as u32;
12228                    if code_point >= 33 && code_point <= 126 {
12229                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12230                    }
12231                    c
12232                })
12233                .collect()
12234        })
12235    }
12236
12237    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12238    where
12239        Fn: FnMut(&str) -> String,
12240    {
12241        let buffer = self.buffer.read(cx).snapshot(cx);
12242
12243        let mut new_selections = Vec::new();
12244        let mut edits = Vec::new();
12245        let mut selection_adjustment = 0isize;
12246
12247        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12248            let selection_is_empty = selection.is_empty();
12249
12250            let (start, end) = if selection_is_empty {
12251                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12252                (word_range.start, word_range.end)
12253            } else {
12254                (
12255                    buffer.point_to_offset(selection.start),
12256                    buffer.point_to_offset(selection.end),
12257                )
12258            };
12259
12260            let text = buffer.text_for_range(start..end).collect::<String>();
12261            let old_length = text.len() as isize;
12262            let text = callback(&text);
12263
12264            new_selections.push(Selection {
12265                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12266                end: MultiBufferOffset(
12267                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12268                ),
12269                goal: SelectionGoal::None,
12270                id: selection.id,
12271                reversed: selection.reversed,
12272            });
12273
12274            selection_adjustment += old_length - text.len() as isize;
12275
12276            edits.push((start..end, text));
12277        }
12278
12279        self.transact(window, cx, |this, window, cx| {
12280            this.buffer.update(cx, |buffer, cx| {
12281                buffer.edit(edits, None, cx);
12282            });
12283
12284            this.change_selections(Default::default(), window, cx, |s| {
12285                s.select(new_selections);
12286            });
12287
12288            this.request_autoscroll(Autoscroll::fit(), cx);
12289        });
12290    }
12291
12292    pub fn move_selection_on_drop(
12293        &mut self,
12294        selection: &Selection<Anchor>,
12295        target: DisplayPoint,
12296        is_cut: bool,
12297        window: &mut Window,
12298        cx: &mut Context<Self>,
12299    ) {
12300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12301        let buffer = display_map.buffer_snapshot();
12302        let mut edits = Vec::new();
12303        let insert_point = display_map
12304            .clip_point(target, Bias::Left)
12305            .to_point(&display_map);
12306        let text = buffer
12307            .text_for_range(selection.start..selection.end)
12308            .collect::<String>();
12309        if is_cut {
12310            edits.push(((selection.start..selection.end), String::new()));
12311        }
12312        let insert_anchor = buffer.anchor_before(insert_point);
12313        edits.push(((insert_anchor..insert_anchor), text));
12314        let last_edit_start = insert_anchor.bias_left(buffer);
12315        let last_edit_end = insert_anchor.bias_right(buffer);
12316        self.transact(window, cx, |this, window, cx| {
12317            this.buffer.update(cx, |buffer, cx| {
12318                buffer.edit(edits, None, cx);
12319            });
12320            this.change_selections(Default::default(), window, cx, |s| {
12321                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12322            });
12323        });
12324    }
12325
12326    pub fn clear_selection_drag_state(&mut self) {
12327        self.selection_drag_state = SelectionDragState::None;
12328    }
12329
12330    pub fn duplicate(
12331        &mut self,
12332        upwards: bool,
12333        whole_lines: bool,
12334        window: &mut Window,
12335        cx: &mut Context<Self>,
12336    ) {
12337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12338
12339        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12340        let buffer = display_map.buffer_snapshot();
12341        let selections = self.selections.all::<Point>(&display_map);
12342
12343        let mut edits = Vec::new();
12344        let mut selections_iter = selections.iter().peekable();
12345        while let Some(selection) = selections_iter.next() {
12346            let mut rows = selection.spanned_rows(false, &display_map);
12347            // duplicate line-wise
12348            if whole_lines || selection.start == selection.end {
12349                // Avoid duplicating the same lines twice.
12350                while let Some(next_selection) = selections_iter.peek() {
12351                    let next_rows = next_selection.spanned_rows(false, &display_map);
12352                    if next_rows.start < rows.end {
12353                        rows.end = next_rows.end;
12354                        selections_iter.next().unwrap();
12355                    } else {
12356                        break;
12357                    }
12358                }
12359
12360                // Copy the text from the selected row region and splice it either at the start
12361                // or end of the region.
12362                let start = Point::new(rows.start.0, 0);
12363                let end = Point::new(
12364                    rows.end.previous_row().0,
12365                    buffer.line_len(rows.end.previous_row()),
12366                );
12367
12368                let mut text = buffer.text_for_range(start..end).collect::<String>();
12369
12370                let insert_location = if upwards {
12371                    // When duplicating upward, we need to insert before the current line.
12372                    // If we're on the last line and it doesn't end with a newline,
12373                    // we need to add a newline before the duplicated content.
12374                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12375                        && buffer.max_point().column > 0
12376                        && !text.ends_with('\n');
12377
12378                    if needs_leading_newline {
12379                        text.insert(0, '\n');
12380                        end
12381                    } else {
12382                        text.push('\n');
12383                        Point::new(rows.start.0, 0)
12384                    }
12385                } else {
12386                    text.push('\n');
12387                    start
12388                };
12389                edits.push((insert_location..insert_location, text));
12390            } else {
12391                // duplicate character-wise
12392                let start = selection.start;
12393                let end = selection.end;
12394                let text = buffer.text_for_range(start..end).collect::<String>();
12395                edits.push((selection.end..selection.end, text));
12396            }
12397        }
12398
12399        self.transact(window, cx, |this, window, cx| {
12400            this.buffer.update(cx, |buffer, cx| {
12401                buffer.edit(edits, None, cx);
12402            });
12403
12404            // When duplicating upward with whole lines, move the cursor to the duplicated line
12405            if upwards && whole_lines {
12406                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12407
12408                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12409                    let mut new_ranges = Vec::new();
12410                    let selections = s.all::<Point>(&display_map);
12411                    let mut selections_iter = selections.iter().peekable();
12412
12413                    while let Some(first_selection) = selections_iter.next() {
12414                        // Group contiguous selections together to find the total row span
12415                        let mut group_selections = vec![first_selection];
12416                        let mut rows = first_selection.spanned_rows(false, &display_map);
12417
12418                        while let Some(next_selection) = selections_iter.peek() {
12419                            let next_rows = next_selection.spanned_rows(false, &display_map);
12420                            if next_rows.start < rows.end {
12421                                rows.end = next_rows.end;
12422                                group_selections.push(selections_iter.next().unwrap());
12423                            } else {
12424                                break;
12425                            }
12426                        }
12427
12428                        let row_count = rows.end.0 - rows.start.0;
12429
12430                        // Move all selections in this group up by the total number of duplicated rows
12431                        for selection in group_selections {
12432                            let new_start = Point::new(
12433                                selection.start.row.saturating_sub(row_count),
12434                                selection.start.column,
12435                            );
12436
12437                            let new_end = Point::new(
12438                                selection.end.row.saturating_sub(row_count),
12439                                selection.end.column,
12440                            );
12441
12442                            new_ranges.push(new_start..new_end);
12443                        }
12444                    }
12445
12446                    s.select_ranges(new_ranges);
12447                });
12448            }
12449
12450            this.request_autoscroll(Autoscroll::fit(), cx);
12451        });
12452    }
12453
12454    pub fn duplicate_line_up(
12455        &mut self,
12456        _: &DuplicateLineUp,
12457        window: &mut Window,
12458        cx: &mut Context<Self>,
12459    ) {
12460        self.duplicate(true, true, window, cx);
12461    }
12462
12463    pub fn duplicate_line_down(
12464        &mut self,
12465        _: &DuplicateLineDown,
12466        window: &mut Window,
12467        cx: &mut Context<Self>,
12468    ) {
12469        self.duplicate(false, true, window, cx);
12470    }
12471
12472    pub fn duplicate_selection(
12473        &mut self,
12474        _: &DuplicateSelection,
12475        window: &mut Window,
12476        cx: &mut Context<Self>,
12477    ) {
12478        self.duplicate(false, false, window, cx);
12479    }
12480
12481    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12483        if self.mode.is_single_line() {
12484            cx.propagate();
12485            return;
12486        }
12487
12488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12489        let buffer = self.buffer.read(cx).snapshot(cx);
12490
12491        let mut edits = Vec::new();
12492        let mut unfold_ranges = Vec::new();
12493        let mut refold_creases = Vec::new();
12494
12495        let selections = self.selections.all::<Point>(&display_map);
12496        let mut selections = selections.iter().peekable();
12497        let mut contiguous_row_selections = Vec::new();
12498        let mut new_selections = Vec::new();
12499
12500        while let Some(selection) = selections.next() {
12501            // Find all the selections that span a contiguous row range
12502            let (start_row, end_row) = consume_contiguous_rows(
12503                &mut contiguous_row_selections,
12504                selection,
12505                &display_map,
12506                &mut selections,
12507            );
12508
12509            // Move the text spanned by the row range to be before the line preceding the row range
12510            if start_row.0 > 0 {
12511                let range_to_move = Point::new(
12512                    start_row.previous_row().0,
12513                    buffer.line_len(start_row.previous_row()),
12514                )
12515                    ..Point::new(
12516                        end_row.previous_row().0,
12517                        buffer.line_len(end_row.previous_row()),
12518                    );
12519                let insertion_point = display_map
12520                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12521                    .0;
12522
12523                // Don't move lines across excerpts
12524                if buffer
12525                    .excerpt_containing(insertion_point..range_to_move.end)
12526                    .is_some()
12527                {
12528                    let text = buffer
12529                        .text_for_range(range_to_move.clone())
12530                        .flat_map(|s| s.chars())
12531                        .skip(1)
12532                        .chain(['\n'])
12533                        .collect::<String>();
12534
12535                    edits.push((
12536                        buffer.anchor_after(range_to_move.start)
12537                            ..buffer.anchor_before(range_to_move.end),
12538                        String::new(),
12539                    ));
12540                    let insertion_anchor = buffer.anchor_after(insertion_point);
12541                    edits.push((insertion_anchor..insertion_anchor, text));
12542
12543                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12544
12545                    // Move selections up
12546                    new_selections.extend(contiguous_row_selections.drain(..).map(
12547                        |mut selection| {
12548                            selection.start.row -= row_delta;
12549                            selection.end.row -= row_delta;
12550                            selection
12551                        },
12552                    ));
12553
12554                    // Move folds up
12555                    unfold_ranges.push(range_to_move.clone());
12556                    for fold in display_map.folds_in_range(
12557                        buffer.anchor_before(range_to_move.start)
12558                            ..buffer.anchor_after(range_to_move.end),
12559                    ) {
12560                        let mut start = fold.range.start.to_point(&buffer);
12561                        let mut end = fold.range.end.to_point(&buffer);
12562                        start.row -= row_delta;
12563                        end.row -= row_delta;
12564                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12565                    }
12566                }
12567            }
12568
12569            // If we didn't move line(s), preserve the existing selections
12570            new_selections.append(&mut contiguous_row_selections);
12571        }
12572
12573        self.transact(window, cx, |this, window, cx| {
12574            this.unfold_ranges(&unfold_ranges, true, true, cx);
12575            this.buffer.update(cx, |buffer, cx| {
12576                for (range, text) in edits {
12577                    buffer.edit([(range, text)], None, cx);
12578                }
12579            });
12580            this.fold_creases(refold_creases, true, window, cx);
12581            this.change_selections(Default::default(), window, cx, |s| {
12582                s.select(new_selections);
12583            })
12584        });
12585    }
12586
12587    pub fn move_line_down(
12588        &mut self,
12589        _: &MoveLineDown,
12590        window: &mut Window,
12591        cx: &mut Context<Self>,
12592    ) {
12593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12594        if self.mode.is_single_line() {
12595            cx.propagate();
12596            return;
12597        }
12598
12599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12600        let buffer = self.buffer.read(cx).snapshot(cx);
12601
12602        let mut edits = Vec::new();
12603        let mut unfold_ranges = Vec::new();
12604        let mut refold_creases = Vec::new();
12605
12606        let selections = self.selections.all::<Point>(&display_map);
12607        let mut selections = selections.iter().peekable();
12608        let mut contiguous_row_selections = Vec::new();
12609        let mut new_selections = Vec::new();
12610
12611        while let Some(selection) = selections.next() {
12612            // Find all the selections that span a contiguous row range
12613            let (start_row, end_row) = consume_contiguous_rows(
12614                &mut contiguous_row_selections,
12615                selection,
12616                &display_map,
12617                &mut selections,
12618            );
12619
12620            // Move the text spanned by the row range to be after the last line of the row range
12621            if end_row.0 <= buffer.max_point().row {
12622                let range_to_move =
12623                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12624                let insertion_point = display_map
12625                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12626                    .0;
12627
12628                // Don't move lines across excerpt boundaries
12629                if buffer
12630                    .excerpt_containing(range_to_move.start..insertion_point)
12631                    .is_some()
12632                {
12633                    let mut text = String::from("\n");
12634                    text.extend(buffer.text_for_range(range_to_move.clone()));
12635                    text.pop(); // Drop trailing newline
12636                    edits.push((
12637                        buffer.anchor_after(range_to_move.start)
12638                            ..buffer.anchor_before(range_to_move.end),
12639                        String::new(),
12640                    ));
12641                    let insertion_anchor = buffer.anchor_after(insertion_point);
12642                    edits.push((insertion_anchor..insertion_anchor, text));
12643
12644                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12645
12646                    // Move selections down
12647                    new_selections.extend(contiguous_row_selections.drain(..).map(
12648                        |mut selection| {
12649                            selection.start.row += row_delta;
12650                            selection.end.row += row_delta;
12651                            selection
12652                        },
12653                    ));
12654
12655                    // Move folds down
12656                    unfold_ranges.push(range_to_move.clone());
12657                    for fold in display_map.folds_in_range(
12658                        buffer.anchor_before(range_to_move.start)
12659                            ..buffer.anchor_after(range_to_move.end),
12660                    ) {
12661                        let mut start = fold.range.start.to_point(&buffer);
12662                        let mut end = fold.range.end.to_point(&buffer);
12663                        start.row += row_delta;
12664                        end.row += row_delta;
12665                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12666                    }
12667                }
12668            }
12669
12670            // If we didn't move line(s), preserve the existing selections
12671            new_selections.append(&mut contiguous_row_selections);
12672        }
12673
12674        self.transact(window, cx, |this, window, cx| {
12675            this.unfold_ranges(&unfold_ranges, true, true, cx);
12676            this.buffer.update(cx, |buffer, cx| {
12677                for (range, text) in edits {
12678                    buffer.edit([(range, text)], None, cx);
12679                }
12680            });
12681            this.fold_creases(refold_creases, true, window, cx);
12682            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12683        });
12684    }
12685
12686    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12688        let text_layout_details = &self.text_layout_details(window);
12689        self.transact(window, cx, |this, window, cx| {
12690            let edits = this.change_selections(Default::default(), window, cx, |s| {
12691                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12692                s.move_with(|display_map, selection| {
12693                    if !selection.is_empty() {
12694                        return;
12695                    }
12696
12697                    let mut head = selection.head();
12698                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12699                    if head.column() == display_map.line_len(head.row()) {
12700                        transpose_offset = display_map
12701                            .buffer_snapshot()
12702                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12703                    }
12704
12705                    if transpose_offset == MultiBufferOffset(0) {
12706                        return;
12707                    }
12708
12709                    *head.column_mut() += 1;
12710                    head = display_map.clip_point(head, Bias::Right);
12711                    let goal = SelectionGoal::HorizontalPosition(
12712                        display_map
12713                            .x_for_display_point(head, text_layout_details)
12714                            .into(),
12715                    );
12716                    selection.collapse_to(head, goal);
12717
12718                    let transpose_start = display_map
12719                        .buffer_snapshot()
12720                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12721                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12722                        let transpose_end = display_map
12723                            .buffer_snapshot()
12724                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12725                        if let Some(ch) = display_map
12726                            .buffer_snapshot()
12727                            .chars_at(transpose_start)
12728                            .next()
12729                        {
12730                            edits.push((transpose_start..transpose_offset, String::new()));
12731                            edits.push((transpose_end..transpose_end, ch.to_string()));
12732                        }
12733                    }
12734                });
12735                edits
12736            });
12737            this.buffer
12738                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12739            let selections = this
12740                .selections
12741                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12742            this.change_selections(Default::default(), window, cx, |s| {
12743                s.select(selections);
12744            });
12745        });
12746    }
12747
12748    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12750        if self.mode.is_single_line() {
12751            cx.propagate();
12752            return;
12753        }
12754
12755        self.rewrap_impl(RewrapOptions::default(), cx)
12756    }
12757
12758    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12759        let buffer = self.buffer.read(cx).snapshot(cx);
12760        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12761
12762        #[derive(Clone, Debug, PartialEq)]
12763        enum CommentFormat {
12764            /// single line comment, with prefix for line
12765            Line(String),
12766            /// single line within a block comment, with prefix for line
12767            BlockLine(String),
12768            /// a single line of a block comment that includes the initial delimiter
12769            BlockCommentWithStart(BlockCommentConfig),
12770            /// a single line of a block comment that includes the ending delimiter
12771            BlockCommentWithEnd(BlockCommentConfig),
12772        }
12773
12774        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12775        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12776            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12777                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12778                .peekable();
12779
12780            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12781                row
12782            } else {
12783                return Vec::new();
12784            };
12785
12786            let language_settings = buffer.language_settings_at(selection.head(), cx);
12787            let language_scope = buffer.language_scope_at(selection.head());
12788
12789            let indent_and_prefix_for_row =
12790                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12791                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12792                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12793                        &language_scope
12794                    {
12795                        let indent_end = Point::new(row, indent.len);
12796                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12797                        let line_text_after_indent = buffer
12798                            .text_for_range(indent_end..line_end)
12799                            .collect::<String>();
12800
12801                        let is_within_comment_override = buffer
12802                            .language_scope_at(indent_end)
12803                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12804                        let comment_delimiters = if is_within_comment_override {
12805                            // we are within a comment syntax node, but we don't
12806                            // yet know what kind of comment: block, doc or line
12807                            match (
12808                                language_scope.documentation_comment(),
12809                                language_scope.block_comment(),
12810                            ) {
12811                                (Some(config), _) | (_, Some(config))
12812                                    if buffer.contains_str_at(indent_end, &config.start) =>
12813                                {
12814                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12815                                }
12816                                (Some(config), _) | (_, Some(config))
12817                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12818                                {
12819                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12820                                }
12821                                (Some(config), _) | (_, Some(config))
12822                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12823                                {
12824                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12825                                }
12826                                (_, _) => language_scope
12827                                    .line_comment_prefixes()
12828                                    .iter()
12829                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12830                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12831                            }
12832                        } else {
12833                            // we not in an overridden comment node, but we may
12834                            // be within a non-overridden line comment node
12835                            language_scope
12836                                .line_comment_prefixes()
12837                                .iter()
12838                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12839                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12840                        };
12841
12842                        let rewrap_prefix = language_scope
12843                            .rewrap_prefixes()
12844                            .iter()
12845                            .find_map(|prefix_regex| {
12846                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12847                                    if mat.start() == 0 {
12848                                        Some(mat.as_str().to_string())
12849                                    } else {
12850                                        None
12851                                    }
12852                                })
12853                            })
12854                            .flatten();
12855                        (comment_delimiters, rewrap_prefix)
12856                    } else {
12857                        (None, None)
12858                    };
12859                    (indent, comment_prefix, rewrap_prefix)
12860                };
12861
12862            let mut ranges = Vec::new();
12863            let from_empty_selection = selection.is_empty();
12864
12865            let mut current_range_start = first_row;
12866            let mut prev_row = first_row;
12867            let (
12868                mut current_range_indent,
12869                mut current_range_comment_delimiters,
12870                mut current_range_rewrap_prefix,
12871            ) = indent_and_prefix_for_row(first_row);
12872
12873            for row in non_blank_rows_iter.skip(1) {
12874                let has_paragraph_break = row > prev_row + 1;
12875
12876                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12877                    indent_and_prefix_for_row(row);
12878
12879                let has_indent_change = row_indent != current_range_indent;
12880                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12881
12882                let has_boundary_change = has_comment_change
12883                    || row_rewrap_prefix.is_some()
12884                    || (has_indent_change && current_range_comment_delimiters.is_some());
12885
12886                if has_paragraph_break || has_boundary_change {
12887                    ranges.push((
12888                        language_settings.clone(),
12889                        Point::new(current_range_start, 0)
12890                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12891                        current_range_indent,
12892                        current_range_comment_delimiters.clone(),
12893                        current_range_rewrap_prefix.clone(),
12894                        from_empty_selection,
12895                    ));
12896                    current_range_start = row;
12897                    current_range_indent = row_indent;
12898                    current_range_comment_delimiters = row_comment_delimiters;
12899                    current_range_rewrap_prefix = row_rewrap_prefix;
12900                }
12901                prev_row = row;
12902            }
12903
12904            ranges.push((
12905                language_settings.clone(),
12906                Point::new(current_range_start, 0)
12907                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12908                current_range_indent,
12909                current_range_comment_delimiters,
12910                current_range_rewrap_prefix,
12911                from_empty_selection,
12912            ));
12913
12914            ranges
12915        });
12916
12917        let mut edits = Vec::new();
12918        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12919
12920        for (
12921            language_settings,
12922            wrap_range,
12923            mut indent_size,
12924            comment_prefix,
12925            rewrap_prefix,
12926            from_empty_selection,
12927        ) in wrap_ranges
12928        {
12929            let mut start_row = wrap_range.start.row;
12930            let mut end_row = wrap_range.end.row;
12931
12932            // Skip selections that overlap with a range that has already been rewrapped.
12933            let selection_range = start_row..end_row;
12934            if rewrapped_row_ranges
12935                .iter()
12936                .any(|range| range.overlaps(&selection_range))
12937            {
12938                continue;
12939            }
12940
12941            let tab_size = language_settings.tab_size;
12942
12943            let (line_prefix, inside_comment) = match &comment_prefix {
12944                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12945                    (Some(prefix.as_str()), true)
12946                }
12947                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12948                    (Some(prefix.as_ref()), true)
12949                }
12950                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12951                    start: _,
12952                    end: _,
12953                    prefix,
12954                    tab_size,
12955                })) => {
12956                    indent_size.len += tab_size;
12957                    (Some(prefix.as_ref()), true)
12958                }
12959                None => (None, false),
12960            };
12961            let indent_prefix = indent_size.chars().collect::<String>();
12962            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12963
12964            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12965                RewrapBehavior::InComments => inside_comment,
12966                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12967                RewrapBehavior::Anywhere => true,
12968            };
12969
12970            let should_rewrap = options.override_language_settings
12971                || allow_rewrap_based_on_language
12972                || self.hard_wrap.is_some();
12973            if !should_rewrap {
12974                continue;
12975            }
12976
12977            if from_empty_selection {
12978                'expand_upwards: while start_row > 0 {
12979                    let prev_row = start_row - 1;
12980                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12981                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12982                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12983                    {
12984                        start_row = prev_row;
12985                    } else {
12986                        break 'expand_upwards;
12987                    }
12988                }
12989
12990                'expand_downwards: while end_row < buffer.max_point().row {
12991                    let next_row = end_row + 1;
12992                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12993                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12994                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12995                    {
12996                        end_row = next_row;
12997                    } else {
12998                        break 'expand_downwards;
12999                    }
13000                }
13001            }
13002
13003            let start = Point::new(start_row, 0);
13004            let start_offset = ToOffset::to_offset(&start, &buffer);
13005            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13006            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13007            let mut first_line_delimiter = None;
13008            let mut last_line_delimiter = None;
13009            let Some(lines_without_prefixes) = selection_text
13010                .lines()
13011                .enumerate()
13012                .map(|(ix, line)| {
13013                    let line_trimmed = line.trim_start();
13014                    if rewrap_prefix.is_some() && ix > 0 {
13015                        Ok(line_trimmed)
13016                    } else if let Some(
13017                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13018                            start,
13019                            prefix,
13020                            end,
13021                            tab_size,
13022                        })
13023                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13024                            start,
13025                            prefix,
13026                            end,
13027                            tab_size,
13028                        }),
13029                    ) = &comment_prefix
13030                    {
13031                        let line_trimmed = line_trimmed
13032                            .strip_prefix(start.as_ref())
13033                            .map(|s| {
13034                                let mut indent_size = indent_size;
13035                                indent_size.len -= tab_size;
13036                                let indent_prefix: String = indent_size.chars().collect();
13037                                first_line_delimiter = Some((indent_prefix, start));
13038                                s.trim_start()
13039                            })
13040                            .unwrap_or(line_trimmed);
13041                        let line_trimmed = line_trimmed
13042                            .strip_suffix(end.as_ref())
13043                            .map(|s| {
13044                                last_line_delimiter = Some(end);
13045                                s.trim_end()
13046                            })
13047                            .unwrap_or(line_trimmed);
13048                        let line_trimmed = line_trimmed
13049                            .strip_prefix(prefix.as_ref())
13050                            .unwrap_or(line_trimmed);
13051                        Ok(line_trimmed)
13052                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13053                        line_trimmed.strip_prefix(prefix).with_context(|| {
13054                            format!("line did not start with prefix {prefix:?}: {line:?}")
13055                        })
13056                    } else {
13057                        line_trimmed
13058                            .strip_prefix(&line_prefix.trim_start())
13059                            .with_context(|| {
13060                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13061                            })
13062                    }
13063                })
13064                .collect::<Result<Vec<_>, _>>()
13065                .log_err()
13066            else {
13067                continue;
13068            };
13069
13070            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13071                buffer
13072                    .language_settings_at(Point::new(start_row, 0), cx)
13073                    .preferred_line_length as usize
13074            });
13075
13076            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13077                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13078            } else {
13079                line_prefix.clone()
13080            };
13081
13082            let wrapped_text = {
13083                let mut wrapped_text = wrap_with_prefix(
13084                    line_prefix,
13085                    subsequent_lines_prefix,
13086                    lines_without_prefixes.join("\n"),
13087                    wrap_column,
13088                    tab_size,
13089                    options.preserve_existing_whitespace,
13090                );
13091
13092                if let Some((indent, delimiter)) = first_line_delimiter {
13093                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13094                }
13095                if let Some(last_line) = last_line_delimiter {
13096                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13097                }
13098
13099                wrapped_text
13100            };
13101
13102            // TODO: should always use char-based diff while still supporting cursor behavior that
13103            // matches vim.
13104            let mut diff_options = DiffOptions::default();
13105            if options.override_language_settings {
13106                diff_options.max_word_diff_len = 0;
13107                diff_options.max_word_diff_line_count = 0;
13108            } else {
13109                diff_options.max_word_diff_len = usize::MAX;
13110                diff_options.max_word_diff_line_count = usize::MAX;
13111            }
13112
13113            for (old_range, new_text) in
13114                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13115            {
13116                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13117                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13118                edits.push((edit_start..edit_end, new_text));
13119            }
13120
13121            rewrapped_row_ranges.push(start_row..=end_row);
13122        }
13123
13124        self.buffer
13125            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13126    }
13127
13128    pub fn cut_common(
13129        &mut self,
13130        cut_no_selection_line: bool,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) -> ClipboardItem {
13134        let mut text = String::new();
13135        let buffer = self.buffer.read(cx).snapshot(cx);
13136        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13137        let mut clipboard_selections = Vec::with_capacity(selections.len());
13138        {
13139            let max_point = buffer.max_point();
13140            let mut is_first = true;
13141            let mut prev_selection_was_entire_line = false;
13142            for selection in &mut selections {
13143                let is_entire_line =
13144                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13145                if is_entire_line {
13146                    selection.start = Point::new(selection.start.row, 0);
13147                    if !selection.is_empty() && selection.end.column == 0 {
13148                        selection.end = cmp::min(max_point, selection.end);
13149                    } else {
13150                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13151                    }
13152                    selection.goal = SelectionGoal::None;
13153                }
13154                if is_first {
13155                    is_first = false;
13156                } else if !prev_selection_was_entire_line {
13157                    text += "\n";
13158                }
13159                prev_selection_was_entire_line = is_entire_line;
13160                let mut len = 0;
13161                for chunk in buffer.text_for_range(selection.start..selection.end) {
13162                    text.push_str(chunk);
13163                    len += chunk.len();
13164                }
13165
13166                clipboard_selections.push(ClipboardSelection::for_buffer(
13167                    len,
13168                    is_entire_line,
13169                    selection.range(),
13170                    &buffer,
13171                    self.project.as_ref(),
13172                    cx,
13173                ));
13174            }
13175        }
13176
13177        self.transact(window, cx, |this, window, cx| {
13178            this.change_selections(Default::default(), window, cx, |s| {
13179                s.select(selections);
13180            });
13181            this.insert("", window, cx);
13182        });
13183        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13184    }
13185
13186    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13188        let item = self.cut_common(true, window, cx);
13189        cx.write_to_clipboard(item);
13190    }
13191
13192    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13194        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13195            s.move_with(|snapshot, sel| {
13196                if sel.is_empty() {
13197                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13198                }
13199                if sel.is_empty() {
13200                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13201                }
13202            });
13203        });
13204        let item = self.cut_common(false, window, cx);
13205        cx.set_global(KillRing(item))
13206    }
13207
13208    pub fn kill_ring_yank(
13209        &mut self,
13210        _: &KillRingYank,
13211        window: &mut Window,
13212        cx: &mut Context<Self>,
13213    ) {
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13215        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13216            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13217                (kill_ring.text().to_string(), kill_ring.metadata_json())
13218            } else {
13219                return;
13220            }
13221        } else {
13222            return;
13223        };
13224        self.do_paste(&text, metadata, false, window, cx);
13225    }
13226
13227    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13228        self.do_copy(true, cx);
13229    }
13230
13231    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13232        self.do_copy(false, cx);
13233    }
13234
13235    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13236        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13237        let buffer = self.buffer.read(cx).read(cx);
13238        let mut text = String::new();
13239
13240        let mut clipboard_selections = Vec::with_capacity(selections.len());
13241        {
13242            let max_point = buffer.max_point();
13243            let mut is_first = true;
13244            let mut prev_selection_was_entire_line = false;
13245            for selection in &selections {
13246                let mut start = selection.start;
13247                let mut end = selection.end;
13248                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13249                let mut add_trailing_newline = false;
13250                if is_entire_line {
13251                    start = Point::new(start.row, 0);
13252                    let next_line_start = Point::new(end.row + 1, 0);
13253                    if next_line_start <= max_point {
13254                        end = next_line_start;
13255                    } else {
13256                        // We're on the last line without a trailing newline.
13257                        // Copy to the end of the line and add a newline afterwards.
13258                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13259                        add_trailing_newline = true;
13260                    }
13261                }
13262
13263                let mut trimmed_selections = Vec::new();
13264                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13265                    let row = MultiBufferRow(start.row);
13266                    let first_indent = buffer.indent_size_for_line(row);
13267                    if first_indent.len == 0 || start.column > first_indent.len {
13268                        trimmed_selections.push(start..end);
13269                    } else {
13270                        trimmed_selections.push(
13271                            Point::new(row.0, first_indent.len)
13272                                ..Point::new(row.0, buffer.line_len(row)),
13273                        );
13274                        for row in start.row + 1..=end.row {
13275                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13276                            if row == end.row {
13277                                line_len = end.column;
13278                            }
13279                            if line_len == 0 {
13280                                trimmed_selections
13281                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13282                                continue;
13283                            }
13284                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13285                            if row_indent_size.len >= first_indent.len {
13286                                trimmed_selections.push(
13287                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13288                                );
13289                            } else {
13290                                trimmed_selections.clear();
13291                                trimmed_selections.push(start..end);
13292                                break;
13293                            }
13294                        }
13295                    }
13296                } else {
13297                    trimmed_selections.push(start..end);
13298                }
13299
13300                let is_multiline_trim = trimmed_selections.len() > 1;
13301                for trimmed_range in trimmed_selections {
13302                    if is_first {
13303                        is_first = false;
13304                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13305                        text += "\n";
13306                    }
13307                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13308                    let mut len = 0;
13309                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13310                        text.push_str(chunk);
13311                        len += chunk.len();
13312                    }
13313                    if add_trailing_newline {
13314                        text.push('\n');
13315                        len += 1;
13316                    }
13317                    clipboard_selections.push(ClipboardSelection::for_buffer(
13318                        len,
13319                        is_entire_line,
13320                        trimmed_range,
13321                        &buffer,
13322                        self.project.as_ref(),
13323                        cx,
13324                    ));
13325                }
13326            }
13327        }
13328
13329        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13330            text,
13331            clipboard_selections,
13332        ));
13333    }
13334
13335    pub fn do_paste(
13336        &mut self,
13337        text: &String,
13338        clipboard_selections: Option<Vec<ClipboardSelection>>,
13339        handle_entire_lines: bool,
13340        window: &mut Window,
13341        cx: &mut Context<Self>,
13342    ) {
13343        if self.read_only(cx) {
13344            return;
13345        }
13346
13347        let clipboard_text = Cow::Borrowed(text.as_str());
13348
13349        self.transact(window, cx, |this, window, cx| {
13350            let had_active_edit_prediction = this.has_active_edit_prediction();
13351            let display_map = this.display_snapshot(cx);
13352            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13353            let cursor_offset = this
13354                .selections
13355                .last::<MultiBufferOffset>(&display_map)
13356                .head();
13357
13358            if let Some(mut clipboard_selections) = clipboard_selections {
13359                let all_selections_were_entire_line =
13360                    clipboard_selections.iter().all(|s| s.is_entire_line);
13361                let first_selection_indent_column =
13362                    clipboard_selections.first().map(|s| s.first_line_indent);
13363                if clipboard_selections.len() != old_selections.len() {
13364                    clipboard_selections.drain(..);
13365                }
13366                let mut auto_indent_on_paste = true;
13367
13368                this.buffer.update(cx, |buffer, cx| {
13369                    let snapshot = buffer.read(cx);
13370                    auto_indent_on_paste = snapshot
13371                        .language_settings_at(cursor_offset, cx)
13372                        .auto_indent_on_paste;
13373
13374                    let mut start_offset = 0;
13375                    let mut edits = Vec::new();
13376                    let mut original_indent_columns = Vec::new();
13377                    for (ix, selection) in old_selections.iter().enumerate() {
13378                        let to_insert;
13379                        let entire_line;
13380                        let original_indent_column;
13381                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13382                            let end_offset = start_offset + clipboard_selection.len;
13383                            to_insert = &clipboard_text[start_offset..end_offset];
13384                            entire_line = clipboard_selection.is_entire_line;
13385                            start_offset = if entire_line {
13386                                end_offset
13387                            } else {
13388                                end_offset + 1
13389                            };
13390                            original_indent_column = Some(clipboard_selection.first_line_indent);
13391                        } else {
13392                            to_insert = &*clipboard_text;
13393                            entire_line = all_selections_were_entire_line;
13394                            original_indent_column = first_selection_indent_column
13395                        }
13396
13397                        let (range, to_insert) =
13398                            if selection.is_empty() && handle_entire_lines && entire_line {
13399                                // If the corresponding selection was empty when this slice of the
13400                                // clipboard text was written, then the entire line containing the
13401                                // selection was copied. If this selection is also currently empty,
13402                                // then paste the line before the current line of the buffer.
13403                                let column = selection.start.to_point(&snapshot).column as usize;
13404                                let line_start = selection.start - column;
13405                                (line_start..line_start, Cow::Borrowed(to_insert))
13406                            } else {
13407                                let language = snapshot.language_at(selection.head());
13408                                let range = selection.range();
13409                                if let Some(language) = language
13410                                    && language.name() == "Markdown".into()
13411                                {
13412                                    edit_for_markdown_paste(
13413                                        &snapshot,
13414                                        range,
13415                                        to_insert,
13416                                        url::Url::parse(to_insert).ok(),
13417                                    )
13418                                } else {
13419                                    (range, Cow::Borrowed(to_insert))
13420                                }
13421                            };
13422
13423                        edits.push((range, to_insert));
13424                        original_indent_columns.push(original_indent_column);
13425                    }
13426                    drop(snapshot);
13427
13428                    buffer.edit(
13429                        edits,
13430                        if auto_indent_on_paste {
13431                            Some(AutoindentMode::Block {
13432                                original_indent_columns,
13433                            })
13434                        } else {
13435                            None
13436                        },
13437                        cx,
13438                    );
13439                });
13440
13441                let selections = this
13442                    .selections
13443                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13444                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13445            } else {
13446                let url = url::Url::parse(&clipboard_text).ok();
13447
13448                let auto_indent_mode = if !clipboard_text.is_empty() {
13449                    Some(AutoindentMode::Block {
13450                        original_indent_columns: Vec::new(),
13451                    })
13452                } else {
13453                    None
13454                };
13455
13456                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13457                    let snapshot = buffer.snapshot(cx);
13458
13459                    let anchors = old_selections
13460                        .iter()
13461                        .map(|s| {
13462                            let anchor = snapshot.anchor_after(s.head());
13463                            s.map(|_| anchor)
13464                        })
13465                        .collect::<Vec<_>>();
13466
13467                    let mut edits = Vec::new();
13468
13469                    for selection in old_selections.iter() {
13470                        let language = snapshot.language_at(selection.head());
13471                        let range = selection.range();
13472
13473                        let (edit_range, edit_text) = if let Some(language) = language
13474                            && language.name() == "Markdown".into()
13475                        {
13476                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13477                        } else {
13478                            (range, clipboard_text.clone())
13479                        };
13480
13481                        edits.push((edit_range, edit_text));
13482                    }
13483
13484                    drop(snapshot);
13485                    buffer.edit(edits, auto_indent_mode, cx);
13486
13487                    anchors
13488                });
13489
13490                this.change_selections(Default::default(), window, cx, |s| {
13491                    s.select_anchors(selection_anchors);
13492                });
13493            }
13494
13495            //   🤔                 |    ..     | show_in_menu |
13496            // | ..                  |   true        true
13497            // | had_edit_prediction |   false       true
13498
13499            let trigger_in_words =
13500                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13501
13502            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13503        });
13504    }
13505
13506    pub fn diff_clipboard_with_selection(
13507        &mut self,
13508        _: &DiffClipboardWithSelection,
13509        window: &mut Window,
13510        cx: &mut Context<Self>,
13511    ) {
13512        let selections = self
13513            .selections
13514            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13515
13516        if selections.is_empty() {
13517            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13518            return;
13519        };
13520
13521        let clipboard_text = match cx.read_from_clipboard() {
13522            Some(item) => match item.entries().first() {
13523                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13524                _ => None,
13525            },
13526            None => None,
13527        };
13528
13529        let Some(clipboard_text) = clipboard_text else {
13530            log::warn!("Clipboard doesn't contain text.");
13531            return;
13532        };
13533
13534        window.dispatch_action(
13535            Box::new(DiffClipboardWithSelectionData {
13536                clipboard_text,
13537                editor: cx.entity(),
13538            }),
13539            cx,
13540        );
13541    }
13542
13543    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13545        if let Some(item) = cx.read_from_clipboard() {
13546            let entries = item.entries();
13547
13548            match entries.first() {
13549                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13550                // of all the pasted entries.
13551                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13552                    .do_paste(
13553                        clipboard_string.text(),
13554                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13555                        true,
13556                        window,
13557                        cx,
13558                    ),
13559                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13560            }
13561        }
13562    }
13563
13564    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13565        if self.read_only(cx) {
13566            return;
13567        }
13568
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13570
13571        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13572            if let Some((selections, _)) =
13573                self.selection_history.transaction(transaction_id).cloned()
13574            {
13575                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13576                    s.select_anchors(selections.to_vec());
13577                });
13578            } else {
13579                log::error!(
13580                    "No entry in selection_history found for undo. \
13581                     This may correspond to a bug where undo does not update the selection. \
13582                     If this is occurring, please add details to \
13583                     https://github.com/zed-industries/zed/issues/22692"
13584                );
13585            }
13586            self.request_autoscroll(Autoscroll::fit(), cx);
13587            self.unmark_text(window, cx);
13588            self.refresh_edit_prediction(true, false, window, cx);
13589            cx.emit(EditorEvent::Edited { transaction_id });
13590            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13591        }
13592    }
13593
13594    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13595        if self.read_only(cx) {
13596            return;
13597        }
13598
13599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13600
13601        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13602            if let Some((_, Some(selections))) =
13603                self.selection_history.transaction(transaction_id).cloned()
13604            {
13605                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13606                    s.select_anchors(selections.to_vec());
13607                });
13608            } else {
13609                log::error!(
13610                    "No entry in selection_history found for redo. \
13611                     This may correspond to a bug where undo does not update the selection. \
13612                     If this is occurring, please add details to \
13613                     https://github.com/zed-industries/zed/issues/22692"
13614                );
13615            }
13616            self.request_autoscroll(Autoscroll::fit(), cx);
13617            self.unmark_text(window, cx);
13618            self.refresh_edit_prediction(true, false, window, cx);
13619            cx.emit(EditorEvent::Edited { transaction_id });
13620        }
13621    }
13622
13623    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13624        self.buffer
13625            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13626    }
13627
13628    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13629        self.buffer
13630            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13631    }
13632
13633    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13635        self.change_selections(Default::default(), window, cx, |s| {
13636            s.move_with(|map, selection| {
13637                let cursor = if selection.is_empty() {
13638                    movement::left(map, selection.start)
13639                } else {
13640                    selection.start
13641                };
13642                selection.collapse_to(cursor, SelectionGoal::None);
13643            });
13644        })
13645    }
13646
13647    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13649        self.change_selections(Default::default(), window, cx, |s| {
13650            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13651        })
13652    }
13653
13654    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13656        self.change_selections(Default::default(), window, cx, |s| {
13657            s.move_with(|map, selection| {
13658                let cursor = if selection.is_empty() {
13659                    movement::right(map, selection.end)
13660                } else {
13661                    selection.end
13662                };
13663                selection.collapse_to(cursor, SelectionGoal::None)
13664            });
13665        })
13666    }
13667
13668    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13669        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13670        self.change_selections(Default::default(), window, cx, |s| {
13671            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13672        });
13673    }
13674
13675    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13676        if self.take_rename(true, window, cx).is_some() {
13677            return;
13678        }
13679
13680        if self.mode.is_single_line() {
13681            cx.propagate();
13682            return;
13683        }
13684
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686
13687        let text_layout_details = &self.text_layout_details(window);
13688        let selection_count = self.selections.count();
13689        let first_selection = self.selections.first_anchor();
13690
13691        self.change_selections(Default::default(), window, cx, |s| {
13692            s.move_with(|map, selection| {
13693                if !selection.is_empty() {
13694                    selection.goal = SelectionGoal::None;
13695                }
13696                let (cursor, goal) = movement::up(
13697                    map,
13698                    selection.start,
13699                    selection.goal,
13700                    false,
13701                    text_layout_details,
13702                );
13703                selection.collapse_to(cursor, goal);
13704            });
13705        });
13706
13707        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13708        {
13709            cx.propagate();
13710        }
13711    }
13712
13713    pub fn move_up_by_lines(
13714        &mut self,
13715        action: &MoveUpByLines,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if self.take_rename(true, window, cx).is_some() {
13720            return;
13721        }
13722
13723        if self.mode.is_single_line() {
13724            cx.propagate();
13725            return;
13726        }
13727
13728        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13729
13730        let text_layout_details = &self.text_layout_details(window);
13731
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_with(|map, selection| {
13734                if !selection.is_empty() {
13735                    selection.goal = SelectionGoal::None;
13736                }
13737                let (cursor, goal) = movement::up_by_rows(
13738                    map,
13739                    selection.start,
13740                    action.lines,
13741                    selection.goal,
13742                    false,
13743                    text_layout_details,
13744                );
13745                selection.collapse_to(cursor, goal);
13746            });
13747        })
13748    }
13749
13750    pub fn move_down_by_lines(
13751        &mut self,
13752        action: &MoveDownByLines,
13753        window: &mut Window,
13754        cx: &mut Context<Self>,
13755    ) {
13756        if self.take_rename(true, window, cx).is_some() {
13757            return;
13758        }
13759
13760        if self.mode.is_single_line() {
13761            cx.propagate();
13762            return;
13763        }
13764
13765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13766
13767        let text_layout_details = &self.text_layout_details(window);
13768
13769        self.change_selections(Default::default(), window, cx, |s| {
13770            s.move_with(|map, selection| {
13771                if !selection.is_empty() {
13772                    selection.goal = SelectionGoal::None;
13773                }
13774                let (cursor, goal) = movement::down_by_rows(
13775                    map,
13776                    selection.start,
13777                    action.lines,
13778                    selection.goal,
13779                    false,
13780                    text_layout_details,
13781                );
13782                selection.collapse_to(cursor, goal);
13783            });
13784        })
13785    }
13786
13787    pub fn select_down_by_lines(
13788        &mut self,
13789        action: &SelectDownByLines,
13790        window: &mut Window,
13791        cx: &mut Context<Self>,
13792    ) {
13793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13794        let text_layout_details = &self.text_layout_details(window);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, goal| {
13797                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13798            })
13799        })
13800    }
13801
13802    pub fn select_up_by_lines(
13803        &mut self,
13804        action: &SelectUpByLines,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809        let text_layout_details = &self.text_layout_details(window);
13810        self.change_selections(Default::default(), window, cx, |s| {
13811            s.move_heads_with(|map, head, goal| {
13812                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13813            })
13814        })
13815    }
13816
13817    pub fn select_page_up(
13818        &mut self,
13819        _: &SelectPageUp,
13820        window: &mut Window,
13821        cx: &mut Context<Self>,
13822    ) {
13823        let Some(row_count) = self.visible_row_count() else {
13824            return;
13825        };
13826
13827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13828
13829        let text_layout_details = &self.text_layout_details(window);
13830
13831        self.change_selections(Default::default(), window, cx, |s| {
13832            s.move_heads_with(|map, head, goal| {
13833                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13834            })
13835        })
13836    }
13837
13838    pub fn move_page_up(
13839        &mut self,
13840        action: &MovePageUp,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) {
13844        if self.take_rename(true, window, cx).is_some() {
13845            return;
13846        }
13847
13848        if self
13849            .context_menu
13850            .borrow_mut()
13851            .as_mut()
13852            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13853            .unwrap_or(false)
13854        {
13855            return;
13856        }
13857
13858        if matches!(self.mode, EditorMode::SingleLine) {
13859            cx.propagate();
13860            return;
13861        }
13862
13863        let Some(row_count) = self.visible_row_count() else {
13864            return;
13865        };
13866
13867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13868
13869        let effects = if action.center_cursor {
13870            SelectionEffects::scroll(Autoscroll::center())
13871        } else {
13872            SelectionEffects::default()
13873        };
13874
13875        let text_layout_details = &self.text_layout_details(window);
13876
13877        self.change_selections(effects, window, cx, |s| {
13878            s.move_with(|map, selection| {
13879                if !selection.is_empty() {
13880                    selection.goal = SelectionGoal::None;
13881                }
13882                let (cursor, goal) = movement::up_by_rows(
13883                    map,
13884                    selection.end,
13885                    row_count,
13886                    selection.goal,
13887                    false,
13888                    text_layout_details,
13889                );
13890                selection.collapse_to(cursor, goal);
13891            });
13892        });
13893    }
13894
13895    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13897        let text_layout_details = &self.text_layout_details(window);
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_heads_with(|map, head, goal| {
13900                movement::up(map, head, goal, false, text_layout_details)
13901            })
13902        })
13903    }
13904
13905    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13906        self.take_rename(true, window, cx);
13907
13908        if self.mode.is_single_line() {
13909            cx.propagate();
13910            return;
13911        }
13912
13913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13914
13915        let text_layout_details = &self.text_layout_details(window);
13916        let selection_count = self.selections.count();
13917        let first_selection = self.selections.first_anchor();
13918
13919        self.change_selections(Default::default(), window, cx, |s| {
13920            s.move_with(|map, selection| {
13921                if !selection.is_empty() {
13922                    selection.goal = SelectionGoal::None;
13923                }
13924                let (cursor, goal) = movement::down(
13925                    map,
13926                    selection.end,
13927                    selection.goal,
13928                    false,
13929                    text_layout_details,
13930                );
13931                selection.collapse_to(cursor, goal);
13932            });
13933        });
13934
13935        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13936        {
13937            cx.propagate();
13938        }
13939    }
13940
13941    pub fn select_page_down(
13942        &mut self,
13943        _: &SelectPageDown,
13944        window: &mut Window,
13945        cx: &mut Context<Self>,
13946    ) {
13947        let Some(row_count) = self.visible_row_count() else {
13948            return;
13949        };
13950
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952
13953        let text_layout_details = &self.text_layout_details(window);
13954
13955        self.change_selections(Default::default(), window, cx, |s| {
13956            s.move_heads_with(|map, head, goal| {
13957                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13958            })
13959        })
13960    }
13961
13962    pub fn move_page_down(
13963        &mut self,
13964        action: &MovePageDown,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if self.take_rename(true, window, cx).is_some() {
13969            return;
13970        }
13971
13972        if self
13973            .context_menu
13974            .borrow_mut()
13975            .as_mut()
13976            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13977            .unwrap_or(false)
13978        {
13979            return;
13980        }
13981
13982        if matches!(self.mode, EditorMode::SingleLine) {
13983            cx.propagate();
13984            return;
13985        }
13986
13987        let Some(row_count) = self.visible_row_count() else {
13988            return;
13989        };
13990
13991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13992
13993        let effects = if action.center_cursor {
13994            SelectionEffects::scroll(Autoscroll::center())
13995        } else {
13996            SelectionEffects::default()
13997        };
13998
13999        let text_layout_details = &self.text_layout_details(window);
14000        self.change_selections(effects, window, cx, |s| {
14001            s.move_with(|map, selection| {
14002                if !selection.is_empty() {
14003                    selection.goal = SelectionGoal::None;
14004                }
14005                let (cursor, goal) = movement::down_by_rows(
14006                    map,
14007                    selection.end,
14008                    row_count,
14009                    selection.goal,
14010                    false,
14011                    text_layout_details,
14012                );
14013                selection.collapse_to(cursor, goal);
14014            });
14015        });
14016    }
14017
14018    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14020        let text_layout_details = &self.text_layout_details(window);
14021        self.change_selections(Default::default(), window, cx, |s| {
14022            s.move_heads_with(|map, head, goal| {
14023                movement::down(map, head, goal, false, text_layout_details)
14024            })
14025        });
14026    }
14027
14028    pub fn context_menu_first(
14029        &mut self,
14030        _: &ContextMenuFirst,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14035            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14036        }
14037    }
14038
14039    pub fn context_menu_prev(
14040        &mut self,
14041        _: &ContextMenuPrevious,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) {
14045        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14046            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14047        }
14048    }
14049
14050    pub fn context_menu_next(
14051        &mut self,
14052        _: &ContextMenuNext,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) {
14056        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14057            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14058        }
14059    }
14060
14061    pub fn context_menu_last(
14062        &mut self,
14063        _: &ContextMenuLast,
14064        window: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14068            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14069        }
14070    }
14071
14072    pub fn signature_help_prev(
14073        &mut self,
14074        _: &SignatureHelpPrevious,
14075        _: &mut Window,
14076        cx: &mut Context<Self>,
14077    ) {
14078        if let Some(popover) = self.signature_help_state.popover_mut() {
14079            if popover.current_signature == 0 {
14080                popover.current_signature = popover.signatures.len() - 1;
14081            } else {
14082                popover.current_signature -= 1;
14083            }
14084            cx.notify();
14085        }
14086    }
14087
14088    pub fn signature_help_next(
14089        &mut self,
14090        _: &SignatureHelpNext,
14091        _: &mut Window,
14092        cx: &mut Context<Self>,
14093    ) {
14094        if let Some(popover) = self.signature_help_state.popover_mut() {
14095            if popover.current_signature + 1 == popover.signatures.len() {
14096                popover.current_signature = 0;
14097            } else {
14098                popover.current_signature += 1;
14099            }
14100            cx.notify();
14101        }
14102    }
14103
14104    pub fn move_to_previous_word_start(
14105        &mut self,
14106        _: &MoveToPreviousWordStart,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) {
14110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14111        self.change_selections(Default::default(), window, cx, |s| {
14112            s.move_cursors_with(|map, head, _| {
14113                (
14114                    movement::previous_word_start(map, head),
14115                    SelectionGoal::None,
14116                )
14117            });
14118        })
14119    }
14120
14121    pub fn move_to_previous_subword_start(
14122        &mut self,
14123        _: &MoveToPreviousSubwordStart,
14124        window: &mut Window,
14125        cx: &mut Context<Self>,
14126    ) {
14127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14128        self.change_selections(Default::default(), window, cx, |s| {
14129            s.move_cursors_with(|map, head, _| {
14130                (
14131                    movement::previous_subword_start(map, head),
14132                    SelectionGoal::None,
14133                )
14134            });
14135        })
14136    }
14137
14138    pub fn select_to_previous_word_start(
14139        &mut self,
14140        _: &SelectToPreviousWordStart,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) {
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145        self.change_selections(Default::default(), window, cx, |s| {
14146            s.move_heads_with(|map, head, _| {
14147                (
14148                    movement::previous_word_start(map, head),
14149                    SelectionGoal::None,
14150                )
14151            });
14152        })
14153    }
14154
14155    pub fn select_to_previous_subword_start(
14156        &mut self,
14157        _: &SelectToPreviousSubwordStart,
14158        window: &mut Window,
14159        cx: &mut Context<Self>,
14160    ) {
14161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14162        self.change_selections(Default::default(), window, cx, |s| {
14163            s.move_heads_with(|map, head, _| {
14164                (
14165                    movement::previous_subword_start(map, head),
14166                    SelectionGoal::None,
14167                )
14168            });
14169        })
14170    }
14171
14172    pub fn delete_to_previous_word_start(
14173        &mut self,
14174        action: &DeleteToPreviousWordStart,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14179        self.transact(window, cx, |this, window, cx| {
14180            this.select_autoclose_pair(window, cx);
14181            this.change_selections(Default::default(), window, cx, |s| {
14182                s.move_with(|map, selection| {
14183                    if selection.is_empty() {
14184                        let mut cursor = if action.ignore_newlines {
14185                            movement::previous_word_start(map, selection.head())
14186                        } else {
14187                            movement::previous_word_start_or_newline(map, selection.head())
14188                        };
14189                        cursor = movement::adjust_greedy_deletion(
14190                            map,
14191                            selection.head(),
14192                            cursor,
14193                            action.ignore_brackets,
14194                        );
14195                        selection.set_head(cursor, SelectionGoal::None);
14196                    }
14197                });
14198            });
14199            this.insert("", window, cx);
14200        });
14201    }
14202
14203    pub fn delete_to_previous_subword_start(
14204        &mut self,
14205        action: &DeleteToPreviousSubwordStart,
14206        window: &mut Window,
14207        cx: &mut Context<Self>,
14208    ) {
14209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14210        self.transact(window, cx, |this, window, cx| {
14211            this.select_autoclose_pair(window, cx);
14212            this.change_selections(Default::default(), window, cx, |s| {
14213                s.move_with(|map, selection| {
14214                    if selection.is_empty() {
14215                        let mut cursor = if action.ignore_newlines {
14216                            movement::previous_subword_start(map, selection.head())
14217                        } else {
14218                            movement::previous_subword_start_or_newline(map, selection.head())
14219                        };
14220                        cursor = movement::adjust_greedy_deletion(
14221                            map,
14222                            selection.head(),
14223                            cursor,
14224                            action.ignore_brackets,
14225                        );
14226                        selection.set_head(cursor, SelectionGoal::None);
14227                    }
14228                });
14229            });
14230            this.insert("", window, cx);
14231        });
14232    }
14233
14234    pub fn move_to_next_word_end(
14235        &mut self,
14236        _: &MoveToNextWordEnd,
14237        window: &mut Window,
14238        cx: &mut Context<Self>,
14239    ) {
14240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14241        self.change_selections(Default::default(), window, cx, |s| {
14242            s.move_cursors_with(|map, head, _| {
14243                (movement::next_word_end(map, head), SelectionGoal::None)
14244            });
14245        })
14246    }
14247
14248    pub fn move_to_next_subword_end(
14249        &mut self,
14250        _: &MoveToNextSubwordEnd,
14251        window: &mut Window,
14252        cx: &mut Context<Self>,
14253    ) {
14254        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14255        self.change_selections(Default::default(), window, cx, |s| {
14256            s.move_cursors_with(|map, head, _| {
14257                (movement::next_subword_end(map, head), SelectionGoal::None)
14258            });
14259        })
14260    }
14261
14262    pub fn select_to_next_word_end(
14263        &mut self,
14264        _: &SelectToNextWordEnd,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) {
14268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14269        self.change_selections(Default::default(), window, cx, |s| {
14270            s.move_heads_with(|map, head, _| {
14271                (movement::next_word_end(map, head), SelectionGoal::None)
14272            });
14273        })
14274    }
14275
14276    pub fn select_to_next_subword_end(
14277        &mut self,
14278        _: &SelectToNextSubwordEnd,
14279        window: &mut Window,
14280        cx: &mut Context<Self>,
14281    ) {
14282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14283        self.change_selections(Default::default(), window, cx, |s| {
14284            s.move_heads_with(|map, head, _| {
14285                (movement::next_subword_end(map, head), SelectionGoal::None)
14286            });
14287        })
14288    }
14289
14290    pub fn delete_to_next_word_end(
14291        &mut self,
14292        action: &DeleteToNextWordEnd,
14293        window: &mut Window,
14294        cx: &mut Context<Self>,
14295    ) {
14296        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14297        self.transact(window, cx, |this, window, cx| {
14298            this.change_selections(Default::default(), window, cx, |s| {
14299                s.move_with(|map, selection| {
14300                    if selection.is_empty() {
14301                        let mut cursor = if action.ignore_newlines {
14302                            movement::next_word_end(map, selection.head())
14303                        } else {
14304                            movement::next_word_end_or_newline(map, selection.head())
14305                        };
14306                        cursor = movement::adjust_greedy_deletion(
14307                            map,
14308                            selection.head(),
14309                            cursor,
14310                            action.ignore_brackets,
14311                        );
14312                        selection.set_head(cursor, SelectionGoal::None);
14313                    }
14314                });
14315            });
14316            this.insert("", window, cx);
14317        });
14318    }
14319
14320    pub fn delete_to_next_subword_end(
14321        &mut self,
14322        action: &DeleteToNextSubwordEnd,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) {
14326        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14327        self.transact(window, cx, |this, window, cx| {
14328            this.change_selections(Default::default(), window, cx, |s| {
14329                s.move_with(|map, selection| {
14330                    if selection.is_empty() {
14331                        let mut cursor = if action.ignore_newlines {
14332                            movement::next_subword_end(map, selection.head())
14333                        } else {
14334                            movement::next_subword_end_or_newline(map, selection.head())
14335                        };
14336                        cursor = movement::adjust_greedy_deletion(
14337                            map,
14338                            selection.head(),
14339                            cursor,
14340                            action.ignore_brackets,
14341                        );
14342                        selection.set_head(cursor, SelectionGoal::None);
14343                    }
14344                });
14345            });
14346            this.insert("", window, cx);
14347        });
14348    }
14349
14350    pub fn move_to_beginning_of_line(
14351        &mut self,
14352        action: &MoveToBeginningOfLine,
14353        window: &mut Window,
14354        cx: &mut Context<Self>,
14355    ) {
14356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14357        self.change_selections(Default::default(), window, cx, |s| {
14358            s.move_cursors_with(|map, head, _| {
14359                (
14360                    movement::indented_line_beginning(
14361                        map,
14362                        head,
14363                        action.stop_at_soft_wraps,
14364                        action.stop_at_indent,
14365                    ),
14366                    SelectionGoal::None,
14367                )
14368            });
14369        })
14370    }
14371
14372    pub fn select_to_beginning_of_line(
14373        &mut self,
14374        action: &SelectToBeginningOfLine,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14379        self.change_selections(Default::default(), window, cx, |s| {
14380            s.move_heads_with(|map, head, _| {
14381                (
14382                    movement::indented_line_beginning(
14383                        map,
14384                        head,
14385                        action.stop_at_soft_wraps,
14386                        action.stop_at_indent,
14387                    ),
14388                    SelectionGoal::None,
14389                )
14390            });
14391        });
14392    }
14393
14394    pub fn delete_to_beginning_of_line(
14395        &mut self,
14396        action: &DeleteToBeginningOfLine,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14401        self.transact(window, cx, |this, window, cx| {
14402            this.change_selections(Default::default(), window, cx, |s| {
14403                s.move_with(|_, selection| {
14404                    selection.reversed = true;
14405                });
14406            });
14407
14408            this.select_to_beginning_of_line(
14409                &SelectToBeginningOfLine {
14410                    stop_at_soft_wraps: false,
14411                    stop_at_indent: action.stop_at_indent,
14412                },
14413                window,
14414                cx,
14415            );
14416            this.backspace(&Backspace, window, cx);
14417        });
14418    }
14419
14420    pub fn move_to_end_of_line(
14421        &mut self,
14422        action: &MoveToEndOfLine,
14423        window: &mut Window,
14424        cx: &mut Context<Self>,
14425    ) {
14426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14427        self.change_selections(Default::default(), window, cx, |s| {
14428            s.move_cursors_with(|map, head, _| {
14429                (
14430                    movement::line_end(map, head, action.stop_at_soft_wraps),
14431                    SelectionGoal::None,
14432                )
14433            });
14434        })
14435    }
14436
14437    pub fn select_to_end_of_line(
14438        &mut self,
14439        action: &SelectToEndOfLine,
14440        window: &mut Window,
14441        cx: &mut Context<Self>,
14442    ) {
14443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14444        self.change_selections(Default::default(), window, cx, |s| {
14445            s.move_heads_with(|map, head, _| {
14446                (
14447                    movement::line_end(map, head, action.stop_at_soft_wraps),
14448                    SelectionGoal::None,
14449                )
14450            });
14451        })
14452    }
14453
14454    pub fn delete_to_end_of_line(
14455        &mut self,
14456        _: &DeleteToEndOfLine,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) {
14460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14461        self.transact(window, cx, |this, window, cx| {
14462            this.select_to_end_of_line(
14463                &SelectToEndOfLine {
14464                    stop_at_soft_wraps: false,
14465                },
14466                window,
14467                cx,
14468            );
14469            this.delete(&Delete, window, cx);
14470        });
14471    }
14472
14473    pub fn cut_to_end_of_line(
14474        &mut self,
14475        action: &CutToEndOfLine,
14476        window: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) {
14479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14480        self.transact(window, cx, |this, window, cx| {
14481            this.select_to_end_of_line(
14482                &SelectToEndOfLine {
14483                    stop_at_soft_wraps: false,
14484                },
14485                window,
14486                cx,
14487            );
14488            if !action.stop_at_newlines {
14489                this.change_selections(Default::default(), window, cx, |s| {
14490                    s.move_with(|_, sel| {
14491                        if sel.is_empty() {
14492                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14493                        }
14494                    });
14495                });
14496            }
14497            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14498            let item = this.cut_common(false, window, cx);
14499            cx.write_to_clipboard(item);
14500        });
14501    }
14502
14503    pub fn move_to_start_of_paragraph(
14504        &mut self,
14505        _: &MoveToStartOfParagraph,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) {
14509        if matches!(self.mode, EditorMode::SingleLine) {
14510            cx.propagate();
14511            return;
14512        }
14513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14514        self.change_selections(Default::default(), window, cx, |s| {
14515            s.move_with(|map, selection| {
14516                selection.collapse_to(
14517                    movement::start_of_paragraph(map, selection.head(), 1),
14518                    SelectionGoal::None,
14519                )
14520            });
14521        })
14522    }
14523
14524    pub fn move_to_end_of_paragraph(
14525        &mut self,
14526        _: &MoveToEndOfParagraph,
14527        window: &mut Window,
14528        cx: &mut Context<Self>,
14529    ) {
14530        if matches!(self.mode, EditorMode::SingleLine) {
14531            cx.propagate();
14532            return;
14533        }
14534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14535        self.change_selections(Default::default(), window, cx, |s| {
14536            s.move_with(|map, selection| {
14537                selection.collapse_to(
14538                    movement::end_of_paragraph(map, selection.head(), 1),
14539                    SelectionGoal::None,
14540                )
14541            });
14542        })
14543    }
14544
14545    pub fn select_to_start_of_paragraph(
14546        &mut self,
14547        _: &SelectToStartOfParagraph,
14548        window: &mut Window,
14549        cx: &mut Context<Self>,
14550    ) {
14551        if matches!(self.mode, EditorMode::SingleLine) {
14552            cx.propagate();
14553            return;
14554        }
14555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14556        self.change_selections(Default::default(), window, cx, |s| {
14557            s.move_heads_with(|map, head, _| {
14558                (
14559                    movement::start_of_paragraph(map, head, 1),
14560                    SelectionGoal::None,
14561                )
14562            });
14563        })
14564    }
14565
14566    pub fn select_to_end_of_paragraph(
14567        &mut self,
14568        _: &SelectToEndOfParagraph,
14569        window: &mut Window,
14570        cx: &mut Context<Self>,
14571    ) {
14572        if matches!(self.mode, EditorMode::SingleLine) {
14573            cx.propagate();
14574            return;
14575        }
14576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14577        self.change_selections(Default::default(), window, cx, |s| {
14578            s.move_heads_with(|map, head, _| {
14579                (
14580                    movement::end_of_paragraph(map, head, 1),
14581                    SelectionGoal::None,
14582                )
14583            });
14584        })
14585    }
14586
14587    pub fn move_to_start_of_excerpt(
14588        &mut self,
14589        _: &MoveToStartOfExcerpt,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if matches!(self.mode, EditorMode::SingleLine) {
14594            cx.propagate();
14595            return;
14596        }
14597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14598        self.change_selections(Default::default(), window, cx, |s| {
14599            s.move_with(|map, selection| {
14600                selection.collapse_to(
14601                    movement::start_of_excerpt(
14602                        map,
14603                        selection.head(),
14604                        workspace::searchable::Direction::Prev,
14605                    ),
14606                    SelectionGoal::None,
14607                )
14608            });
14609        })
14610    }
14611
14612    pub fn move_to_start_of_next_excerpt(
14613        &mut self,
14614        _: &MoveToStartOfNextExcerpt,
14615        window: &mut Window,
14616        cx: &mut Context<Self>,
14617    ) {
14618        if matches!(self.mode, EditorMode::SingleLine) {
14619            cx.propagate();
14620            return;
14621        }
14622
14623        self.change_selections(Default::default(), window, cx, |s| {
14624            s.move_with(|map, selection| {
14625                selection.collapse_to(
14626                    movement::start_of_excerpt(
14627                        map,
14628                        selection.head(),
14629                        workspace::searchable::Direction::Next,
14630                    ),
14631                    SelectionGoal::None,
14632                )
14633            });
14634        })
14635    }
14636
14637    pub fn move_to_end_of_excerpt(
14638        &mut self,
14639        _: &MoveToEndOfExcerpt,
14640        window: &mut Window,
14641        cx: &mut Context<Self>,
14642    ) {
14643        if matches!(self.mode, EditorMode::SingleLine) {
14644            cx.propagate();
14645            return;
14646        }
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        self.change_selections(Default::default(), window, cx, |s| {
14649            s.move_with(|map, selection| {
14650                selection.collapse_to(
14651                    movement::end_of_excerpt(
14652                        map,
14653                        selection.head(),
14654                        workspace::searchable::Direction::Next,
14655                    ),
14656                    SelectionGoal::None,
14657                )
14658            });
14659        })
14660    }
14661
14662    pub fn move_to_end_of_previous_excerpt(
14663        &mut self,
14664        _: &MoveToEndOfPreviousExcerpt,
14665        window: &mut Window,
14666        cx: &mut Context<Self>,
14667    ) {
14668        if matches!(self.mode, EditorMode::SingleLine) {
14669            cx.propagate();
14670            return;
14671        }
14672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14673        self.change_selections(Default::default(), window, cx, |s| {
14674            s.move_with(|map, selection| {
14675                selection.collapse_to(
14676                    movement::end_of_excerpt(
14677                        map,
14678                        selection.head(),
14679                        workspace::searchable::Direction::Prev,
14680                    ),
14681                    SelectionGoal::None,
14682                )
14683            });
14684        })
14685    }
14686
14687    pub fn select_to_start_of_excerpt(
14688        &mut self,
14689        _: &SelectToStartOfExcerpt,
14690        window: &mut Window,
14691        cx: &mut Context<Self>,
14692    ) {
14693        if matches!(self.mode, EditorMode::SingleLine) {
14694            cx.propagate();
14695            return;
14696        }
14697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14698        self.change_selections(Default::default(), window, cx, |s| {
14699            s.move_heads_with(|map, head, _| {
14700                (
14701                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14702                    SelectionGoal::None,
14703                )
14704            });
14705        })
14706    }
14707
14708    pub fn select_to_start_of_next_excerpt(
14709        &mut self,
14710        _: &SelectToStartOfNextExcerpt,
14711        window: &mut Window,
14712        cx: &mut Context<Self>,
14713    ) {
14714        if matches!(self.mode, EditorMode::SingleLine) {
14715            cx.propagate();
14716            return;
14717        }
14718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14719        self.change_selections(Default::default(), window, cx, |s| {
14720            s.move_heads_with(|map, head, _| {
14721                (
14722                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14723                    SelectionGoal::None,
14724                )
14725            });
14726        })
14727    }
14728
14729    pub fn select_to_end_of_excerpt(
14730        &mut self,
14731        _: &SelectToEndOfExcerpt,
14732        window: &mut Window,
14733        cx: &mut Context<Self>,
14734    ) {
14735        if matches!(self.mode, EditorMode::SingleLine) {
14736            cx.propagate();
14737            return;
14738        }
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740        self.change_selections(Default::default(), window, cx, |s| {
14741            s.move_heads_with(|map, head, _| {
14742                (
14743                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14744                    SelectionGoal::None,
14745                )
14746            });
14747        })
14748    }
14749
14750    pub fn select_to_end_of_previous_excerpt(
14751        &mut self,
14752        _: &SelectToEndOfPreviousExcerpt,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) {
14756        if matches!(self.mode, EditorMode::SingleLine) {
14757            cx.propagate();
14758            return;
14759        }
14760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14761        self.change_selections(Default::default(), window, cx, |s| {
14762            s.move_heads_with(|map, head, _| {
14763                (
14764                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14765                    SelectionGoal::None,
14766                )
14767            });
14768        })
14769    }
14770
14771    pub fn move_to_beginning(
14772        &mut self,
14773        _: &MoveToBeginning,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) {
14777        if matches!(self.mode, EditorMode::SingleLine) {
14778            cx.propagate();
14779            return;
14780        }
14781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14782        self.change_selections(Default::default(), window, cx, |s| {
14783            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14784        });
14785    }
14786
14787    pub fn select_to_beginning(
14788        &mut self,
14789        _: &SelectToBeginning,
14790        window: &mut Window,
14791        cx: &mut Context<Self>,
14792    ) {
14793        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14794        selection.set_head(Point::zero(), SelectionGoal::None);
14795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14796        self.change_selections(Default::default(), window, cx, |s| {
14797            s.select(vec![selection]);
14798        });
14799    }
14800
14801    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14802        if matches!(self.mode, EditorMode::SingleLine) {
14803            cx.propagate();
14804            return;
14805        }
14806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14807        let cursor = self.buffer.read(cx).read(cx).len();
14808        self.change_selections(Default::default(), window, cx, |s| {
14809            s.select_ranges(vec![cursor..cursor])
14810        });
14811    }
14812
14813    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14814        self.nav_history = nav_history;
14815    }
14816
14817    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14818        self.nav_history.as_ref()
14819    }
14820
14821    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14822        self.push_to_nav_history(
14823            self.selections.newest_anchor().head(),
14824            None,
14825            false,
14826            true,
14827            cx,
14828        );
14829    }
14830
14831    fn push_to_nav_history(
14832        &mut self,
14833        cursor_anchor: Anchor,
14834        new_position: Option<Point>,
14835        is_deactivate: bool,
14836        always: bool,
14837        cx: &mut Context<Self>,
14838    ) {
14839        if let Some(nav_history) = self.nav_history.as_mut() {
14840            let buffer = self.buffer.read(cx).read(cx);
14841            let cursor_position = cursor_anchor.to_point(&buffer);
14842            let scroll_state = self.scroll_manager.anchor();
14843            let scroll_top_row = scroll_state.top_row(&buffer);
14844            drop(buffer);
14845
14846            if let Some(new_position) = new_position {
14847                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14848                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14849                    return;
14850                }
14851            }
14852
14853            nav_history.push(
14854                Some(NavigationData {
14855                    cursor_anchor,
14856                    cursor_position,
14857                    scroll_anchor: scroll_state,
14858                    scroll_top_row,
14859                }),
14860                cx,
14861            );
14862            cx.emit(EditorEvent::PushedToNavHistory {
14863                anchor: cursor_anchor,
14864                is_deactivate,
14865            })
14866        }
14867    }
14868
14869    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14870        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14871        let buffer = self.buffer.read(cx).snapshot(cx);
14872        let mut selection = self
14873            .selections
14874            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14875        selection.set_head(buffer.len(), SelectionGoal::None);
14876        self.change_selections(Default::default(), window, cx, |s| {
14877            s.select(vec![selection]);
14878        });
14879    }
14880
14881    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14883        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14884            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14885        });
14886    }
14887
14888    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14890        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14891        let mut selections = self.selections.all::<Point>(&display_map);
14892        let max_point = display_map.buffer_snapshot().max_point();
14893        for selection in &mut selections {
14894            let rows = selection.spanned_rows(true, &display_map);
14895            selection.start = Point::new(rows.start.0, 0);
14896            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14897            selection.reversed = false;
14898        }
14899        self.change_selections(Default::default(), window, cx, |s| {
14900            s.select(selections);
14901        });
14902    }
14903
14904    pub fn split_selection_into_lines(
14905        &mut self,
14906        action: &SplitSelectionIntoLines,
14907        window: &mut Window,
14908        cx: &mut Context<Self>,
14909    ) {
14910        let selections = self
14911            .selections
14912            .all::<Point>(&self.display_snapshot(cx))
14913            .into_iter()
14914            .map(|selection| selection.start..selection.end)
14915            .collect::<Vec<_>>();
14916        self.unfold_ranges(&selections, true, true, cx);
14917
14918        let mut new_selection_ranges = Vec::new();
14919        {
14920            let buffer = self.buffer.read(cx).read(cx);
14921            for selection in selections {
14922                for row in selection.start.row..selection.end.row {
14923                    let line_start = Point::new(row, 0);
14924                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14925
14926                    if action.keep_selections {
14927                        // Keep the selection range for each line
14928                        let selection_start = if row == selection.start.row {
14929                            selection.start
14930                        } else {
14931                            line_start
14932                        };
14933                        new_selection_ranges.push(selection_start..line_end);
14934                    } else {
14935                        // Collapse to cursor at end of line
14936                        new_selection_ranges.push(line_end..line_end);
14937                    }
14938                }
14939
14940                let is_multiline_selection = selection.start.row != selection.end.row;
14941                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14942                // so this action feels more ergonomic when paired with other selection operations
14943                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14944                if !should_skip_last {
14945                    if action.keep_selections {
14946                        if is_multiline_selection {
14947                            let line_start = Point::new(selection.end.row, 0);
14948                            new_selection_ranges.push(line_start..selection.end);
14949                        } else {
14950                            new_selection_ranges.push(selection.start..selection.end);
14951                        }
14952                    } else {
14953                        new_selection_ranges.push(selection.end..selection.end);
14954                    }
14955                }
14956            }
14957        }
14958        self.change_selections(Default::default(), window, cx, |s| {
14959            s.select_ranges(new_selection_ranges);
14960        });
14961    }
14962
14963    pub fn add_selection_above(
14964        &mut self,
14965        action: &AddSelectionAbove,
14966        window: &mut Window,
14967        cx: &mut Context<Self>,
14968    ) {
14969        self.add_selection(true, action.skip_soft_wrap, window, cx);
14970    }
14971
14972    pub fn add_selection_below(
14973        &mut self,
14974        action: &AddSelectionBelow,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) {
14978        self.add_selection(false, action.skip_soft_wrap, window, cx);
14979    }
14980
14981    fn add_selection(
14982        &mut self,
14983        above: bool,
14984        skip_soft_wrap: bool,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) {
14988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14989
14990        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14991        let all_selections = self.selections.all::<Point>(&display_map);
14992        let text_layout_details = self.text_layout_details(window);
14993
14994        let (mut columnar_selections, new_selections_to_columnarize) = {
14995            if let Some(state) = self.add_selections_state.as_ref() {
14996                let columnar_selection_ids: HashSet<_> = state
14997                    .groups
14998                    .iter()
14999                    .flat_map(|group| group.stack.iter())
15000                    .copied()
15001                    .collect();
15002
15003                all_selections
15004                    .into_iter()
15005                    .partition(|s| columnar_selection_ids.contains(&s.id))
15006            } else {
15007                (Vec::new(), all_selections)
15008            }
15009        };
15010
15011        let mut state = self
15012            .add_selections_state
15013            .take()
15014            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15015
15016        for selection in new_selections_to_columnarize {
15017            let range = selection.display_range(&display_map).sorted();
15018            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15019            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15020            let positions = start_x.min(end_x)..start_x.max(end_x);
15021            let mut stack = Vec::new();
15022            for row in range.start.row().0..=range.end.row().0 {
15023                if let Some(selection) = self.selections.build_columnar_selection(
15024                    &display_map,
15025                    DisplayRow(row),
15026                    &positions,
15027                    selection.reversed,
15028                    &text_layout_details,
15029                ) {
15030                    stack.push(selection.id);
15031                    columnar_selections.push(selection);
15032                }
15033            }
15034            if !stack.is_empty() {
15035                if above {
15036                    stack.reverse();
15037                }
15038                state.groups.push(AddSelectionsGroup { above, stack });
15039            }
15040        }
15041
15042        let mut final_selections = Vec::new();
15043        let end_row = if above {
15044            DisplayRow(0)
15045        } else {
15046            display_map.max_point().row()
15047        };
15048
15049        let mut last_added_item_per_group = HashMap::default();
15050        for group in state.groups.iter_mut() {
15051            if let Some(last_id) = group.stack.last() {
15052                last_added_item_per_group.insert(*last_id, group);
15053            }
15054        }
15055
15056        for selection in columnar_selections {
15057            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15058                if above == group.above {
15059                    let range = selection.display_range(&display_map).sorted();
15060                    debug_assert_eq!(range.start.row(), range.end.row());
15061                    let mut row = range.start.row();
15062                    let positions =
15063                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15064                            Pixels::from(start)..Pixels::from(end)
15065                        } else {
15066                            let start_x =
15067                                display_map.x_for_display_point(range.start, &text_layout_details);
15068                            let end_x =
15069                                display_map.x_for_display_point(range.end, &text_layout_details);
15070                            start_x.min(end_x)..start_x.max(end_x)
15071                        };
15072
15073                    let mut maybe_new_selection = None;
15074                    let direction = if above { -1 } else { 1 };
15075
15076                    while row != end_row {
15077                        let new_buffer_row = if skip_soft_wrap {
15078                            let new_row = display_map
15079                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15080                            row = new_row.row();
15081                            Some(new_row.to_point(&display_map).row)
15082                        } else {
15083                            if above {
15084                                row.0 -= 1;
15085                            } else {
15086                                row.0 += 1;
15087                            }
15088                            None
15089                        };
15090
15091                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15092                            let start_col = selection.start.column;
15093                            let end_col = selection.end.column;
15094                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15095
15096                            self.selections
15097                                .build_columnar_selection_from_buffer_columns(
15098                                    &display_map,
15099                                    buffer_row,
15100                                    &buffer_columns,
15101                                    selection.reversed,
15102                                    &text_layout_details,
15103                                )
15104                        } else {
15105                            self.selections.build_columnar_selection(
15106                                &display_map,
15107                                row,
15108                                &positions,
15109                                selection.reversed,
15110                                &text_layout_details,
15111                            )
15112                        };
15113
15114                        if let Some(new_selection) = new_selection {
15115                            maybe_new_selection = Some(new_selection);
15116                            break;
15117                        }
15118                    }
15119
15120                    if let Some(new_selection) = maybe_new_selection {
15121                        group.stack.push(new_selection.id);
15122                        if above {
15123                            final_selections.push(new_selection);
15124                            final_selections.push(selection);
15125                        } else {
15126                            final_selections.push(selection);
15127                            final_selections.push(new_selection);
15128                        }
15129                    } else {
15130                        final_selections.push(selection);
15131                    }
15132                } else {
15133                    group.stack.pop();
15134                }
15135            } else {
15136                final_selections.push(selection);
15137            }
15138        }
15139
15140        self.change_selections(Default::default(), window, cx, |s| {
15141            s.select(final_selections);
15142        });
15143
15144        let final_selection_ids: HashSet<_> = self
15145            .selections
15146            .all::<Point>(&display_map)
15147            .iter()
15148            .map(|s| s.id)
15149            .collect();
15150        state.groups.retain_mut(|group| {
15151            // selections might get merged above so we remove invalid items from stacks
15152            group.stack.retain(|id| final_selection_ids.contains(id));
15153
15154            // single selection in stack can be treated as initial state
15155            group.stack.len() > 1
15156        });
15157
15158        if !state.groups.is_empty() {
15159            self.add_selections_state = Some(state);
15160        }
15161    }
15162
15163    pub fn insert_snippet_at_selections(
15164        &mut self,
15165        action: &InsertSnippet,
15166        window: &mut Window,
15167        cx: &mut Context<Self>,
15168    ) {
15169        self.try_insert_snippet_at_selections(action, window, cx)
15170            .log_err();
15171    }
15172
15173    fn try_insert_snippet_at_selections(
15174        &mut self,
15175        action: &InsertSnippet,
15176        window: &mut Window,
15177        cx: &mut Context<Self>,
15178    ) -> Result<()> {
15179        let insertion_ranges = self
15180            .selections
15181            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15182            .into_iter()
15183            .map(|selection| selection.range())
15184            .collect_vec();
15185
15186        let snippet = if let Some(snippet_body) = &action.snippet {
15187            if action.language.is_none() && action.name.is_none() {
15188                Snippet::parse(snippet_body)?
15189            } else {
15190                bail!("`snippet` is mutually exclusive with `language` and `name`")
15191            }
15192        } else if let Some(name) = &action.name {
15193            let project = self.project().context("no project")?;
15194            let snippet_store = project.read(cx).snippets().read(cx);
15195            let snippet = snippet_store
15196                .snippets_for(action.language.clone(), cx)
15197                .into_iter()
15198                .find(|snippet| snippet.name == *name)
15199                .context("snippet not found")?;
15200            Snippet::parse(&snippet.body)?
15201        } else {
15202            // todo(andrew): open modal to select snippet
15203            bail!("`name` or `snippet` is required")
15204        };
15205
15206        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15207    }
15208
15209    fn select_match_ranges(
15210        &mut self,
15211        range: Range<MultiBufferOffset>,
15212        reversed: bool,
15213        replace_newest: bool,
15214        auto_scroll: Option<Autoscroll>,
15215        window: &mut Window,
15216        cx: &mut Context<Editor>,
15217    ) {
15218        self.unfold_ranges(
15219            std::slice::from_ref(&range),
15220            false,
15221            auto_scroll.is_some(),
15222            cx,
15223        );
15224        let effects = if let Some(scroll) = auto_scroll {
15225            SelectionEffects::scroll(scroll)
15226        } else {
15227            SelectionEffects::no_scroll()
15228        };
15229        self.change_selections(effects, window, cx, |s| {
15230            if replace_newest {
15231                s.delete(s.newest_anchor().id);
15232            }
15233            if reversed {
15234                s.insert_range(range.end..range.start);
15235            } else {
15236                s.insert_range(range);
15237            }
15238        });
15239    }
15240
15241    pub fn select_next_match_internal(
15242        &mut self,
15243        display_map: &DisplaySnapshot,
15244        replace_newest: bool,
15245        autoscroll: Option<Autoscroll>,
15246        window: &mut Window,
15247        cx: &mut Context<Self>,
15248    ) -> Result<()> {
15249        let buffer = display_map.buffer_snapshot();
15250        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15251        if let Some(mut select_next_state) = self.select_next_state.take() {
15252            let query = &select_next_state.query;
15253            if !select_next_state.done {
15254                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15255                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15256                let mut next_selected_range = None;
15257
15258                let bytes_after_last_selection =
15259                    buffer.bytes_in_range(last_selection.end..buffer.len());
15260                let bytes_before_first_selection =
15261                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15262                let query_matches = query
15263                    .stream_find_iter(bytes_after_last_selection)
15264                    .map(|result| (last_selection.end, result))
15265                    .chain(
15266                        query
15267                            .stream_find_iter(bytes_before_first_selection)
15268                            .map(|result| (MultiBufferOffset(0), result)),
15269                    );
15270
15271                for (start_offset, query_match) in query_matches {
15272                    let query_match = query_match.unwrap(); // can only fail due to I/O
15273                    let offset_range =
15274                        start_offset + query_match.start()..start_offset + query_match.end();
15275
15276                    if !select_next_state.wordwise
15277                        || (!buffer.is_inside_word(offset_range.start, None)
15278                            && !buffer.is_inside_word(offset_range.end, None))
15279                    {
15280                        let idx = selections
15281                            .partition_point(|selection| selection.end <= offset_range.start);
15282                        let overlaps = selections
15283                            .get(idx)
15284                            .map_or(false, |selection| selection.start < offset_range.end);
15285
15286                        if !overlaps {
15287                            next_selected_range = Some(offset_range);
15288                            break;
15289                        }
15290                    }
15291                }
15292
15293                if let Some(next_selected_range) = next_selected_range {
15294                    self.select_match_ranges(
15295                        next_selected_range,
15296                        last_selection.reversed,
15297                        replace_newest,
15298                        autoscroll,
15299                        window,
15300                        cx,
15301                    );
15302                } else {
15303                    select_next_state.done = true;
15304                }
15305            }
15306
15307            self.select_next_state = Some(select_next_state);
15308        } else {
15309            let mut only_carets = true;
15310            let mut same_text_selected = true;
15311            let mut selected_text = None;
15312
15313            let mut selections_iter = selections.iter().peekable();
15314            while let Some(selection) = selections_iter.next() {
15315                if selection.start != selection.end {
15316                    only_carets = false;
15317                }
15318
15319                if same_text_selected {
15320                    if selected_text.is_none() {
15321                        selected_text =
15322                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15323                    }
15324
15325                    if let Some(next_selection) = selections_iter.peek() {
15326                        if next_selection.len() == selection.len() {
15327                            let next_selected_text = buffer
15328                                .text_for_range(next_selection.range())
15329                                .collect::<String>();
15330                            if Some(next_selected_text) != selected_text {
15331                                same_text_selected = false;
15332                                selected_text = None;
15333                            }
15334                        } else {
15335                            same_text_selected = false;
15336                            selected_text = None;
15337                        }
15338                    }
15339                }
15340            }
15341
15342            if only_carets {
15343                for selection in &mut selections {
15344                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15345                    selection.start = word_range.start;
15346                    selection.end = word_range.end;
15347                    selection.goal = SelectionGoal::None;
15348                    selection.reversed = false;
15349                    self.select_match_ranges(
15350                        selection.start..selection.end,
15351                        selection.reversed,
15352                        replace_newest,
15353                        autoscroll,
15354                        window,
15355                        cx,
15356                    );
15357                }
15358
15359                if selections.len() == 1 {
15360                    let selection = selections
15361                        .last()
15362                        .expect("ensured that there's only one selection");
15363                    let query = buffer
15364                        .text_for_range(selection.start..selection.end)
15365                        .collect::<String>();
15366                    let is_empty = query.is_empty();
15367                    let select_state = SelectNextState {
15368                        query: self.build_query(&[query], cx)?,
15369                        wordwise: true,
15370                        done: is_empty,
15371                    };
15372                    self.select_next_state = Some(select_state);
15373                } else {
15374                    self.select_next_state = None;
15375                }
15376            } else if let Some(selected_text) = selected_text {
15377                self.select_next_state = Some(SelectNextState {
15378                    query: self.build_query(&[selected_text], cx)?,
15379                    wordwise: false,
15380                    done: false,
15381                });
15382                self.select_next_match_internal(
15383                    display_map,
15384                    replace_newest,
15385                    autoscroll,
15386                    window,
15387                    cx,
15388                )?;
15389            }
15390        }
15391        Ok(())
15392    }
15393
15394    pub fn select_all_matches(
15395        &mut self,
15396        _action: &SelectAllMatches,
15397        window: &mut Window,
15398        cx: &mut Context<Self>,
15399    ) -> Result<()> {
15400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15401
15402        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15403
15404        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15405        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15406        else {
15407            return Ok(());
15408        };
15409
15410        let mut new_selections = Vec::new();
15411
15412        let reversed = self
15413            .selections
15414            .oldest::<MultiBufferOffset>(&display_map)
15415            .reversed;
15416        let buffer = display_map.buffer_snapshot();
15417        let query_matches = select_next_state
15418            .query
15419            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15420
15421        for query_match in query_matches.into_iter() {
15422            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15423            let offset_range = if reversed {
15424                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15425            } else {
15426                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15427            };
15428
15429            if !select_next_state.wordwise
15430                || (!buffer.is_inside_word(offset_range.start, None)
15431                    && !buffer.is_inside_word(offset_range.end, None))
15432            {
15433                new_selections.push(offset_range.start..offset_range.end);
15434            }
15435        }
15436
15437        select_next_state.done = true;
15438
15439        if new_selections.is_empty() {
15440            log::error!("bug: new_selections is empty in select_all_matches");
15441            return Ok(());
15442        }
15443
15444        self.unfold_ranges(&new_selections, false, false, cx);
15445        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15446            selections.select_ranges(new_selections)
15447        });
15448
15449        Ok(())
15450    }
15451
15452    pub fn select_next(
15453        &mut self,
15454        action: &SelectNext,
15455        window: &mut Window,
15456        cx: &mut Context<Self>,
15457    ) -> Result<()> {
15458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15459        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15460        self.select_next_match_internal(
15461            &display_map,
15462            action.replace_newest,
15463            Some(Autoscroll::newest()),
15464            window,
15465            cx,
15466        )
15467    }
15468
15469    pub fn select_previous(
15470        &mut self,
15471        action: &SelectPrevious,
15472        window: &mut Window,
15473        cx: &mut Context<Self>,
15474    ) -> Result<()> {
15475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15477        let buffer = display_map.buffer_snapshot();
15478        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15479        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15480            let query = &select_prev_state.query;
15481            if !select_prev_state.done {
15482                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15483                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15484                let mut next_selected_range = None;
15485                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15486                let bytes_before_last_selection =
15487                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15488                let bytes_after_first_selection =
15489                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15490                let query_matches = query
15491                    .stream_find_iter(bytes_before_last_selection)
15492                    .map(|result| (last_selection.start, result))
15493                    .chain(
15494                        query
15495                            .stream_find_iter(bytes_after_first_selection)
15496                            .map(|result| (buffer.len(), result)),
15497                    );
15498                for (end_offset, query_match) in query_matches {
15499                    let query_match = query_match.unwrap(); // can only fail due to I/O
15500                    let offset_range =
15501                        end_offset - query_match.end()..end_offset - query_match.start();
15502
15503                    if !select_prev_state.wordwise
15504                        || (!buffer.is_inside_word(offset_range.start, None)
15505                            && !buffer.is_inside_word(offset_range.end, None))
15506                    {
15507                        next_selected_range = Some(offset_range);
15508                        break;
15509                    }
15510                }
15511
15512                if let Some(next_selected_range) = next_selected_range {
15513                    self.select_match_ranges(
15514                        next_selected_range,
15515                        last_selection.reversed,
15516                        action.replace_newest,
15517                        Some(Autoscroll::newest()),
15518                        window,
15519                        cx,
15520                    );
15521                } else {
15522                    select_prev_state.done = true;
15523                }
15524            }
15525
15526            self.select_prev_state = Some(select_prev_state);
15527        } else {
15528            let mut only_carets = true;
15529            let mut same_text_selected = true;
15530            let mut selected_text = None;
15531
15532            let mut selections_iter = selections.iter().peekable();
15533            while let Some(selection) = selections_iter.next() {
15534                if selection.start != selection.end {
15535                    only_carets = false;
15536                }
15537
15538                if same_text_selected {
15539                    if selected_text.is_none() {
15540                        selected_text =
15541                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15542                    }
15543
15544                    if let Some(next_selection) = selections_iter.peek() {
15545                        if next_selection.len() == selection.len() {
15546                            let next_selected_text = buffer
15547                                .text_for_range(next_selection.range())
15548                                .collect::<String>();
15549                            if Some(next_selected_text) != selected_text {
15550                                same_text_selected = false;
15551                                selected_text = None;
15552                            }
15553                        } else {
15554                            same_text_selected = false;
15555                            selected_text = None;
15556                        }
15557                    }
15558                }
15559            }
15560
15561            if only_carets {
15562                for selection in &mut selections {
15563                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15564                    selection.start = word_range.start;
15565                    selection.end = word_range.end;
15566                    selection.goal = SelectionGoal::None;
15567                    selection.reversed = false;
15568                    self.select_match_ranges(
15569                        selection.start..selection.end,
15570                        selection.reversed,
15571                        action.replace_newest,
15572                        Some(Autoscroll::newest()),
15573                        window,
15574                        cx,
15575                    );
15576                }
15577                if selections.len() == 1 {
15578                    let selection = selections
15579                        .last()
15580                        .expect("ensured that there's only one selection");
15581                    let query = buffer
15582                        .text_for_range(selection.start..selection.end)
15583                        .collect::<String>();
15584                    let is_empty = query.is_empty();
15585                    let select_state = SelectNextState {
15586                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15587                        wordwise: true,
15588                        done: is_empty,
15589                    };
15590                    self.select_prev_state = Some(select_state);
15591                } else {
15592                    self.select_prev_state = None;
15593                }
15594            } else if let Some(selected_text) = selected_text {
15595                self.select_prev_state = Some(SelectNextState {
15596                    query: self
15597                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15598                    wordwise: false,
15599                    done: false,
15600                });
15601                self.select_previous(action, window, cx)?;
15602            }
15603        }
15604        Ok(())
15605    }
15606
15607    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15608    /// setting the case sensitivity based on the global
15609    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15610    /// editor's settings.
15611    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15612    where
15613        I: IntoIterator<Item = P>,
15614        P: AsRef<[u8]>,
15615    {
15616        let case_sensitive = self
15617            .select_next_is_case_sensitive
15618            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15619
15620        let mut builder = AhoCorasickBuilder::new();
15621        builder.ascii_case_insensitive(!case_sensitive);
15622        builder.build(patterns)
15623    }
15624
15625    pub fn find_next_match(
15626        &mut self,
15627        _: &FindNextMatch,
15628        window: &mut Window,
15629        cx: &mut Context<Self>,
15630    ) -> Result<()> {
15631        let selections = self.selections.disjoint_anchors_arc();
15632        match selections.first() {
15633            Some(first) if selections.len() >= 2 => {
15634                self.change_selections(Default::default(), window, cx, |s| {
15635                    s.select_ranges([first.range()]);
15636                });
15637            }
15638            _ => self.select_next(
15639                &SelectNext {
15640                    replace_newest: true,
15641                },
15642                window,
15643                cx,
15644            )?,
15645        }
15646        Ok(())
15647    }
15648
15649    pub fn find_previous_match(
15650        &mut self,
15651        _: &FindPreviousMatch,
15652        window: &mut Window,
15653        cx: &mut Context<Self>,
15654    ) -> Result<()> {
15655        let selections = self.selections.disjoint_anchors_arc();
15656        match selections.last() {
15657            Some(last) if selections.len() >= 2 => {
15658                self.change_selections(Default::default(), window, cx, |s| {
15659                    s.select_ranges([last.range()]);
15660                });
15661            }
15662            _ => self.select_previous(
15663                &SelectPrevious {
15664                    replace_newest: true,
15665                },
15666                window,
15667                cx,
15668            )?,
15669        }
15670        Ok(())
15671    }
15672
15673    pub fn toggle_comments(
15674        &mut self,
15675        action: &ToggleComments,
15676        window: &mut Window,
15677        cx: &mut Context<Self>,
15678    ) {
15679        if self.read_only(cx) {
15680            return;
15681        }
15682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15683        let text_layout_details = &self.text_layout_details(window);
15684        self.transact(window, cx, |this, window, cx| {
15685            let mut selections = this
15686                .selections
15687                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15688            let mut edits = Vec::new();
15689            let mut selection_edit_ranges = Vec::new();
15690            let mut last_toggled_row = None;
15691            let snapshot = this.buffer.read(cx).read(cx);
15692            let empty_str: Arc<str> = Arc::default();
15693            let mut suffixes_inserted = Vec::new();
15694            let ignore_indent = action.ignore_indent;
15695
15696            fn comment_prefix_range(
15697                snapshot: &MultiBufferSnapshot,
15698                row: MultiBufferRow,
15699                comment_prefix: &str,
15700                comment_prefix_whitespace: &str,
15701                ignore_indent: bool,
15702            ) -> Range<Point> {
15703                let indent_size = if ignore_indent {
15704                    0
15705                } else {
15706                    snapshot.indent_size_for_line(row).len
15707                };
15708
15709                let start = Point::new(row.0, indent_size);
15710
15711                let mut line_bytes = snapshot
15712                    .bytes_in_range(start..snapshot.max_point())
15713                    .flatten()
15714                    .copied();
15715
15716                // If this line currently begins with the line comment prefix, then record
15717                // the range containing the prefix.
15718                if line_bytes
15719                    .by_ref()
15720                    .take(comment_prefix.len())
15721                    .eq(comment_prefix.bytes())
15722                {
15723                    // Include any whitespace that matches the comment prefix.
15724                    let matching_whitespace_len = line_bytes
15725                        .zip(comment_prefix_whitespace.bytes())
15726                        .take_while(|(a, b)| a == b)
15727                        .count() as u32;
15728                    let end = Point::new(
15729                        start.row,
15730                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15731                    );
15732                    start..end
15733                } else {
15734                    start..start
15735                }
15736            }
15737
15738            fn comment_suffix_range(
15739                snapshot: &MultiBufferSnapshot,
15740                row: MultiBufferRow,
15741                comment_suffix: &str,
15742                comment_suffix_has_leading_space: bool,
15743            ) -> Range<Point> {
15744                let end = Point::new(row.0, snapshot.line_len(row));
15745                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15746
15747                let mut line_end_bytes = snapshot
15748                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15749                    .flatten()
15750                    .copied();
15751
15752                let leading_space_len = if suffix_start_column > 0
15753                    && line_end_bytes.next() == Some(b' ')
15754                    && comment_suffix_has_leading_space
15755                {
15756                    1
15757                } else {
15758                    0
15759                };
15760
15761                // If this line currently begins with the line comment prefix, then record
15762                // the range containing the prefix.
15763                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15764                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15765                    start..end
15766                } else {
15767                    end..end
15768                }
15769            }
15770
15771            // TODO: Handle selections that cross excerpts
15772            for selection in &mut selections {
15773                let start_column = snapshot
15774                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15775                    .len;
15776                let language = if let Some(language) =
15777                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15778                {
15779                    language
15780                } else {
15781                    continue;
15782                };
15783
15784                selection_edit_ranges.clear();
15785
15786                // If multiple selections contain a given row, avoid processing that
15787                // row more than once.
15788                let mut start_row = MultiBufferRow(selection.start.row);
15789                if last_toggled_row == Some(start_row) {
15790                    start_row = start_row.next_row();
15791                }
15792                let end_row =
15793                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15794                        MultiBufferRow(selection.end.row - 1)
15795                    } else {
15796                        MultiBufferRow(selection.end.row)
15797                    };
15798                last_toggled_row = Some(end_row);
15799
15800                if start_row > end_row {
15801                    continue;
15802                }
15803
15804                // If the language has line comments, toggle those.
15805                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15806
15807                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15808                if ignore_indent {
15809                    full_comment_prefixes = full_comment_prefixes
15810                        .into_iter()
15811                        .map(|s| Arc::from(s.trim_end()))
15812                        .collect();
15813                }
15814
15815                if !full_comment_prefixes.is_empty() {
15816                    let first_prefix = full_comment_prefixes
15817                        .first()
15818                        .expect("prefixes is non-empty");
15819                    let prefix_trimmed_lengths = full_comment_prefixes
15820                        .iter()
15821                        .map(|p| p.trim_end_matches(' ').len())
15822                        .collect::<SmallVec<[usize; 4]>>();
15823
15824                    let mut all_selection_lines_are_comments = true;
15825
15826                    for row in start_row.0..=end_row.0 {
15827                        let row = MultiBufferRow(row);
15828                        if start_row < end_row && snapshot.is_line_blank(row) {
15829                            continue;
15830                        }
15831
15832                        let prefix_range = full_comment_prefixes
15833                            .iter()
15834                            .zip(prefix_trimmed_lengths.iter().copied())
15835                            .map(|(prefix, trimmed_prefix_len)| {
15836                                comment_prefix_range(
15837                                    snapshot.deref(),
15838                                    row,
15839                                    &prefix[..trimmed_prefix_len],
15840                                    &prefix[trimmed_prefix_len..],
15841                                    ignore_indent,
15842                                )
15843                            })
15844                            .max_by_key(|range| range.end.column - range.start.column)
15845                            .expect("prefixes is non-empty");
15846
15847                        if prefix_range.is_empty() {
15848                            all_selection_lines_are_comments = false;
15849                        }
15850
15851                        selection_edit_ranges.push(prefix_range);
15852                    }
15853
15854                    if all_selection_lines_are_comments {
15855                        edits.extend(
15856                            selection_edit_ranges
15857                                .iter()
15858                                .cloned()
15859                                .map(|range| (range, empty_str.clone())),
15860                        );
15861                    } else {
15862                        let min_column = selection_edit_ranges
15863                            .iter()
15864                            .map(|range| range.start.column)
15865                            .min()
15866                            .unwrap_or(0);
15867                        edits.extend(selection_edit_ranges.iter().map(|range| {
15868                            let position = Point::new(range.start.row, min_column);
15869                            (position..position, first_prefix.clone())
15870                        }));
15871                    }
15872                } else if let Some(BlockCommentConfig {
15873                    start: full_comment_prefix,
15874                    end: comment_suffix,
15875                    ..
15876                }) = language.block_comment()
15877                {
15878                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15879                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15880                    let prefix_range = comment_prefix_range(
15881                        snapshot.deref(),
15882                        start_row,
15883                        comment_prefix,
15884                        comment_prefix_whitespace,
15885                        ignore_indent,
15886                    );
15887                    let suffix_range = comment_suffix_range(
15888                        snapshot.deref(),
15889                        end_row,
15890                        comment_suffix.trim_start_matches(' '),
15891                        comment_suffix.starts_with(' '),
15892                    );
15893
15894                    if prefix_range.is_empty() || suffix_range.is_empty() {
15895                        edits.push((
15896                            prefix_range.start..prefix_range.start,
15897                            full_comment_prefix.clone(),
15898                        ));
15899                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15900                        suffixes_inserted.push((end_row, comment_suffix.len()));
15901                    } else {
15902                        edits.push((prefix_range, empty_str.clone()));
15903                        edits.push((suffix_range, empty_str.clone()));
15904                    }
15905                } else {
15906                    continue;
15907                }
15908            }
15909
15910            drop(snapshot);
15911            this.buffer.update(cx, |buffer, cx| {
15912                buffer.edit(edits, None, cx);
15913            });
15914
15915            // Adjust selections so that they end before any comment suffixes that
15916            // were inserted.
15917            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15918            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15919            let snapshot = this.buffer.read(cx).read(cx);
15920            for selection in &mut selections {
15921                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15922                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15923                        Ordering::Less => {
15924                            suffixes_inserted.next();
15925                            continue;
15926                        }
15927                        Ordering::Greater => break,
15928                        Ordering::Equal => {
15929                            if selection.end.column == snapshot.line_len(row) {
15930                                if selection.is_empty() {
15931                                    selection.start.column -= suffix_len as u32;
15932                                }
15933                                selection.end.column -= suffix_len as u32;
15934                            }
15935                            break;
15936                        }
15937                    }
15938                }
15939            }
15940
15941            drop(snapshot);
15942            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15943
15944            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15945            let selections_on_single_row = selections.windows(2).all(|selections| {
15946                selections[0].start.row == selections[1].start.row
15947                    && selections[0].end.row == selections[1].end.row
15948                    && selections[0].start.row == selections[0].end.row
15949            });
15950            let selections_selecting = selections
15951                .iter()
15952                .any(|selection| selection.start != selection.end);
15953            let advance_downwards = action.advance_downwards
15954                && selections_on_single_row
15955                && !selections_selecting
15956                && !matches!(this.mode, EditorMode::SingleLine);
15957
15958            if advance_downwards {
15959                let snapshot = this.buffer.read(cx).snapshot(cx);
15960
15961                this.change_selections(Default::default(), window, cx, |s| {
15962                    s.move_cursors_with(|display_snapshot, display_point, _| {
15963                        let mut point = display_point.to_point(display_snapshot);
15964                        point.row += 1;
15965                        point = snapshot.clip_point(point, Bias::Left);
15966                        let display_point = point.to_display_point(display_snapshot);
15967                        let goal = SelectionGoal::HorizontalPosition(
15968                            display_snapshot
15969                                .x_for_display_point(display_point, text_layout_details)
15970                                .into(),
15971                        );
15972                        (display_point, goal)
15973                    })
15974                });
15975            }
15976        });
15977    }
15978
15979    pub fn select_enclosing_symbol(
15980        &mut self,
15981        _: &SelectEnclosingSymbol,
15982        window: &mut Window,
15983        cx: &mut Context<Self>,
15984    ) {
15985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15986
15987        let buffer = self.buffer.read(cx).snapshot(cx);
15988        let old_selections = self
15989            .selections
15990            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15991            .into_boxed_slice();
15992
15993        fn update_selection(
15994            selection: &Selection<MultiBufferOffset>,
15995            buffer_snap: &MultiBufferSnapshot,
15996        ) -> Option<Selection<MultiBufferOffset>> {
15997            let cursor = selection.head();
15998            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15999            for symbol in symbols.iter().rev() {
16000                let start = symbol.range.start.to_offset(buffer_snap);
16001                let end = symbol.range.end.to_offset(buffer_snap);
16002                let new_range = start..end;
16003                if start < selection.start || end > selection.end {
16004                    return Some(Selection {
16005                        id: selection.id,
16006                        start: new_range.start,
16007                        end: new_range.end,
16008                        goal: SelectionGoal::None,
16009                        reversed: selection.reversed,
16010                    });
16011                }
16012            }
16013            None
16014        }
16015
16016        let mut selected_larger_symbol = false;
16017        let new_selections = old_selections
16018            .iter()
16019            .map(|selection| match update_selection(selection, &buffer) {
16020                Some(new_selection) => {
16021                    if new_selection.range() != selection.range() {
16022                        selected_larger_symbol = true;
16023                    }
16024                    new_selection
16025                }
16026                None => selection.clone(),
16027            })
16028            .collect::<Vec<_>>();
16029
16030        if selected_larger_symbol {
16031            self.change_selections(Default::default(), window, cx, |s| {
16032                s.select(new_selections);
16033            });
16034        }
16035    }
16036
16037    pub fn select_larger_syntax_node(
16038        &mut self,
16039        _: &SelectLargerSyntaxNode,
16040        window: &mut Window,
16041        cx: &mut Context<Self>,
16042    ) {
16043        let Some(visible_row_count) = self.visible_row_count() else {
16044            return;
16045        };
16046        let old_selections: Box<[_]> = self
16047            .selections
16048            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16049            .into();
16050        if old_selections.is_empty() {
16051            return;
16052        }
16053
16054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16055
16056        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16057        let buffer = self.buffer.read(cx).snapshot(cx);
16058
16059        let mut selected_larger_node = false;
16060        let mut new_selections = old_selections
16061            .iter()
16062            .map(|selection| {
16063                let old_range = selection.start..selection.end;
16064
16065                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16066                    // manually select word at selection
16067                    if ["string_content", "inline"].contains(&node.kind()) {
16068                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16069                        // ignore if word is already selected
16070                        if !word_range.is_empty() && old_range != word_range {
16071                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16072                            // only select word if start and end point belongs to same word
16073                            if word_range == last_word_range {
16074                                selected_larger_node = true;
16075                                return Selection {
16076                                    id: selection.id,
16077                                    start: word_range.start,
16078                                    end: word_range.end,
16079                                    goal: SelectionGoal::None,
16080                                    reversed: selection.reversed,
16081                                };
16082                            }
16083                        }
16084                    }
16085                }
16086
16087                let mut new_range = old_range.clone();
16088                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16089                    new_range = range;
16090                    if !node.is_named() {
16091                        continue;
16092                    }
16093                    if !display_map.intersects_fold(new_range.start)
16094                        && !display_map.intersects_fold(new_range.end)
16095                    {
16096                        break;
16097                    }
16098                }
16099
16100                selected_larger_node |= new_range != old_range;
16101                Selection {
16102                    id: selection.id,
16103                    start: new_range.start,
16104                    end: new_range.end,
16105                    goal: SelectionGoal::None,
16106                    reversed: selection.reversed,
16107                }
16108            })
16109            .collect::<Vec<_>>();
16110
16111        if !selected_larger_node {
16112            return; // don't put this call in the history
16113        }
16114
16115        // scroll based on transformation done to the last selection created by the user
16116        let (last_old, last_new) = old_selections
16117            .last()
16118            .zip(new_selections.last().cloned())
16119            .expect("old_selections isn't empty");
16120
16121        // revert selection
16122        let is_selection_reversed = {
16123            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16124            new_selections.last_mut().expect("checked above").reversed =
16125                should_newest_selection_be_reversed;
16126            should_newest_selection_be_reversed
16127        };
16128
16129        if selected_larger_node {
16130            self.select_syntax_node_history.disable_clearing = true;
16131            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16132                s.select(new_selections.clone());
16133            });
16134            self.select_syntax_node_history.disable_clearing = false;
16135        }
16136
16137        let start_row = last_new.start.to_display_point(&display_map).row().0;
16138        let end_row = last_new.end.to_display_point(&display_map).row().0;
16139        let selection_height = end_row - start_row + 1;
16140        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16141
16142        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16143        let scroll_behavior = if fits_on_the_screen {
16144            self.request_autoscroll(Autoscroll::fit(), cx);
16145            SelectSyntaxNodeScrollBehavior::FitSelection
16146        } else if is_selection_reversed {
16147            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16148            SelectSyntaxNodeScrollBehavior::CursorTop
16149        } else {
16150            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16151            SelectSyntaxNodeScrollBehavior::CursorBottom
16152        };
16153
16154        self.select_syntax_node_history.push((
16155            old_selections,
16156            scroll_behavior,
16157            is_selection_reversed,
16158        ));
16159    }
16160
16161    pub fn select_smaller_syntax_node(
16162        &mut self,
16163        _: &SelectSmallerSyntaxNode,
16164        window: &mut Window,
16165        cx: &mut Context<Self>,
16166    ) {
16167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16168
16169        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16170            self.select_syntax_node_history.pop()
16171        {
16172            if let Some(selection) = selections.last_mut() {
16173                selection.reversed = is_selection_reversed;
16174            }
16175
16176            self.select_syntax_node_history.disable_clearing = true;
16177            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16178                s.select(selections.to_vec());
16179            });
16180            self.select_syntax_node_history.disable_clearing = false;
16181
16182            match scroll_behavior {
16183                SelectSyntaxNodeScrollBehavior::CursorTop => {
16184                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16185                }
16186                SelectSyntaxNodeScrollBehavior::FitSelection => {
16187                    self.request_autoscroll(Autoscroll::fit(), cx);
16188                }
16189                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16190                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16191                }
16192            }
16193        }
16194    }
16195
16196    pub fn unwrap_syntax_node(
16197        &mut self,
16198        _: &UnwrapSyntaxNode,
16199        window: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) {
16202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16203
16204        let buffer = self.buffer.read(cx).snapshot(cx);
16205        let selections = self
16206            .selections
16207            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16208            .into_iter()
16209            // subtracting the offset requires sorting
16210            .sorted_by_key(|i| i.start);
16211
16212        let full_edits = selections
16213            .into_iter()
16214            .filter_map(|selection| {
16215                let child = if selection.is_empty()
16216                    && let Some((_, ancestor_range)) =
16217                        buffer.syntax_ancestor(selection.start..selection.end)
16218                {
16219                    ancestor_range
16220                } else {
16221                    selection.range()
16222                };
16223
16224                let mut parent = child.clone();
16225                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16226                    parent = ancestor_range;
16227                    if parent.start < child.start || parent.end > child.end {
16228                        break;
16229                    }
16230                }
16231
16232                if parent == child {
16233                    return None;
16234                }
16235                let text = buffer.text_for_range(child).collect::<String>();
16236                Some((selection.id, parent, text))
16237            })
16238            .collect::<Vec<_>>();
16239        if full_edits.is_empty() {
16240            return;
16241        }
16242
16243        self.transact(window, cx, |this, window, cx| {
16244            this.buffer.update(cx, |buffer, cx| {
16245                buffer.edit(
16246                    full_edits
16247                        .iter()
16248                        .map(|(_, p, t)| (p.clone(), t.clone()))
16249                        .collect::<Vec<_>>(),
16250                    None,
16251                    cx,
16252                );
16253            });
16254            this.change_selections(Default::default(), window, cx, |s| {
16255                let mut offset = 0;
16256                let mut selections = vec![];
16257                for (id, parent, text) in full_edits {
16258                    let start = parent.start - offset;
16259                    offset += (parent.end - parent.start) - text.len();
16260                    selections.push(Selection {
16261                        id,
16262                        start,
16263                        end: start + text.len(),
16264                        reversed: false,
16265                        goal: Default::default(),
16266                    });
16267                }
16268                s.select(selections);
16269            });
16270        });
16271    }
16272
16273    pub fn select_next_syntax_node(
16274        &mut self,
16275        _: &SelectNextSyntaxNode,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        let old_selections: Box<[_]> = self
16280            .selections
16281            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16282            .into();
16283        if old_selections.is_empty() {
16284            return;
16285        }
16286
16287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16288
16289        let buffer = self.buffer.read(cx).snapshot(cx);
16290        let mut selected_sibling = false;
16291
16292        let new_selections = old_selections
16293            .iter()
16294            .map(|selection| {
16295                let old_range = selection.start..selection.end;
16296
16297                let old_range =
16298                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16299                let excerpt = buffer.excerpt_containing(old_range.clone());
16300
16301                if let Some(mut excerpt) = excerpt
16302                    && let Some(node) = excerpt
16303                        .buffer()
16304                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16305                {
16306                    let new_range = excerpt.map_range_from_buffer(
16307                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16308                    );
16309                    selected_sibling = true;
16310                    Selection {
16311                        id: selection.id,
16312                        start: new_range.start,
16313                        end: new_range.end,
16314                        goal: SelectionGoal::None,
16315                        reversed: selection.reversed,
16316                    }
16317                } else {
16318                    selection.clone()
16319                }
16320            })
16321            .collect::<Vec<_>>();
16322
16323        if selected_sibling {
16324            self.change_selections(
16325                SelectionEffects::scroll(Autoscroll::fit()),
16326                window,
16327                cx,
16328                |s| {
16329                    s.select(new_selections);
16330                },
16331            );
16332        }
16333    }
16334
16335    pub fn select_prev_syntax_node(
16336        &mut self,
16337        _: &SelectPreviousSyntaxNode,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) {
16341        let old_selections: Box<[_]> = self
16342            .selections
16343            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16344            .into();
16345        if old_selections.is_empty() {
16346            return;
16347        }
16348
16349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16350
16351        let buffer = self.buffer.read(cx).snapshot(cx);
16352        let mut selected_sibling = false;
16353
16354        let new_selections = old_selections
16355            .iter()
16356            .map(|selection| {
16357                let old_range = selection.start..selection.end;
16358                let old_range =
16359                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16360                let excerpt = buffer.excerpt_containing(old_range.clone());
16361
16362                if let Some(mut excerpt) = excerpt
16363                    && let Some(node) = excerpt
16364                        .buffer()
16365                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16366                {
16367                    let new_range = excerpt.map_range_from_buffer(
16368                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16369                    );
16370                    selected_sibling = true;
16371                    Selection {
16372                        id: selection.id,
16373                        start: new_range.start,
16374                        end: new_range.end,
16375                        goal: SelectionGoal::None,
16376                        reversed: selection.reversed,
16377                    }
16378                } else {
16379                    selection.clone()
16380                }
16381            })
16382            .collect::<Vec<_>>();
16383
16384        if selected_sibling {
16385            self.change_selections(
16386                SelectionEffects::scroll(Autoscroll::fit()),
16387                window,
16388                cx,
16389                |s| {
16390                    s.select(new_selections);
16391                },
16392            );
16393        }
16394    }
16395
16396    pub fn move_to_start_of_larger_syntax_node(
16397        &mut self,
16398        _: &MoveToStartOfLargerSyntaxNode,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) {
16402        self.move_cursors_to_syntax_nodes(window, cx, false);
16403    }
16404
16405    pub fn move_to_end_of_larger_syntax_node(
16406        &mut self,
16407        _: &MoveToEndOfLargerSyntaxNode,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) {
16411        self.move_cursors_to_syntax_nodes(window, cx, true);
16412    }
16413
16414    fn move_cursors_to_syntax_nodes(
16415        &mut self,
16416        window: &mut Window,
16417        cx: &mut Context<Self>,
16418        move_to_end: bool,
16419    ) -> bool {
16420        let old_selections: Box<[_]> = self
16421            .selections
16422            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16423            .into();
16424        if old_selections.is_empty() {
16425            return false;
16426        }
16427
16428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16429
16430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16431        let buffer = self.buffer.read(cx).snapshot(cx);
16432
16433        let mut any_cursor_moved = false;
16434        let new_selections = old_selections
16435            .iter()
16436            .map(|selection| {
16437                if !selection.is_empty() {
16438                    return selection.clone();
16439                }
16440
16441                let selection_pos = selection.head();
16442                let old_range = selection_pos..selection_pos;
16443
16444                let mut new_pos = selection_pos;
16445                let mut search_range = old_range;
16446                while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16447                    search_range = range.clone();
16448                    if !node.is_named()
16449                        || display_map.intersects_fold(range.start)
16450                        || display_map.intersects_fold(range.end)
16451                        // If cursor is already at the end of the syntax node, continue searching
16452                        || (move_to_end && range.end == selection_pos)
16453                        // If cursor is already at the start of the syntax node, continue searching
16454                        || (!move_to_end && range.start == selection_pos)
16455                    {
16456                        continue;
16457                    }
16458
16459                    // If we found a string_content node, find the largest parent that is still string_content
16460                    // Enables us to skip to the end of strings without taking multiple steps inside the string
16461                    let (_, final_range) = if node.kind() == "string_content" {
16462                        let mut current_node = node;
16463                        let mut current_range = range;
16464                        while let Some((parent, parent_range)) =
16465                            buffer.syntax_ancestor(current_range.clone())
16466                        {
16467                            if parent.kind() == "string_content" {
16468                                current_node = parent;
16469                                current_range = parent_range;
16470                            } else {
16471                                break;
16472                            }
16473                        }
16474
16475                        (current_node, current_range)
16476                    } else {
16477                        (node, range)
16478                    };
16479
16480                    new_pos = if move_to_end {
16481                        final_range.end
16482                    } else {
16483                        final_range.start
16484                    };
16485
16486                    break;
16487                }
16488
16489                any_cursor_moved |= new_pos != selection_pos;
16490
16491                Selection {
16492                    id: selection.id,
16493                    start: new_pos,
16494                    end: new_pos,
16495                    goal: SelectionGoal::None,
16496                    reversed: false,
16497                }
16498            })
16499            .collect::<Vec<_>>();
16500
16501        self.change_selections(Default::default(), window, cx, |s| {
16502            s.select(new_selections);
16503        });
16504        self.request_autoscroll(Autoscroll::newest(), cx);
16505
16506        any_cursor_moved
16507    }
16508
16509    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16510        if !EditorSettings::get_global(cx).gutter.runnables {
16511            self.clear_tasks();
16512            return Task::ready(());
16513        }
16514        let project = self.project().map(Entity::downgrade);
16515        let task_sources = self.lsp_task_sources(cx);
16516        let multi_buffer = self.buffer.downgrade();
16517        cx.spawn_in(window, async move |editor, cx| {
16518            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16519            let Some(project) = project.and_then(|p| p.upgrade()) else {
16520                return;
16521            };
16522            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16523                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16524            }) else {
16525                return;
16526            };
16527
16528            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16529            if hide_runnables {
16530                return;
16531            }
16532            let new_rows =
16533                cx.background_spawn({
16534                    let snapshot = display_snapshot.clone();
16535                    async move {
16536                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16537                    }
16538                })
16539                    .await;
16540            let Ok(lsp_tasks) =
16541                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16542            else {
16543                return;
16544            };
16545            let lsp_tasks = lsp_tasks.await;
16546
16547            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16548                lsp_tasks
16549                    .into_iter()
16550                    .flat_map(|(kind, tasks)| {
16551                        tasks.into_iter().filter_map(move |(location, task)| {
16552                            Some((kind.clone(), location?, task))
16553                        })
16554                    })
16555                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16556                        let buffer = location.target.buffer;
16557                        let buffer_snapshot = buffer.read(cx).snapshot();
16558                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16559                            |(excerpt_id, snapshot, _)| {
16560                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16561                                    display_snapshot
16562                                        .buffer_snapshot()
16563                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16564                                } else {
16565                                    None
16566                                }
16567                            },
16568                        );
16569                        if let Some(offset) = offset {
16570                            let task_buffer_range =
16571                                location.target.range.to_point(&buffer_snapshot);
16572                            let context_buffer_range =
16573                                task_buffer_range.to_offset(&buffer_snapshot);
16574                            let context_range = BufferOffset(context_buffer_range.start)
16575                                ..BufferOffset(context_buffer_range.end);
16576
16577                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16578                                .or_insert_with(|| RunnableTasks {
16579                                    templates: Vec::new(),
16580                                    offset,
16581                                    column: task_buffer_range.start.column,
16582                                    extra_variables: HashMap::default(),
16583                                    context_range,
16584                                })
16585                                .templates
16586                                .push((kind, task.original_task().clone()));
16587                        }
16588
16589                        acc
16590                    })
16591            }) else {
16592                return;
16593            };
16594
16595            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16596                buffer.language_settings(cx).tasks.prefer_lsp
16597            }) else {
16598                return;
16599            };
16600
16601            let rows = Self::runnable_rows(
16602                project,
16603                display_snapshot,
16604                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16605                new_rows,
16606                cx.clone(),
16607            )
16608            .await;
16609            editor
16610                .update(cx, |editor, _| {
16611                    editor.clear_tasks();
16612                    for (key, mut value) in rows {
16613                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16614                            value.templates.extend(lsp_tasks.templates);
16615                        }
16616
16617                        editor.insert_tasks(key, value);
16618                    }
16619                    for (key, value) in lsp_tasks_by_rows {
16620                        editor.insert_tasks(key, value);
16621                    }
16622                })
16623                .ok();
16624        })
16625    }
16626    fn fetch_runnable_ranges(
16627        snapshot: &DisplaySnapshot,
16628        range: Range<Anchor>,
16629    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16630        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16631    }
16632
16633    fn runnable_rows(
16634        project: Entity<Project>,
16635        snapshot: DisplaySnapshot,
16636        prefer_lsp: bool,
16637        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16638        cx: AsyncWindowContext,
16639    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16640        cx.spawn(async move |cx| {
16641            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16642            for (run_range, mut runnable) in runnable_ranges {
16643                let Some(tasks) = cx
16644                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16645                    .ok()
16646                else {
16647                    continue;
16648                };
16649                let mut tasks = tasks.await;
16650
16651                if prefer_lsp {
16652                    tasks.retain(|(task_kind, _)| {
16653                        !matches!(task_kind, TaskSourceKind::Language { .. })
16654                    });
16655                }
16656                if tasks.is_empty() {
16657                    continue;
16658                }
16659
16660                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16661                let Some(row) = snapshot
16662                    .buffer_snapshot()
16663                    .buffer_line_for_row(MultiBufferRow(point.row))
16664                    .map(|(_, range)| range.start.row)
16665                else {
16666                    continue;
16667                };
16668
16669                let context_range =
16670                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16671                runnable_rows.push((
16672                    (runnable.buffer_id, row),
16673                    RunnableTasks {
16674                        templates: tasks,
16675                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16676                        context_range,
16677                        column: point.column,
16678                        extra_variables: runnable.extra_captures,
16679                    },
16680                ));
16681            }
16682            runnable_rows
16683        })
16684    }
16685
16686    fn templates_with_tags(
16687        project: &Entity<Project>,
16688        runnable: &mut Runnable,
16689        cx: &mut App,
16690    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16691        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16692            let (worktree_id, file) = project
16693                .buffer_for_id(runnable.buffer, cx)
16694                .and_then(|buffer| buffer.read(cx).file())
16695                .map(|file| (file.worktree_id(cx), file.clone()))
16696                .unzip();
16697
16698            (
16699                project.task_store().read(cx).task_inventory().cloned(),
16700                worktree_id,
16701                file,
16702            )
16703        });
16704
16705        let tags = mem::take(&mut runnable.tags);
16706        let language = runnable.language.clone();
16707        cx.spawn(async move |cx| {
16708            let mut templates_with_tags = Vec::new();
16709            if let Some(inventory) = inventory {
16710                for RunnableTag(tag) in tags {
16711                    let new_tasks = inventory.update(cx, |inventory, cx| {
16712                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16713                    });
16714                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16715                        move |(_, template)| {
16716                            template.tags.iter().any(|source_tag| source_tag == &tag)
16717                        },
16718                    ));
16719                }
16720            }
16721            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16722
16723            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16724                // Strongest source wins; if we have worktree tag binding, prefer that to
16725                // global and language bindings;
16726                // if we have a global binding, prefer that to language binding.
16727                let first_mismatch = templates_with_tags
16728                    .iter()
16729                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16730                if let Some(index) = first_mismatch {
16731                    templates_with_tags.truncate(index);
16732                }
16733            }
16734
16735            templates_with_tags
16736        })
16737    }
16738
16739    pub fn move_to_enclosing_bracket(
16740        &mut self,
16741        _: &MoveToEnclosingBracket,
16742        window: &mut Window,
16743        cx: &mut Context<Self>,
16744    ) {
16745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16746        self.change_selections(Default::default(), window, cx, |s| {
16747            s.move_offsets_with(|snapshot, selection| {
16748                let Some(enclosing_bracket_ranges) =
16749                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16750                else {
16751                    return;
16752                };
16753
16754                let mut best_length = usize::MAX;
16755                let mut best_inside = false;
16756                let mut best_in_bracket_range = false;
16757                let mut best_destination = None;
16758                for (open, close) in enclosing_bracket_ranges {
16759                    let close = close.to_inclusive();
16760                    let length = *close.end() - open.start;
16761                    let inside = selection.start >= open.end && selection.end <= *close.start();
16762                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16763                        || close.contains(&selection.head());
16764
16765                    // If best is next to a bracket and current isn't, skip
16766                    if !in_bracket_range && best_in_bracket_range {
16767                        continue;
16768                    }
16769
16770                    // Prefer smaller lengths unless best is inside and current isn't
16771                    if length > best_length && (best_inside || !inside) {
16772                        continue;
16773                    }
16774
16775                    best_length = length;
16776                    best_inside = inside;
16777                    best_in_bracket_range = in_bracket_range;
16778                    best_destination = Some(
16779                        if close.contains(&selection.start) && close.contains(&selection.end) {
16780                            if inside { open.end } else { open.start }
16781                        } else if inside {
16782                            *close.start()
16783                        } else {
16784                            *close.end()
16785                        },
16786                    );
16787                }
16788
16789                if let Some(destination) = best_destination {
16790                    selection.collapse_to(destination, SelectionGoal::None);
16791                }
16792            })
16793        });
16794    }
16795
16796    pub fn undo_selection(
16797        &mut self,
16798        _: &UndoSelection,
16799        window: &mut Window,
16800        cx: &mut Context<Self>,
16801    ) {
16802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16803        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16804            self.selection_history.mode = SelectionHistoryMode::Undoing;
16805            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16806                this.end_selection(window, cx);
16807                this.change_selections(
16808                    SelectionEffects::scroll(Autoscroll::newest()),
16809                    window,
16810                    cx,
16811                    |s| s.select_anchors(entry.selections.to_vec()),
16812                );
16813            });
16814            self.selection_history.mode = SelectionHistoryMode::Normal;
16815
16816            self.select_next_state = entry.select_next_state;
16817            self.select_prev_state = entry.select_prev_state;
16818            self.add_selections_state = entry.add_selections_state;
16819        }
16820    }
16821
16822    pub fn redo_selection(
16823        &mut self,
16824        _: &RedoSelection,
16825        window: &mut Window,
16826        cx: &mut Context<Self>,
16827    ) {
16828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16829        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16830            self.selection_history.mode = SelectionHistoryMode::Redoing;
16831            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16832                this.end_selection(window, cx);
16833                this.change_selections(
16834                    SelectionEffects::scroll(Autoscroll::newest()),
16835                    window,
16836                    cx,
16837                    |s| s.select_anchors(entry.selections.to_vec()),
16838                );
16839            });
16840            self.selection_history.mode = SelectionHistoryMode::Normal;
16841
16842            self.select_next_state = entry.select_next_state;
16843            self.select_prev_state = entry.select_prev_state;
16844            self.add_selections_state = entry.add_selections_state;
16845        }
16846    }
16847
16848    pub fn expand_excerpts(
16849        &mut self,
16850        action: &ExpandExcerpts,
16851        _: &mut Window,
16852        cx: &mut Context<Self>,
16853    ) {
16854        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16855    }
16856
16857    pub fn expand_excerpts_down(
16858        &mut self,
16859        action: &ExpandExcerptsDown,
16860        _: &mut Window,
16861        cx: &mut Context<Self>,
16862    ) {
16863        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16864    }
16865
16866    pub fn expand_excerpts_up(
16867        &mut self,
16868        action: &ExpandExcerptsUp,
16869        _: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16873    }
16874
16875    pub fn expand_excerpts_for_direction(
16876        &mut self,
16877        lines: u32,
16878        direction: ExpandExcerptDirection,
16879        cx: &mut Context<Self>,
16880    ) {
16881        let selections = self.selections.disjoint_anchors_arc();
16882
16883        let lines = if lines == 0 {
16884            EditorSettings::get_global(cx).expand_excerpt_lines
16885        } else {
16886            lines
16887        };
16888
16889        let snapshot = self.buffer.read(cx).snapshot(cx);
16890        let mut excerpt_ids = selections
16891            .iter()
16892            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16893            .collect::<Vec<_>>();
16894        excerpt_ids.sort();
16895        excerpt_ids.dedup();
16896
16897        if self.delegate_expand_excerpts {
16898            cx.emit(EditorEvent::ExpandExcerptsRequested {
16899                excerpt_ids,
16900                lines,
16901                direction,
16902            });
16903            return;
16904        }
16905
16906        self.buffer.update(cx, |buffer, cx| {
16907            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16908        })
16909    }
16910
16911    pub fn expand_excerpt(
16912        &mut self,
16913        excerpt: ExcerptId,
16914        direction: ExpandExcerptDirection,
16915        window: &mut Window,
16916        cx: &mut Context<Self>,
16917    ) {
16918        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16919
16920        if self.delegate_expand_excerpts {
16921            cx.emit(EditorEvent::ExpandExcerptsRequested {
16922                excerpt_ids: vec![excerpt],
16923                lines: lines_to_expand,
16924                direction,
16925            });
16926            return;
16927        }
16928
16929        let current_scroll_position = self.scroll_position(cx);
16930        let mut scroll = None;
16931
16932        if direction == ExpandExcerptDirection::Down {
16933            let multi_buffer = self.buffer.read(cx);
16934            let snapshot = multi_buffer.snapshot(cx);
16935            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16936                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16937                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16938            {
16939                let buffer_snapshot = buffer.read(cx).snapshot();
16940                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16941                let last_row = buffer_snapshot.max_point().row;
16942                let lines_below = last_row.saturating_sub(excerpt_end_row);
16943                if lines_below >= lines_to_expand {
16944                    scroll = Some(
16945                        current_scroll_position
16946                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16947                    );
16948                }
16949            }
16950        }
16951        if direction == ExpandExcerptDirection::Up
16952            && self
16953                .buffer
16954                .read(cx)
16955                .snapshot(cx)
16956                .excerpt_before(excerpt)
16957                .is_none()
16958        {
16959            scroll = Some(current_scroll_position);
16960        }
16961
16962        self.buffer.update(cx, |buffer, cx| {
16963            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16964        });
16965
16966        if let Some(new_scroll_position) = scroll {
16967            self.set_scroll_position(new_scroll_position, window, cx);
16968        }
16969    }
16970
16971    pub fn go_to_singleton_buffer_point(
16972        &mut self,
16973        point: Point,
16974        window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) {
16977        self.go_to_singleton_buffer_range(point..point, window, cx);
16978    }
16979
16980    pub fn go_to_singleton_buffer_range(
16981        &mut self,
16982        range: Range<Point>,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) {
16986        let multibuffer = self.buffer().read(cx);
16987        let Some(buffer) = multibuffer.as_singleton() else {
16988            return;
16989        };
16990        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16991            return;
16992        };
16993        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16994            return;
16995        };
16996        self.change_selections(
16997            SelectionEffects::default().nav_history(true),
16998            window,
16999            cx,
17000            |s| s.select_anchor_ranges([start..end]),
17001        );
17002    }
17003
17004    pub fn go_to_diagnostic(
17005        &mut self,
17006        action: &GoToDiagnostic,
17007        window: &mut Window,
17008        cx: &mut Context<Self>,
17009    ) {
17010        if !self.diagnostics_enabled() {
17011            return;
17012        }
17013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17014        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17015    }
17016
17017    pub fn go_to_prev_diagnostic(
17018        &mut self,
17019        action: &GoToPreviousDiagnostic,
17020        window: &mut Window,
17021        cx: &mut Context<Self>,
17022    ) {
17023        if !self.diagnostics_enabled() {
17024            return;
17025        }
17026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17027        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17028    }
17029
17030    pub fn go_to_diagnostic_impl(
17031        &mut self,
17032        direction: Direction,
17033        severity: GoToDiagnosticSeverityFilter,
17034        window: &mut Window,
17035        cx: &mut Context<Self>,
17036    ) {
17037        let buffer = self.buffer.read(cx).snapshot(cx);
17038        let selection = self
17039            .selections
17040            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17041
17042        let mut active_group_id = None;
17043        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17044            && active_group.active_range.start.to_offset(&buffer) == selection.start
17045        {
17046            active_group_id = Some(active_group.group_id);
17047        }
17048
17049        fn filtered<'a>(
17050            severity: GoToDiagnosticSeverityFilter,
17051            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17052        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17053            diagnostics
17054                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17055                .filter(|entry| entry.range.start != entry.range.end)
17056                .filter(|entry| !entry.diagnostic.is_unnecessary)
17057        }
17058
17059        let before = filtered(
17060            severity,
17061            buffer
17062                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17063                .filter(|entry| entry.range.start <= selection.start),
17064        );
17065        let after = filtered(
17066            severity,
17067            buffer
17068                .diagnostics_in_range(selection.start..buffer.len())
17069                .filter(|entry| entry.range.start >= selection.start),
17070        );
17071
17072        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17073        if direction == Direction::Prev {
17074            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17075            {
17076                for diagnostic in prev_diagnostics.into_iter().rev() {
17077                    if diagnostic.range.start != selection.start
17078                        || active_group_id
17079                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17080                    {
17081                        found = Some(diagnostic);
17082                        break 'outer;
17083                    }
17084                }
17085            }
17086        } else {
17087            for diagnostic in after.chain(before) {
17088                if diagnostic.range.start != selection.start
17089                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17090                {
17091                    found = Some(diagnostic);
17092                    break;
17093                }
17094            }
17095        }
17096        let Some(next_diagnostic) = found else {
17097            return;
17098        };
17099
17100        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17101        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17102            return;
17103        };
17104        let snapshot = self.snapshot(window, cx);
17105        if snapshot.intersects_fold(next_diagnostic.range.start) {
17106            self.unfold_ranges(
17107                std::slice::from_ref(&next_diagnostic.range),
17108                true,
17109                false,
17110                cx,
17111            );
17112        }
17113        self.change_selections(Default::default(), window, cx, |s| {
17114            s.select_ranges(vec![
17115                next_diagnostic.range.start..next_diagnostic.range.start,
17116            ])
17117        });
17118        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17119        self.refresh_edit_prediction(false, true, window, cx);
17120    }
17121
17122    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17124        let snapshot = self.snapshot(window, cx);
17125        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17126        self.go_to_hunk_before_or_after_position(
17127            &snapshot,
17128            selection.head(),
17129            Direction::Next,
17130            window,
17131            cx,
17132        );
17133    }
17134
17135    pub fn go_to_hunk_before_or_after_position(
17136        &mut self,
17137        snapshot: &EditorSnapshot,
17138        position: Point,
17139        direction: Direction,
17140        window: &mut Window,
17141        cx: &mut Context<Editor>,
17142    ) {
17143        let row = if direction == Direction::Next {
17144            self.hunk_after_position(snapshot, position)
17145                .map(|hunk| hunk.row_range.start)
17146        } else {
17147            self.hunk_before_position(snapshot, position)
17148        };
17149
17150        if let Some(row) = row {
17151            let destination = Point::new(row.0, 0);
17152            let autoscroll = Autoscroll::center();
17153
17154            self.unfold_ranges(&[destination..destination], false, false, cx);
17155            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17156                s.select_ranges([destination..destination]);
17157            });
17158        }
17159    }
17160
17161    fn hunk_after_position(
17162        &mut self,
17163        snapshot: &EditorSnapshot,
17164        position: Point,
17165    ) -> Option<MultiBufferDiffHunk> {
17166        snapshot
17167            .buffer_snapshot()
17168            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17169            .find(|hunk| hunk.row_range.start.0 > position.row)
17170            .or_else(|| {
17171                snapshot
17172                    .buffer_snapshot()
17173                    .diff_hunks_in_range(Point::zero()..position)
17174                    .find(|hunk| hunk.row_range.end.0 < position.row)
17175            })
17176    }
17177
17178    fn go_to_prev_hunk(
17179        &mut self,
17180        _: &GoToPreviousHunk,
17181        window: &mut Window,
17182        cx: &mut Context<Self>,
17183    ) {
17184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17185        let snapshot = self.snapshot(window, cx);
17186        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17187        self.go_to_hunk_before_or_after_position(
17188            &snapshot,
17189            selection.head(),
17190            Direction::Prev,
17191            window,
17192            cx,
17193        );
17194    }
17195
17196    fn hunk_before_position(
17197        &mut self,
17198        snapshot: &EditorSnapshot,
17199        position: Point,
17200    ) -> Option<MultiBufferRow> {
17201        snapshot
17202            .buffer_snapshot()
17203            .diff_hunk_before(position)
17204            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17205    }
17206
17207    fn go_to_next_change(
17208        &mut self,
17209        _: &GoToNextChange,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) {
17213        if let Some(selections) = self
17214            .change_list
17215            .next_change(1, Direction::Next)
17216            .map(|s| s.to_vec())
17217        {
17218            self.change_selections(Default::default(), window, cx, |s| {
17219                let map = s.display_snapshot();
17220                s.select_display_ranges(selections.iter().map(|a| {
17221                    let point = a.to_display_point(&map);
17222                    point..point
17223                }))
17224            })
17225        }
17226    }
17227
17228    fn go_to_previous_change(
17229        &mut self,
17230        _: &GoToPreviousChange,
17231        window: &mut Window,
17232        cx: &mut Context<Self>,
17233    ) {
17234        if let Some(selections) = self
17235            .change_list
17236            .next_change(1, Direction::Prev)
17237            .map(|s| s.to_vec())
17238        {
17239            self.change_selections(Default::default(), window, cx, |s| {
17240                let map = s.display_snapshot();
17241                s.select_display_ranges(selections.iter().map(|a| {
17242                    let point = a.to_display_point(&map);
17243                    point..point
17244                }))
17245            })
17246        }
17247    }
17248
17249    pub fn go_to_next_document_highlight(
17250        &mut self,
17251        _: &GoToNextDocumentHighlight,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) {
17255        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17256    }
17257
17258    pub fn go_to_prev_document_highlight(
17259        &mut self,
17260        _: &GoToPreviousDocumentHighlight,
17261        window: &mut Window,
17262        cx: &mut Context<Self>,
17263    ) {
17264        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17265    }
17266
17267    pub fn go_to_document_highlight_before_or_after_position(
17268        &mut self,
17269        direction: Direction,
17270        window: &mut Window,
17271        cx: &mut Context<Editor>,
17272    ) {
17273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17274        let snapshot = self.snapshot(window, cx);
17275        let buffer = &snapshot.buffer_snapshot();
17276        let position = self
17277            .selections
17278            .newest::<Point>(&snapshot.display_snapshot)
17279            .head();
17280        let anchor_position = buffer.anchor_after(position);
17281
17282        // Get all document highlights (both read and write)
17283        let mut all_highlights = Vec::new();
17284
17285        if let Some((_, read_highlights)) = self
17286            .background_highlights
17287            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17288        {
17289            all_highlights.extend(read_highlights.iter());
17290        }
17291
17292        if let Some((_, write_highlights)) = self
17293            .background_highlights
17294            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17295        {
17296            all_highlights.extend(write_highlights.iter());
17297        }
17298
17299        if all_highlights.is_empty() {
17300            return;
17301        }
17302
17303        // Sort highlights by position
17304        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17305
17306        let target_highlight = match direction {
17307            Direction::Next => {
17308                // Find the first highlight after the current position
17309                all_highlights
17310                    .iter()
17311                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17312            }
17313            Direction::Prev => {
17314                // Find the last highlight before the current position
17315                all_highlights
17316                    .iter()
17317                    .rev()
17318                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17319            }
17320        };
17321
17322        if let Some(highlight) = target_highlight {
17323            let destination = highlight.start.to_point(buffer);
17324            let autoscroll = Autoscroll::center();
17325
17326            self.unfold_ranges(&[destination..destination], false, false, cx);
17327            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17328                s.select_ranges([destination..destination]);
17329            });
17330        }
17331    }
17332
17333    fn go_to_line<T: 'static>(
17334        &mut self,
17335        position: Anchor,
17336        highlight_color: Option<Hsla>,
17337        window: &mut Window,
17338        cx: &mut Context<Self>,
17339    ) {
17340        let snapshot = self.snapshot(window, cx).display_snapshot;
17341        let position = position.to_point(&snapshot.buffer_snapshot());
17342        let start = snapshot
17343            .buffer_snapshot()
17344            .clip_point(Point::new(position.row, 0), Bias::Left);
17345        let end = start + Point::new(1, 0);
17346        let start = snapshot.buffer_snapshot().anchor_before(start);
17347        let end = snapshot.buffer_snapshot().anchor_before(end);
17348
17349        self.highlight_rows::<T>(
17350            start..end,
17351            highlight_color
17352                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17353            Default::default(),
17354            cx,
17355        );
17356
17357        if self.buffer.read(cx).is_singleton() {
17358            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17359        }
17360    }
17361
17362    pub fn go_to_definition(
17363        &mut self,
17364        _: &GoToDefinition,
17365        window: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) -> Task<Result<Navigated>> {
17368        let definition =
17369            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17370        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17371        cx.spawn_in(window, async move |editor, cx| {
17372            if definition.await? == Navigated::Yes {
17373                return Ok(Navigated::Yes);
17374            }
17375            match fallback_strategy {
17376                GoToDefinitionFallback::None => Ok(Navigated::No),
17377                GoToDefinitionFallback::FindAllReferences => {
17378                    match editor.update_in(cx, |editor, window, cx| {
17379                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17380                    })? {
17381                        Some(references) => references.await,
17382                        None => Ok(Navigated::No),
17383                    }
17384                }
17385            }
17386        })
17387    }
17388
17389    pub fn go_to_declaration(
17390        &mut self,
17391        _: &GoToDeclaration,
17392        window: &mut Window,
17393        cx: &mut Context<Self>,
17394    ) -> Task<Result<Navigated>> {
17395        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17396    }
17397
17398    pub fn go_to_declaration_split(
17399        &mut self,
17400        _: &GoToDeclaration,
17401        window: &mut Window,
17402        cx: &mut Context<Self>,
17403    ) -> Task<Result<Navigated>> {
17404        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17405    }
17406
17407    pub fn go_to_implementation(
17408        &mut self,
17409        _: &GoToImplementation,
17410        window: &mut Window,
17411        cx: &mut Context<Self>,
17412    ) -> Task<Result<Navigated>> {
17413        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17414    }
17415
17416    pub fn go_to_implementation_split(
17417        &mut self,
17418        _: &GoToImplementationSplit,
17419        window: &mut Window,
17420        cx: &mut Context<Self>,
17421    ) -> Task<Result<Navigated>> {
17422        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17423    }
17424
17425    pub fn go_to_type_definition(
17426        &mut self,
17427        _: &GoToTypeDefinition,
17428        window: &mut Window,
17429        cx: &mut Context<Self>,
17430    ) -> Task<Result<Navigated>> {
17431        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17432    }
17433
17434    pub fn go_to_definition_split(
17435        &mut self,
17436        _: &GoToDefinitionSplit,
17437        window: &mut Window,
17438        cx: &mut Context<Self>,
17439    ) -> Task<Result<Navigated>> {
17440        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17441    }
17442
17443    pub fn go_to_type_definition_split(
17444        &mut self,
17445        _: &GoToTypeDefinitionSplit,
17446        window: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) -> Task<Result<Navigated>> {
17449        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17450    }
17451
17452    fn go_to_definition_of_kind(
17453        &mut self,
17454        kind: GotoDefinitionKind,
17455        split: bool,
17456        window: &mut Window,
17457        cx: &mut Context<Self>,
17458    ) -> Task<Result<Navigated>> {
17459        let Some(provider) = self.semantics_provider.clone() else {
17460            return Task::ready(Ok(Navigated::No));
17461        };
17462        let head = self
17463            .selections
17464            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17465            .head();
17466        let buffer = self.buffer.read(cx);
17467        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17468            return Task::ready(Ok(Navigated::No));
17469        };
17470        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17471            return Task::ready(Ok(Navigated::No));
17472        };
17473
17474        cx.spawn_in(window, async move |editor, cx| {
17475            let Some(definitions) = definitions.await? else {
17476                return Ok(Navigated::No);
17477            };
17478            let navigated = editor
17479                .update_in(cx, |editor, window, cx| {
17480                    editor.navigate_to_hover_links(
17481                        Some(kind),
17482                        definitions
17483                            .into_iter()
17484                            .filter(|location| {
17485                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17486                            })
17487                            .map(HoverLink::Text)
17488                            .collect::<Vec<_>>(),
17489                        split,
17490                        window,
17491                        cx,
17492                    )
17493                })?
17494                .await?;
17495            anyhow::Ok(navigated)
17496        })
17497    }
17498
17499    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17500        let selection = self.selections.newest_anchor();
17501        let head = selection.head();
17502        let tail = selection.tail();
17503
17504        let Some((buffer, start_position)) =
17505            self.buffer.read(cx).text_anchor_for_position(head, cx)
17506        else {
17507            return;
17508        };
17509
17510        let end_position = if head != tail {
17511            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17512                return;
17513            };
17514            Some(pos)
17515        } else {
17516            None
17517        };
17518
17519        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17520            let url = if let Some(end_pos) = end_position {
17521                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17522            } else {
17523                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17524            };
17525
17526            if let Some(url) = url {
17527                cx.update(|window, cx| {
17528                    if parse_zed_link(&url, cx).is_some() {
17529                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17530                    } else {
17531                        cx.open_url(&url);
17532                    }
17533                })?;
17534            }
17535
17536            anyhow::Ok(())
17537        });
17538
17539        url_finder.detach();
17540    }
17541
17542    pub fn open_selected_filename(
17543        &mut self,
17544        _: &OpenSelectedFilename,
17545        window: &mut Window,
17546        cx: &mut Context<Self>,
17547    ) {
17548        let Some(workspace) = self.workspace() else {
17549            return;
17550        };
17551
17552        let position = self.selections.newest_anchor().head();
17553
17554        let Some((buffer, buffer_position)) =
17555            self.buffer.read(cx).text_anchor_for_position(position, cx)
17556        else {
17557            return;
17558        };
17559
17560        let project = self.project.clone();
17561
17562        cx.spawn_in(window, async move |_, cx| {
17563            let result = find_file(&buffer, project, buffer_position, cx).await;
17564
17565            if let Some((_, path)) = result {
17566                workspace
17567                    .update_in(cx, |workspace, window, cx| {
17568                        workspace.open_resolved_path(path, window, cx)
17569                    })?
17570                    .await?;
17571            }
17572            anyhow::Ok(())
17573        })
17574        .detach();
17575    }
17576
17577    pub(crate) fn navigate_to_hover_links(
17578        &mut self,
17579        kind: Option<GotoDefinitionKind>,
17580        definitions: Vec<HoverLink>,
17581        split: bool,
17582        window: &mut Window,
17583        cx: &mut Context<Editor>,
17584    ) -> Task<Result<Navigated>> {
17585        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17586        let mut first_url_or_file = None;
17587        let definitions: Vec<_> = definitions
17588            .into_iter()
17589            .filter_map(|def| match def {
17590                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17591                HoverLink::InlayHint(lsp_location, server_id) => {
17592                    let computation =
17593                        self.compute_target_location(lsp_location, server_id, window, cx);
17594                    Some(cx.background_spawn(computation))
17595                }
17596                HoverLink::Url(url) => {
17597                    first_url_or_file = Some(Either::Left(url));
17598                    None
17599                }
17600                HoverLink::File(path) => {
17601                    first_url_or_file = Some(Either::Right(path));
17602                    None
17603                }
17604            })
17605            .collect();
17606
17607        let workspace = self.workspace();
17608
17609        cx.spawn_in(window, async move |editor, cx| {
17610            let locations: Vec<Location> = future::join_all(definitions)
17611                .await
17612                .into_iter()
17613                .filter_map(|location| location.transpose())
17614                .collect::<Result<_>>()
17615                .context("location tasks")?;
17616            let mut locations = cx.update(|_, cx| {
17617                locations
17618                    .into_iter()
17619                    .map(|location| {
17620                        let buffer = location.buffer.read(cx);
17621                        (location.buffer, location.range.to_point(buffer))
17622                    })
17623                    .into_group_map()
17624            })?;
17625            let mut num_locations = 0;
17626            for ranges in locations.values_mut() {
17627                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17628                ranges.dedup();
17629                num_locations += ranges.len();
17630            }
17631
17632            if num_locations > 1 {
17633                let tab_kind = match kind {
17634                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17635                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17636                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17637                    Some(GotoDefinitionKind::Type) => "Types",
17638                };
17639                let title = editor
17640                    .update_in(cx, |_, _, cx| {
17641                        let target = locations
17642                            .iter()
17643                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17644                            .map(|(buffer, location)| {
17645                                buffer
17646                                    .read(cx)
17647                                    .text_for_range(location.clone())
17648                                    .collect::<String>()
17649                            })
17650                            .filter(|text| !text.contains('\n'))
17651                            .unique()
17652                            .take(3)
17653                            .join(", ");
17654                        if target.is_empty() {
17655                            tab_kind.to_owned()
17656                        } else {
17657                            format!("{tab_kind} for {target}")
17658                        }
17659                    })
17660                    .context("buffer title")?;
17661
17662                let Some(workspace) = workspace else {
17663                    return Ok(Navigated::No);
17664                };
17665
17666                let opened = workspace
17667                    .update_in(cx, |workspace, window, cx| {
17668                        let allow_preview = PreviewTabsSettings::get_global(cx)
17669                            .enable_preview_multibuffer_from_code_navigation;
17670                        Self::open_locations_in_multibuffer(
17671                            workspace,
17672                            locations,
17673                            title,
17674                            split,
17675                            allow_preview,
17676                            MultibufferSelectionMode::First,
17677                            window,
17678                            cx,
17679                        )
17680                    })
17681                    .is_ok();
17682
17683                anyhow::Ok(Navigated::from_bool(opened))
17684            } else if num_locations == 0 {
17685                // If there is one url or file, open it directly
17686                match first_url_or_file {
17687                    Some(Either::Left(url)) => {
17688                        cx.update(|window, cx| {
17689                            if parse_zed_link(&url, cx).is_some() {
17690                                window
17691                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17692                            } else {
17693                                cx.open_url(&url);
17694                            }
17695                        })?;
17696                        Ok(Navigated::Yes)
17697                    }
17698                    Some(Either::Right(path)) => {
17699                        // TODO(andrew): respect preview tab settings
17700                        //               `enable_keep_preview_on_code_navigation` and
17701                        //               `enable_preview_file_from_code_navigation`
17702                        let Some(workspace) = workspace else {
17703                            return Ok(Navigated::No);
17704                        };
17705                        workspace
17706                            .update_in(cx, |workspace, window, cx| {
17707                                workspace.open_resolved_path(path, window, cx)
17708                            })?
17709                            .await?;
17710                        Ok(Navigated::Yes)
17711                    }
17712                    None => Ok(Navigated::No),
17713                }
17714            } else {
17715                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17716                let target_range = target_ranges.first().unwrap().clone();
17717
17718                editor.update_in(cx, |editor, window, cx| {
17719                    let range = target_range.to_point(target_buffer.read(cx));
17720                    let range = editor.range_for_match(&range);
17721                    let range = collapse_multiline_range(range);
17722
17723                    if !split
17724                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17725                    {
17726                        editor.go_to_singleton_buffer_range(range, window, cx);
17727                    } else {
17728                        let Some(workspace) = workspace else {
17729                            return Navigated::No;
17730                        };
17731                        let pane = workspace.read(cx).active_pane().clone();
17732                        window.defer(cx, move |window, cx| {
17733                            let target_editor: Entity<Self> =
17734                                workspace.update(cx, |workspace, cx| {
17735                                    let pane = if split {
17736                                        workspace.adjacent_pane(window, cx)
17737                                    } else {
17738                                        workspace.active_pane().clone()
17739                                    };
17740
17741                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17742                                    let keep_old_preview = preview_tabs_settings
17743                                        .enable_keep_preview_on_code_navigation;
17744                                    let allow_new_preview = preview_tabs_settings
17745                                        .enable_preview_file_from_code_navigation;
17746
17747                                    workspace.open_project_item(
17748                                        pane,
17749                                        target_buffer.clone(),
17750                                        true,
17751                                        true,
17752                                        keep_old_preview,
17753                                        allow_new_preview,
17754                                        window,
17755                                        cx,
17756                                    )
17757                                });
17758                            target_editor.update(cx, |target_editor, cx| {
17759                                // When selecting a definition in a different buffer, disable the nav history
17760                                // to avoid creating a history entry at the previous cursor location.
17761                                pane.update(cx, |pane, _| pane.disable_history());
17762                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17763                                pane.update(cx, |pane, _| pane.enable_history());
17764                            });
17765                        });
17766                    }
17767                    Navigated::Yes
17768                })
17769            }
17770        })
17771    }
17772
17773    fn compute_target_location(
17774        &self,
17775        lsp_location: lsp::Location,
17776        server_id: LanguageServerId,
17777        window: &mut Window,
17778        cx: &mut Context<Self>,
17779    ) -> Task<anyhow::Result<Option<Location>>> {
17780        let Some(project) = self.project.clone() else {
17781            return Task::ready(Ok(None));
17782        };
17783
17784        cx.spawn_in(window, async move |editor, cx| {
17785            let location_task = editor.update(cx, |_, cx| {
17786                project.update(cx, |project, cx| {
17787                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17788                })
17789            })?;
17790            let location = Some({
17791                let target_buffer_handle = location_task.await.context("open local buffer")?;
17792                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17793                    let target_start = target_buffer
17794                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17795                    let target_end = target_buffer
17796                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17797                    target_buffer.anchor_after(target_start)
17798                        ..target_buffer.anchor_before(target_end)
17799                });
17800                Location {
17801                    buffer: target_buffer_handle,
17802                    range,
17803                }
17804            });
17805            Ok(location)
17806        })
17807    }
17808
17809    fn go_to_next_reference(
17810        &mut self,
17811        _: &GoToNextReference,
17812        window: &mut Window,
17813        cx: &mut Context<Self>,
17814    ) {
17815        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17816        if let Some(task) = task {
17817            task.detach();
17818        };
17819    }
17820
17821    fn go_to_prev_reference(
17822        &mut self,
17823        _: &GoToPreviousReference,
17824        window: &mut Window,
17825        cx: &mut Context<Self>,
17826    ) {
17827        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17828        if let Some(task) = task {
17829            task.detach();
17830        };
17831    }
17832
17833    pub fn go_to_reference_before_or_after_position(
17834        &mut self,
17835        direction: Direction,
17836        count: usize,
17837        window: &mut Window,
17838        cx: &mut Context<Self>,
17839    ) -> Option<Task<Result<()>>> {
17840        let selection = self.selections.newest_anchor();
17841        let head = selection.head();
17842
17843        let multi_buffer = self.buffer.read(cx);
17844
17845        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17846        let workspace = self.workspace()?;
17847        let project = workspace.read(cx).project().clone();
17848        let references =
17849            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17850        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17851            let Some(locations) = references.await? else {
17852                return Ok(());
17853            };
17854
17855            if locations.is_empty() {
17856                // totally normal - the cursor may be on something which is not
17857                // a symbol (e.g. a keyword)
17858                log::info!("no references found under cursor");
17859                return Ok(());
17860            }
17861
17862            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17863
17864            let (locations, current_location_index) =
17865                multi_buffer.update(cx, |multi_buffer, cx| {
17866                    let mut locations = locations
17867                        .into_iter()
17868                        .filter_map(|loc| {
17869                            let start = multi_buffer.buffer_anchor_to_anchor(
17870                                &loc.buffer,
17871                                loc.range.start,
17872                                cx,
17873                            )?;
17874                            let end = multi_buffer.buffer_anchor_to_anchor(
17875                                &loc.buffer,
17876                                loc.range.end,
17877                                cx,
17878                            )?;
17879                            Some(start..end)
17880                        })
17881                        .collect::<Vec<_>>();
17882
17883                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17884                    // There is an O(n) implementation, but given this list will be
17885                    // small (usually <100 items), the extra O(log(n)) factor isn't
17886                    // worth the (surprisingly large amount of) extra complexity.
17887                    locations
17888                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17889
17890                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17891
17892                    let current_location_index = locations.iter().position(|loc| {
17893                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17894                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17895                    });
17896
17897                    (locations, current_location_index)
17898                });
17899
17900            let Some(current_location_index) = current_location_index else {
17901                // This indicates something has gone wrong, because we already
17902                // handle the "no references" case above
17903                log::error!(
17904                    "failed to find current reference under cursor. Total references: {}",
17905                    locations.len()
17906                );
17907                return Ok(());
17908            };
17909
17910            let destination_location_index = match direction {
17911                Direction::Next => (current_location_index + count) % locations.len(),
17912                Direction::Prev => {
17913                    (current_location_index + locations.len() - count % locations.len())
17914                        % locations.len()
17915                }
17916            };
17917
17918            // TODO(cameron): is this needed?
17919            // the thinking is to avoid "jumping to the current location" (avoid
17920            // polluting "jumplist" in vim terms)
17921            if current_location_index == destination_location_index {
17922                return Ok(());
17923            }
17924
17925            let Range { start, end } = locations[destination_location_index];
17926
17927            editor.update_in(cx, |editor, window, cx| {
17928                let effects = SelectionEffects::default();
17929
17930                editor.unfold_ranges(&[start..end], false, false, cx);
17931                editor.change_selections(effects, window, cx, |s| {
17932                    s.select_ranges([start..start]);
17933                });
17934            })?;
17935
17936            Ok(())
17937        }))
17938    }
17939
17940    pub fn find_all_references(
17941        &mut self,
17942        action: &FindAllReferences,
17943        window: &mut Window,
17944        cx: &mut Context<Self>,
17945    ) -> Option<Task<Result<Navigated>>> {
17946        let always_open_multibuffer = action.always_open_multibuffer;
17947        let selection = self.selections.newest_anchor();
17948        let multi_buffer = self.buffer.read(cx);
17949        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17950        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17951        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17952        let head = selection_offset.head();
17953
17954        let head_anchor = multi_buffer_snapshot.anchor_at(
17955            head,
17956            if head < selection_offset.tail() {
17957                Bias::Right
17958            } else {
17959                Bias::Left
17960            },
17961        );
17962
17963        match self
17964            .find_all_references_task_sources
17965            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17966        {
17967            Ok(_) => {
17968                log::info!(
17969                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17970                );
17971                return None;
17972            }
17973            Err(i) => {
17974                self.find_all_references_task_sources.insert(i, head_anchor);
17975            }
17976        }
17977
17978        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17979        let workspace = self.workspace()?;
17980        let project = workspace.read(cx).project().clone();
17981        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17982        Some(cx.spawn_in(window, async move |editor, cx| {
17983            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17984                if let Ok(i) = editor
17985                    .find_all_references_task_sources
17986                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17987                {
17988                    editor.find_all_references_task_sources.remove(i);
17989                }
17990            });
17991
17992            let Some(locations) = references.await? else {
17993                return anyhow::Ok(Navigated::No);
17994            };
17995            let mut locations = cx.update(|_, cx| {
17996                locations
17997                    .into_iter()
17998                    .map(|location| {
17999                        let buffer = location.buffer.read(cx);
18000                        (location.buffer, location.range.to_point(buffer))
18001                    })
18002                    // if special-casing the single-match case, remove ranges
18003                    // that intersect current selection
18004                    .filter(|(location_buffer, location)| {
18005                        if always_open_multibuffer || &buffer != location_buffer {
18006                            return true;
18007                        }
18008
18009                        !location.contains_inclusive(&selection_point.range())
18010                    })
18011                    .into_group_map()
18012            })?;
18013            if locations.is_empty() {
18014                return anyhow::Ok(Navigated::No);
18015            }
18016            for ranges in locations.values_mut() {
18017                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18018                ranges.dedup();
18019            }
18020            let mut num_locations = 0;
18021            for ranges in locations.values_mut() {
18022                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18023                ranges.dedup();
18024                num_locations += ranges.len();
18025            }
18026
18027            if num_locations == 1 && !always_open_multibuffer {
18028                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18029                let target_range = target_ranges.first().unwrap().clone();
18030
18031                return editor.update_in(cx, |editor, window, cx| {
18032                    let range = target_range.to_point(target_buffer.read(cx));
18033                    let range = editor.range_for_match(&range);
18034                    let range = range.start..range.start;
18035
18036                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18037                        editor.go_to_singleton_buffer_range(range, window, cx);
18038                    } else {
18039                        let pane = workspace.read(cx).active_pane().clone();
18040                        window.defer(cx, move |window, cx| {
18041                            let target_editor: Entity<Self> =
18042                                workspace.update(cx, |workspace, cx| {
18043                                    let pane = workspace.active_pane().clone();
18044
18045                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18046                                    let keep_old_preview = preview_tabs_settings
18047                                        .enable_keep_preview_on_code_navigation;
18048                                    let allow_new_preview = preview_tabs_settings
18049                                        .enable_preview_file_from_code_navigation;
18050
18051                                    workspace.open_project_item(
18052                                        pane,
18053                                        target_buffer.clone(),
18054                                        true,
18055                                        true,
18056                                        keep_old_preview,
18057                                        allow_new_preview,
18058                                        window,
18059                                        cx,
18060                                    )
18061                                });
18062                            target_editor.update(cx, |target_editor, cx| {
18063                                // When selecting a definition in a different buffer, disable the nav history
18064                                // to avoid creating a history entry at the previous cursor location.
18065                                pane.update(cx, |pane, _| pane.disable_history());
18066                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18067                                pane.update(cx, |pane, _| pane.enable_history());
18068                            });
18069                        });
18070                    }
18071                    Navigated::No
18072                });
18073            }
18074
18075            workspace.update_in(cx, |workspace, window, cx| {
18076                let target = locations
18077                    .iter()
18078                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18079                    .map(|(buffer, location)| {
18080                        buffer
18081                            .read(cx)
18082                            .text_for_range(location.clone())
18083                            .collect::<String>()
18084                    })
18085                    .filter(|text| !text.contains('\n'))
18086                    .unique()
18087                    .take(3)
18088                    .join(", ");
18089                let title = if target.is_empty() {
18090                    "References".to_owned()
18091                } else {
18092                    format!("References to {target}")
18093                };
18094                let allow_preview = PreviewTabsSettings::get_global(cx)
18095                    .enable_preview_multibuffer_from_code_navigation;
18096                Self::open_locations_in_multibuffer(
18097                    workspace,
18098                    locations,
18099                    title,
18100                    false,
18101                    allow_preview,
18102                    MultibufferSelectionMode::First,
18103                    window,
18104                    cx,
18105                );
18106                Navigated::Yes
18107            })
18108        }))
18109    }
18110
18111    /// Opens a multibuffer with the given project locations in it.
18112    pub fn open_locations_in_multibuffer(
18113        workspace: &mut Workspace,
18114        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18115        title: String,
18116        split: bool,
18117        allow_preview: bool,
18118        multibuffer_selection_mode: MultibufferSelectionMode,
18119        window: &mut Window,
18120        cx: &mut Context<Workspace>,
18121    ) {
18122        if locations.is_empty() {
18123            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18124            return;
18125        }
18126
18127        let capability = workspace.project().read(cx).capability();
18128        let mut ranges = <Vec<Range<Anchor>>>::new();
18129
18130        // a key to find existing multibuffer editors with the same set of locations
18131        // to prevent us from opening more and more multibuffer tabs for searches and the like
18132        let mut key = (title.clone(), vec![]);
18133        let excerpt_buffer = cx.new(|cx| {
18134            let key = &mut key.1;
18135            let mut multibuffer = MultiBuffer::new(capability);
18136            for (buffer, mut ranges_for_buffer) in locations {
18137                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18138                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18139                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18140                    PathKey::for_buffer(&buffer, cx),
18141                    buffer.clone(),
18142                    ranges_for_buffer,
18143                    multibuffer_context_lines(cx),
18144                    cx,
18145                );
18146                ranges.extend(new_ranges)
18147            }
18148
18149            multibuffer.with_title(title)
18150        });
18151        let existing = workspace.active_pane().update(cx, |pane, cx| {
18152            pane.items()
18153                .filter_map(|item| item.downcast::<Editor>())
18154                .find(|editor| {
18155                    editor
18156                        .read(cx)
18157                        .lookup_key
18158                        .as_ref()
18159                        .and_then(|it| {
18160                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18161                        })
18162                        .is_some_and(|it| *it == key)
18163                })
18164        });
18165        let was_existing = existing.is_some();
18166        let editor = existing.unwrap_or_else(|| {
18167            cx.new(|cx| {
18168                let mut editor = Editor::for_multibuffer(
18169                    excerpt_buffer,
18170                    Some(workspace.project().clone()),
18171                    window,
18172                    cx,
18173                );
18174                editor.lookup_key = Some(Box::new(key));
18175                editor
18176            })
18177        });
18178        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18179            MultibufferSelectionMode::First => {
18180                if let Some(first_range) = ranges.first() {
18181                    editor.change_selections(
18182                        SelectionEffects::no_scroll(),
18183                        window,
18184                        cx,
18185                        |selections| {
18186                            selections.clear_disjoint();
18187                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18188                        },
18189                    );
18190                }
18191                editor.highlight_background::<Self>(
18192                    &ranges,
18193                    |_, theme| theme.colors().editor_highlighted_line_background,
18194                    cx,
18195                );
18196            }
18197            MultibufferSelectionMode::All => {
18198                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18199                    selections.clear_disjoint();
18200                    selections.select_anchor_ranges(ranges);
18201                });
18202            }
18203        });
18204
18205        let item = Box::new(editor);
18206
18207        let pane = if split {
18208            workspace.adjacent_pane(window, cx)
18209        } else {
18210            workspace.active_pane().clone()
18211        };
18212        let activate_pane = split;
18213
18214        let mut destination_index = None;
18215        pane.update(cx, |pane, cx| {
18216            if allow_preview && !was_existing {
18217                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18218            }
18219            if was_existing && !allow_preview {
18220                pane.unpreview_item_if_preview(item.item_id());
18221            }
18222            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18223        });
18224    }
18225
18226    pub fn rename(
18227        &mut self,
18228        _: &Rename,
18229        window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) -> Option<Task<Result<()>>> {
18232        use language::ToOffset as _;
18233
18234        let provider = self.semantics_provider.clone()?;
18235        let selection = self.selections.newest_anchor().clone();
18236        let (cursor_buffer, cursor_buffer_position) = self
18237            .buffer
18238            .read(cx)
18239            .text_anchor_for_position(selection.head(), cx)?;
18240        let (tail_buffer, cursor_buffer_position_end) = self
18241            .buffer
18242            .read(cx)
18243            .text_anchor_for_position(selection.tail(), cx)?;
18244        if tail_buffer != cursor_buffer {
18245            return None;
18246        }
18247
18248        let snapshot = cursor_buffer.read(cx).snapshot();
18249        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18250        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18251        let prepare_rename = provider
18252            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18253            .unwrap_or_else(|| Task::ready(Ok(None)));
18254        drop(snapshot);
18255
18256        Some(cx.spawn_in(window, async move |this, cx| {
18257            let rename_range = if let Some(range) = prepare_rename.await? {
18258                Some(range)
18259            } else {
18260                this.update(cx, |this, cx| {
18261                    let buffer = this.buffer.read(cx).snapshot(cx);
18262                    let mut buffer_highlights = this
18263                        .document_highlights_for_position(selection.head(), &buffer)
18264                        .filter(|highlight| {
18265                            highlight.start.excerpt_id == selection.head().excerpt_id
18266                                && highlight.end.excerpt_id == selection.head().excerpt_id
18267                        });
18268                    buffer_highlights
18269                        .next()
18270                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18271                })?
18272            };
18273            if let Some(rename_range) = rename_range {
18274                this.update_in(cx, |this, window, cx| {
18275                    let snapshot = cursor_buffer.read(cx).snapshot();
18276                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18277                    let cursor_offset_in_rename_range =
18278                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18279                    let cursor_offset_in_rename_range_end =
18280                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18281
18282                    this.take_rename(false, window, cx);
18283                    let buffer = this.buffer.read(cx).read(cx);
18284                    let cursor_offset = selection.head().to_offset(&buffer);
18285                    let rename_start =
18286                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18287                    let rename_end = rename_start + rename_buffer_range.len();
18288                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18289                    let mut old_highlight_id = None;
18290                    let old_name: Arc<str> = buffer
18291                        .chunks(rename_start..rename_end, true)
18292                        .map(|chunk| {
18293                            if old_highlight_id.is_none() {
18294                                old_highlight_id = chunk.syntax_highlight_id;
18295                            }
18296                            chunk.text
18297                        })
18298                        .collect::<String>()
18299                        .into();
18300
18301                    drop(buffer);
18302
18303                    // Position the selection in the rename editor so that it matches the current selection.
18304                    this.show_local_selections = false;
18305                    let rename_editor = cx.new(|cx| {
18306                        let mut editor = Editor::single_line(window, cx);
18307                        editor.buffer.update(cx, |buffer, cx| {
18308                            buffer.edit(
18309                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18310                                None,
18311                                cx,
18312                            )
18313                        });
18314                        let cursor_offset_in_rename_range =
18315                            MultiBufferOffset(cursor_offset_in_rename_range);
18316                        let cursor_offset_in_rename_range_end =
18317                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18318                        let rename_selection_range = match cursor_offset_in_rename_range
18319                            .cmp(&cursor_offset_in_rename_range_end)
18320                        {
18321                            Ordering::Equal => {
18322                                editor.select_all(&SelectAll, window, cx);
18323                                return editor;
18324                            }
18325                            Ordering::Less => {
18326                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18327                            }
18328                            Ordering::Greater => {
18329                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18330                            }
18331                        };
18332                        if rename_selection_range.end.0 > old_name.len() {
18333                            editor.select_all(&SelectAll, window, cx);
18334                        } else {
18335                            editor.change_selections(Default::default(), window, cx, |s| {
18336                                s.select_ranges([rename_selection_range]);
18337                            });
18338                        }
18339                        editor
18340                    });
18341                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18342                        if e == &EditorEvent::Focused {
18343                            cx.emit(EditorEvent::FocusedIn)
18344                        }
18345                    })
18346                    .detach();
18347
18348                    let write_highlights =
18349                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18350                    let read_highlights =
18351                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18352                    let ranges = write_highlights
18353                        .iter()
18354                        .flat_map(|(_, ranges)| ranges.iter())
18355                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18356                        .cloned()
18357                        .collect();
18358
18359                    this.highlight_text::<Rename>(
18360                        ranges,
18361                        HighlightStyle {
18362                            fade_out: Some(0.6),
18363                            ..Default::default()
18364                        },
18365                        cx,
18366                    );
18367                    let rename_focus_handle = rename_editor.focus_handle(cx);
18368                    window.focus(&rename_focus_handle, cx);
18369                    let block_id = this.insert_blocks(
18370                        [BlockProperties {
18371                            style: BlockStyle::Flex,
18372                            placement: BlockPlacement::Below(range.start),
18373                            height: Some(1),
18374                            render: Arc::new({
18375                                let rename_editor = rename_editor.clone();
18376                                move |cx: &mut BlockContext| {
18377                                    let mut text_style = cx.editor_style.text.clone();
18378                                    if let Some(highlight_style) = old_highlight_id
18379                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18380                                    {
18381                                        text_style = text_style.highlight(highlight_style);
18382                                    }
18383                                    div()
18384                                        .block_mouse_except_scroll()
18385                                        .pl(cx.anchor_x)
18386                                        .child(EditorElement::new(
18387                                            &rename_editor,
18388                                            EditorStyle {
18389                                                background: cx.theme().system().transparent,
18390                                                local_player: cx.editor_style.local_player,
18391                                                text: text_style,
18392                                                scrollbar_width: cx.editor_style.scrollbar_width,
18393                                                syntax: cx.editor_style.syntax.clone(),
18394                                                status: cx.editor_style.status.clone(),
18395                                                inlay_hints_style: HighlightStyle {
18396                                                    font_weight: Some(FontWeight::BOLD),
18397                                                    ..make_inlay_hints_style(cx.app)
18398                                                },
18399                                                edit_prediction_styles: make_suggestion_styles(
18400                                                    cx.app,
18401                                                ),
18402                                                ..EditorStyle::default()
18403                                            },
18404                                        ))
18405                                        .into_any_element()
18406                                }
18407                            }),
18408                            priority: 0,
18409                        }],
18410                        Some(Autoscroll::fit()),
18411                        cx,
18412                    )[0];
18413                    this.pending_rename = Some(RenameState {
18414                        range,
18415                        old_name,
18416                        editor: rename_editor,
18417                        block_id,
18418                    });
18419                })?;
18420            }
18421
18422            Ok(())
18423        }))
18424    }
18425
18426    pub fn confirm_rename(
18427        &mut self,
18428        _: &ConfirmRename,
18429        window: &mut Window,
18430        cx: &mut Context<Self>,
18431    ) -> Option<Task<Result<()>>> {
18432        let rename = self.take_rename(false, window, cx)?;
18433        let workspace = self.workspace()?.downgrade();
18434        let (buffer, start) = self
18435            .buffer
18436            .read(cx)
18437            .text_anchor_for_position(rename.range.start, cx)?;
18438        let (end_buffer, _) = self
18439            .buffer
18440            .read(cx)
18441            .text_anchor_for_position(rename.range.end, cx)?;
18442        if buffer != end_buffer {
18443            return None;
18444        }
18445
18446        let old_name = rename.old_name;
18447        let new_name = rename.editor.read(cx).text(cx);
18448
18449        let rename = self.semantics_provider.as_ref()?.perform_rename(
18450            &buffer,
18451            start,
18452            new_name.clone(),
18453            cx,
18454        )?;
18455
18456        Some(cx.spawn_in(window, async move |editor, cx| {
18457            let project_transaction = rename.await?;
18458            Self::open_project_transaction(
18459                &editor,
18460                workspace,
18461                project_transaction,
18462                format!("Rename: {}{}", old_name, new_name),
18463                cx,
18464            )
18465            .await?;
18466
18467            editor.update(cx, |editor, cx| {
18468                editor.refresh_document_highlights(cx);
18469            })?;
18470            Ok(())
18471        }))
18472    }
18473
18474    fn take_rename(
18475        &mut self,
18476        moving_cursor: bool,
18477        window: &mut Window,
18478        cx: &mut Context<Self>,
18479    ) -> Option<RenameState> {
18480        let rename = self.pending_rename.take()?;
18481        if rename.editor.focus_handle(cx).is_focused(window) {
18482            window.focus(&self.focus_handle, cx);
18483        }
18484
18485        self.remove_blocks(
18486            [rename.block_id].into_iter().collect(),
18487            Some(Autoscroll::fit()),
18488            cx,
18489        );
18490        self.clear_highlights::<Rename>(cx);
18491        self.show_local_selections = true;
18492
18493        if moving_cursor {
18494            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18495                editor
18496                    .selections
18497                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18498                    .head()
18499            });
18500
18501            // Update the selection to match the position of the selection inside
18502            // the rename editor.
18503            let snapshot = self.buffer.read(cx).read(cx);
18504            let rename_range = rename.range.to_offset(&snapshot);
18505            let cursor_in_editor = snapshot
18506                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18507                .min(rename_range.end);
18508            drop(snapshot);
18509
18510            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18511                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18512            });
18513        } else {
18514            self.refresh_document_highlights(cx);
18515        }
18516
18517        Some(rename)
18518    }
18519
18520    pub fn pending_rename(&self) -> Option<&RenameState> {
18521        self.pending_rename.as_ref()
18522    }
18523
18524    fn format(
18525        &mut self,
18526        _: &Format,
18527        window: &mut Window,
18528        cx: &mut Context<Self>,
18529    ) -> Option<Task<Result<()>>> {
18530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18531
18532        let project = match &self.project {
18533            Some(project) => project.clone(),
18534            None => return None,
18535        };
18536
18537        Some(self.perform_format(
18538            project,
18539            FormatTrigger::Manual,
18540            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18541            window,
18542            cx,
18543        ))
18544    }
18545
18546    fn format_selections(
18547        &mut self,
18548        _: &FormatSelections,
18549        window: &mut Window,
18550        cx: &mut Context<Self>,
18551    ) -> Option<Task<Result<()>>> {
18552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18553
18554        let project = match &self.project {
18555            Some(project) => project.clone(),
18556            None => return None,
18557        };
18558
18559        let ranges = self
18560            .selections
18561            .all_adjusted(&self.display_snapshot(cx))
18562            .into_iter()
18563            .map(|selection| selection.range())
18564            .collect_vec();
18565
18566        Some(self.perform_format(
18567            project,
18568            FormatTrigger::Manual,
18569            FormatTarget::Ranges(ranges),
18570            window,
18571            cx,
18572        ))
18573    }
18574
18575    fn perform_format(
18576        &mut self,
18577        project: Entity<Project>,
18578        trigger: FormatTrigger,
18579        target: FormatTarget,
18580        window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) -> Task<Result<()>> {
18583        let buffer = self.buffer.clone();
18584        let (buffers, target) = match target {
18585            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18586            FormatTarget::Ranges(selection_ranges) => {
18587                let multi_buffer = buffer.read(cx);
18588                let snapshot = multi_buffer.read(cx);
18589                let mut buffers = HashSet::default();
18590                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18591                    BTreeMap::new();
18592                for selection_range in selection_ranges {
18593                    for (buffer, buffer_range, _) in
18594                        snapshot.range_to_buffer_ranges(selection_range)
18595                    {
18596                        let buffer_id = buffer.remote_id();
18597                        let start = buffer.anchor_before(buffer_range.start);
18598                        let end = buffer.anchor_after(buffer_range.end);
18599                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18600                        buffer_id_to_ranges
18601                            .entry(buffer_id)
18602                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18603                            .or_insert_with(|| vec![start..end]);
18604                    }
18605                }
18606                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18607            }
18608        };
18609
18610        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18611        let selections_prev = transaction_id_prev
18612            .and_then(|transaction_id_prev| {
18613                // default to selections as they were after the last edit, if we have them,
18614                // instead of how they are now.
18615                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18616                // will take you back to where you made the last edit, instead of staying where you scrolled
18617                self.selection_history
18618                    .transaction(transaction_id_prev)
18619                    .map(|t| t.0.clone())
18620            })
18621            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18622
18623        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18624        let format = project.update(cx, |project, cx| {
18625            project.format(buffers, target, true, trigger, cx)
18626        });
18627
18628        cx.spawn_in(window, async move |editor, cx| {
18629            let transaction = futures::select_biased! {
18630                transaction = format.log_err().fuse() => transaction,
18631                () = timeout => {
18632                    log::warn!("timed out waiting for formatting");
18633                    None
18634                }
18635            };
18636
18637            buffer.update(cx, |buffer, cx| {
18638                if let Some(transaction) = transaction
18639                    && !buffer.is_singleton()
18640                {
18641                    buffer.push_transaction(&transaction.0, cx);
18642                }
18643                cx.notify();
18644            });
18645
18646            if let Some(transaction_id_now) =
18647                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18648            {
18649                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18650                if has_new_transaction {
18651                    editor
18652                        .update(cx, |editor, _| {
18653                            editor
18654                                .selection_history
18655                                .insert_transaction(transaction_id_now, selections_prev);
18656                        })
18657                        .ok();
18658                }
18659            }
18660
18661            Ok(())
18662        })
18663    }
18664
18665    fn organize_imports(
18666        &mut self,
18667        _: &OrganizeImports,
18668        window: &mut Window,
18669        cx: &mut Context<Self>,
18670    ) -> Option<Task<Result<()>>> {
18671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18672        let project = match &self.project {
18673            Some(project) => project.clone(),
18674            None => return None,
18675        };
18676        Some(self.perform_code_action_kind(
18677            project,
18678            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18679            window,
18680            cx,
18681        ))
18682    }
18683
18684    fn perform_code_action_kind(
18685        &mut self,
18686        project: Entity<Project>,
18687        kind: CodeActionKind,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) -> Task<Result<()>> {
18691        let buffer = self.buffer.clone();
18692        let buffers = buffer.read(cx).all_buffers();
18693        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18694        let apply_action = project.update(cx, |project, cx| {
18695            project.apply_code_action_kind(buffers, kind, true, cx)
18696        });
18697        cx.spawn_in(window, async move |_, cx| {
18698            let transaction = futures::select_biased! {
18699                () = timeout => {
18700                    log::warn!("timed out waiting for executing code action");
18701                    None
18702                }
18703                transaction = apply_action.log_err().fuse() => transaction,
18704            };
18705            buffer.update(cx, |buffer, cx| {
18706                // check if we need this
18707                if let Some(transaction) = transaction
18708                    && !buffer.is_singleton()
18709                {
18710                    buffer.push_transaction(&transaction.0, cx);
18711                }
18712                cx.notify();
18713            });
18714            Ok(())
18715        })
18716    }
18717
18718    pub fn restart_language_server(
18719        &mut self,
18720        _: &RestartLanguageServer,
18721        _: &mut Window,
18722        cx: &mut Context<Self>,
18723    ) {
18724        if let Some(project) = self.project.clone() {
18725            self.buffer.update(cx, |multi_buffer, cx| {
18726                project.update(cx, |project, cx| {
18727                    project.restart_language_servers_for_buffers(
18728                        multi_buffer.all_buffers().into_iter().collect(),
18729                        HashSet::default(),
18730                        cx,
18731                    );
18732                });
18733            })
18734        }
18735    }
18736
18737    pub fn stop_language_server(
18738        &mut self,
18739        _: &StopLanguageServer,
18740        _: &mut Window,
18741        cx: &mut Context<Self>,
18742    ) {
18743        if let Some(project) = self.project.clone() {
18744            self.buffer.update(cx, |multi_buffer, cx| {
18745                project.update(cx, |project, cx| {
18746                    project.stop_language_servers_for_buffers(
18747                        multi_buffer.all_buffers().into_iter().collect(),
18748                        HashSet::default(),
18749                        cx,
18750                    );
18751                });
18752            });
18753            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18754        }
18755    }
18756
18757    fn cancel_language_server_work(
18758        workspace: &mut Workspace,
18759        _: &actions::CancelLanguageServerWork,
18760        _: &mut Window,
18761        cx: &mut Context<Workspace>,
18762    ) {
18763        let project = workspace.project();
18764        let buffers = workspace
18765            .active_item(cx)
18766            .and_then(|item| item.act_as::<Editor>(cx))
18767            .map_or(HashSet::default(), |editor| {
18768                editor.read(cx).buffer.read(cx).all_buffers()
18769            });
18770        project.update(cx, |project, cx| {
18771            project.cancel_language_server_work_for_buffers(buffers, cx);
18772        });
18773    }
18774
18775    fn show_character_palette(
18776        &mut self,
18777        _: &ShowCharacterPalette,
18778        window: &mut Window,
18779        _: &mut Context<Self>,
18780    ) {
18781        window.show_character_palette();
18782    }
18783
18784    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18785        if !self.diagnostics_enabled() {
18786            return;
18787        }
18788
18789        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18790            let buffer = self.buffer.read(cx).snapshot(cx);
18791            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18792            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18793            let is_valid = buffer
18794                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18795                .any(|entry| {
18796                    entry.diagnostic.is_primary
18797                        && !entry.range.is_empty()
18798                        && entry.range.start == primary_range_start
18799                        && entry.diagnostic.message == active_diagnostics.active_message
18800                });
18801
18802            if !is_valid {
18803                self.dismiss_diagnostics(cx);
18804            }
18805        }
18806    }
18807
18808    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18809        match &self.active_diagnostics {
18810            ActiveDiagnostic::Group(group) => Some(group),
18811            _ => None,
18812        }
18813    }
18814
18815    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18816        if !self.diagnostics_enabled() {
18817            return;
18818        }
18819        self.dismiss_diagnostics(cx);
18820        self.active_diagnostics = ActiveDiagnostic::All;
18821    }
18822
18823    fn activate_diagnostics(
18824        &mut self,
18825        buffer_id: BufferId,
18826        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18827        window: &mut Window,
18828        cx: &mut Context<Self>,
18829    ) {
18830        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18831            return;
18832        }
18833        self.dismiss_diagnostics(cx);
18834        let snapshot = self.snapshot(window, cx);
18835        let buffer = self.buffer.read(cx).snapshot(cx);
18836        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18837            return;
18838        };
18839
18840        let diagnostic_group = buffer
18841            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18842            .collect::<Vec<_>>();
18843
18844        let language_registry = self
18845            .project()
18846            .map(|project| project.read(cx).languages().clone());
18847
18848        let blocks = renderer.render_group(
18849            diagnostic_group,
18850            buffer_id,
18851            snapshot,
18852            cx.weak_entity(),
18853            language_registry,
18854            cx,
18855        );
18856
18857        let blocks = self.display_map.update(cx, |display_map, cx| {
18858            display_map.insert_blocks(blocks, cx).into_iter().collect()
18859        });
18860        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18861            active_range: buffer.anchor_before(diagnostic.range.start)
18862                ..buffer.anchor_after(diagnostic.range.end),
18863            active_message: diagnostic.diagnostic.message.clone(),
18864            group_id: diagnostic.diagnostic.group_id,
18865            blocks,
18866        });
18867        cx.notify();
18868    }
18869
18870    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18871        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18872            return;
18873        };
18874
18875        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18876        if let ActiveDiagnostic::Group(group) = prev {
18877            self.display_map.update(cx, |display_map, cx| {
18878                display_map.remove_blocks(group.blocks, cx);
18879            });
18880            cx.notify();
18881        }
18882    }
18883
18884    /// Disable inline diagnostics rendering for this editor.
18885    pub fn disable_inline_diagnostics(&mut self) {
18886        self.inline_diagnostics_enabled = false;
18887        self.inline_diagnostics_update = Task::ready(());
18888        self.inline_diagnostics.clear();
18889    }
18890
18891    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18892        self.diagnostics_enabled = false;
18893        self.dismiss_diagnostics(cx);
18894        self.inline_diagnostics_update = Task::ready(());
18895        self.inline_diagnostics.clear();
18896    }
18897
18898    pub fn disable_word_completions(&mut self) {
18899        self.word_completions_enabled = false;
18900    }
18901
18902    pub fn diagnostics_enabled(&self) -> bool {
18903        self.diagnostics_enabled && self.mode.is_full()
18904    }
18905
18906    pub fn inline_diagnostics_enabled(&self) -> bool {
18907        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18908    }
18909
18910    pub fn show_inline_diagnostics(&self) -> bool {
18911        self.show_inline_diagnostics
18912    }
18913
18914    pub fn toggle_inline_diagnostics(
18915        &mut self,
18916        _: &ToggleInlineDiagnostics,
18917        window: &mut Window,
18918        cx: &mut Context<Editor>,
18919    ) {
18920        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18921        self.refresh_inline_diagnostics(false, window, cx);
18922    }
18923
18924    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18925        self.diagnostics_max_severity = severity;
18926        self.display_map.update(cx, |display_map, _| {
18927            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18928        });
18929    }
18930
18931    pub fn toggle_diagnostics(
18932        &mut self,
18933        _: &ToggleDiagnostics,
18934        window: &mut Window,
18935        cx: &mut Context<Editor>,
18936    ) {
18937        if !self.diagnostics_enabled() {
18938            return;
18939        }
18940
18941        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18942            EditorSettings::get_global(cx)
18943                .diagnostics_max_severity
18944                .filter(|severity| severity != &DiagnosticSeverity::Off)
18945                .unwrap_or(DiagnosticSeverity::Hint)
18946        } else {
18947            DiagnosticSeverity::Off
18948        };
18949        self.set_max_diagnostics_severity(new_severity, cx);
18950        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18951            self.active_diagnostics = ActiveDiagnostic::None;
18952            self.inline_diagnostics_update = Task::ready(());
18953            self.inline_diagnostics.clear();
18954        } else {
18955            self.refresh_inline_diagnostics(false, window, cx);
18956        }
18957
18958        cx.notify();
18959    }
18960
18961    pub fn toggle_minimap(
18962        &mut self,
18963        _: &ToggleMinimap,
18964        window: &mut Window,
18965        cx: &mut Context<Editor>,
18966    ) {
18967        if self.supports_minimap(cx) {
18968            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18969        }
18970    }
18971
18972    fn refresh_inline_diagnostics(
18973        &mut self,
18974        debounce: bool,
18975        window: &mut Window,
18976        cx: &mut Context<Self>,
18977    ) {
18978        let max_severity = ProjectSettings::get_global(cx)
18979            .diagnostics
18980            .inline
18981            .max_severity
18982            .unwrap_or(self.diagnostics_max_severity);
18983
18984        if !self.inline_diagnostics_enabled()
18985            || !self.diagnostics_enabled()
18986            || !self.show_inline_diagnostics
18987            || max_severity == DiagnosticSeverity::Off
18988        {
18989            self.inline_diagnostics_update = Task::ready(());
18990            self.inline_diagnostics.clear();
18991            return;
18992        }
18993
18994        let debounce_ms = ProjectSettings::get_global(cx)
18995            .diagnostics
18996            .inline
18997            .update_debounce_ms;
18998        let debounce = if debounce && debounce_ms > 0 {
18999            Some(Duration::from_millis(debounce_ms))
19000        } else {
19001            None
19002        };
19003        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19004            if let Some(debounce) = debounce {
19005                cx.background_executor().timer(debounce).await;
19006            }
19007            let Some(snapshot) = editor.upgrade().map(|editor| {
19008                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19009            }) else {
19010                return;
19011            };
19012
19013            let new_inline_diagnostics = cx
19014                .background_spawn(async move {
19015                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19016                    for diagnostic_entry in
19017                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19018                    {
19019                        let message = diagnostic_entry
19020                            .diagnostic
19021                            .message
19022                            .split_once('\n')
19023                            .map(|(line, _)| line)
19024                            .map(SharedString::new)
19025                            .unwrap_or_else(|| {
19026                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19027                            });
19028                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19029                        let (Ok(i) | Err(i)) = inline_diagnostics
19030                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19031                        inline_diagnostics.insert(
19032                            i,
19033                            (
19034                                start_anchor,
19035                                InlineDiagnostic {
19036                                    message,
19037                                    group_id: diagnostic_entry.diagnostic.group_id,
19038                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19039                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19040                                    severity: diagnostic_entry.diagnostic.severity,
19041                                },
19042                            ),
19043                        );
19044                    }
19045                    inline_diagnostics
19046                })
19047                .await;
19048
19049            editor
19050                .update(cx, |editor, cx| {
19051                    editor.inline_diagnostics = new_inline_diagnostics;
19052                    cx.notify();
19053                })
19054                .ok();
19055        });
19056    }
19057
19058    fn pull_diagnostics(
19059        &mut self,
19060        buffer_id: Option<BufferId>,
19061        window: &Window,
19062        cx: &mut Context<Self>,
19063    ) -> Option<()> {
19064        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
19065            return None;
19066        }
19067        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19068            .diagnostics
19069            .lsp_pull_diagnostics;
19070        if !pull_diagnostics_settings.enabled {
19071            return None;
19072        }
19073        let project = self.project()?.downgrade();
19074
19075        let mut edited_buffer_ids = HashSet::default();
19076        let mut edited_worktree_ids = HashSet::default();
19077        let edited_buffers = match buffer_id {
19078            Some(buffer_id) => {
19079                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19080                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
19081                edited_buffer_ids.insert(buffer.read(cx).remote_id());
19082                edited_worktree_ids.insert(worktree_id);
19083                vec![buffer]
19084            }
19085            None => self
19086                .buffer()
19087                .read(cx)
19088                .all_buffers()
19089                .into_iter()
19090                .filter(|buffer| {
19091                    let buffer = buffer.read(cx);
19092                    match buffer.file().map(|f| f.worktree_id(cx)) {
19093                        Some(worktree_id) => {
19094                            edited_buffer_ids.insert(buffer.remote_id());
19095                            edited_worktree_ids.insert(worktree_id);
19096                            true
19097                        }
19098                        None => false,
19099                    }
19100                })
19101                .collect::<Vec<_>>(),
19102        };
19103
19104        if edited_buffers.is_empty() {
19105            self.pull_diagnostics_task = Task::ready(());
19106            self.pull_diagnostics_background_task = Task::ready(());
19107            return None;
19108        }
19109
19110        let mut already_used_buffers = HashSet::default();
19111        let related_open_buffers = self
19112            .workspace
19113            .as_ref()
19114            .and_then(|(workspace, _)| workspace.upgrade())
19115            .into_iter()
19116            .flat_map(|workspace| workspace.read(cx).panes())
19117            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
19118            .filter(|editor| editor != &cx.entity())
19119            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
19120            .filter(|buffer| {
19121                let buffer = buffer.read(cx);
19122                let buffer_id = buffer.remote_id();
19123                if already_used_buffers.insert(buffer_id) {
19124                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
19125                        return !edited_buffer_ids.contains(&buffer_id)
19126                            && edited_worktree_ids.contains(&worktree_id);
19127                    }
19128                }
19129                false
19130            })
19131            .collect::<Vec<_>>();
19132
19133        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19134        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
19135            if buffers.is_empty() {
19136                return Task::ready(());
19137            }
19138            let project_weak = project.clone();
19139            cx.spawn_in(window, async move |_, cx| {
19140                cx.background_executor().timer(delay).await;
19141
19142                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
19143                    buffers
19144                        .into_iter()
19145                        .filter_map(|buffer| {
19146                            project_weak
19147                                .update(cx, |project, cx| {
19148                                    project.lsp_store().update(cx, |lsp_store, cx| {
19149                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19150                                    })
19151                                })
19152                                .ok()
19153                        })
19154                        .collect::<FuturesUnordered<_>>()
19155                }) else {
19156                    return;
19157                };
19158
19159                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
19160                    if let Err(e) = pull_task {
19161                        log::error!("Failed to update project diagnostics: {e:#}");
19162                    }
19163                }
19164            })
19165        };
19166
19167        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
19168        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
19169
19170        Some(())
19171    }
19172
19173    pub fn set_selections_from_remote(
19174        &mut self,
19175        selections: Vec<Selection<Anchor>>,
19176        pending_selection: Option<Selection<Anchor>>,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        let old_cursor_position = self.selections.newest_anchor().head();
19181        self.selections
19182            .change_with(&self.display_snapshot(cx), |s| {
19183                s.select_anchors(selections);
19184                if let Some(pending_selection) = pending_selection {
19185                    s.set_pending(pending_selection, SelectMode::Character);
19186                } else {
19187                    s.clear_pending();
19188                }
19189            });
19190        self.selections_did_change(
19191            false,
19192            &old_cursor_position,
19193            SelectionEffects::default(),
19194            window,
19195            cx,
19196        );
19197    }
19198
19199    pub fn transact(
19200        &mut self,
19201        window: &mut Window,
19202        cx: &mut Context<Self>,
19203        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19204    ) -> Option<TransactionId> {
19205        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19206            this.start_transaction_at(Instant::now(), window, cx);
19207            update(this, window, cx);
19208            this.end_transaction_at(Instant::now(), cx)
19209        })
19210    }
19211
19212    pub fn start_transaction_at(
19213        &mut self,
19214        now: Instant,
19215        window: &mut Window,
19216        cx: &mut Context<Self>,
19217    ) -> Option<TransactionId> {
19218        self.end_selection(window, cx);
19219        if let Some(tx_id) = self
19220            .buffer
19221            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19222        {
19223            self.selection_history
19224                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19225            cx.emit(EditorEvent::TransactionBegun {
19226                transaction_id: tx_id,
19227            });
19228            Some(tx_id)
19229        } else {
19230            None
19231        }
19232    }
19233
19234    pub fn end_transaction_at(
19235        &mut self,
19236        now: Instant,
19237        cx: &mut Context<Self>,
19238    ) -> Option<TransactionId> {
19239        if let Some(transaction_id) = self
19240            .buffer
19241            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19242        {
19243            if let Some((_, end_selections)) =
19244                self.selection_history.transaction_mut(transaction_id)
19245            {
19246                *end_selections = Some(self.selections.disjoint_anchors_arc());
19247            } else {
19248                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19249            }
19250
19251            cx.emit(EditorEvent::Edited { transaction_id });
19252            Some(transaction_id)
19253        } else {
19254            None
19255        }
19256    }
19257
19258    pub fn modify_transaction_selection_history(
19259        &mut self,
19260        transaction_id: TransactionId,
19261        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19262    ) -> bool {
19263        self.selection_history
19264            .transaction_mut(transaction_id)
19265            .map(modify)
19266            .is_some()
19267    }
19268
19269    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19270        if self.selection_mark_mode {
19271            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19272                s.move_with(|_, sel| {
19273                    sel.collapse_to(sel.head(), SelectionGoal::None);
19274                });
19275            })
19276        }
19277        self.selection_mark_mode = true;
19278        cx.notify();
19279    }
19280
19281    pub fn swap_selection_ends(
19282        &mut self,
19283        _: &actions::SwapSelectionEnds,
19284        window: &mut Window,
19285        cx: &mut Context<Self>,
19286    ) {
19287        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19288            s.move_with(|_, sel| {
19289                if sel.start != sel.end {
19290                    sel.reversed = !sel.reversed
19291                }
19292            });
19293        });
19294        self.request_autoscroll(Autoscroll::newest(), cx);
19295        cx.notify();
19296    }
19297
19298    pub fn toggle_focus(
19299        workspace: &mut Workspace,
19300        _: &actions::ToggleFocus,
19301        window: &mut Window,
19302        cx: &mut Context<Workspace>,
19303    ) {
19304        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19305            return;
19306        };
19307        workspace.activate_item(&item, true, true, window, cx);
19308    }
19309
19310    pub fn toggle_fold(
19311        &mut self,
19312        _: &actions::ToggleFold,
19313        window: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) {
19316        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19317            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19318            let selection = self.selections.newest::<Point>(&display_map);
19319
19320            let range = if selection.is_empty() {
19321                let point = selection.head().to_display_point(&display_map);
19322                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19323                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19324                    .to_point(&display_map);
19325                start..end
19326            } else {
19327                selection.range()
19328            };
19329            if display_map.folds_in_range(range).next().is_some() {
19330                self.unfold_lines(&Default::default(), window, cx)
19331            } else {
19332                self.fold(&Default::default(), window, cx)
19333            }
19334        } else {
19335            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19336            let buffer_ids: HashSet<_> = self
19337                .selections
19338                .disjoint_anchor_ranges()
19339                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19340                .collect();
19341
19342            let should_unfold = buffer_ids
19343                .iter()
19344                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19345
19346            for buffer_id in buffer_ids {
19347                if should_unfold {
19348                    self.unfold_buffer(buffer_id, cx);
19349                } else {
19350                    self.fold_buffer(buffer_id, cx);
19351                }
19352            }
19353        }
19354    }
19355
19356    pub fn toggle_fold_recursive(
19357        &mut self,
19358        _: &actions::ToggleFoldRecursive,
19359        window: &mut Window,
19360        cx: &mut Context<Self>,
19361    ) {
19362        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19363
19364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19365        let range = if selection.is_empty() {
19366            let point = selection.head().to_display_point(&display_map);
19367            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19368            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19369                .to_point(&display_map);
19370            start..end
19371        } else {
19372            selection.range()
19373        };
19374        if display_map.folds_in_range(range).next().is_some() {
19375            self.unfold_recursive(&Default::default(), window, cx)
19376        } else {
19377            self.fold_recursive(&Default::default(), window, cx)
19378        }
19379    }
19380
19381    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19382        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19383            let mut to_fold = Vec::new();
19384            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19385            let selections = self.selections.all_adjusted(&display_map);
19386
19387            for selection in selections {
19388                let range = selection.range().sorted();
19389                let buffer_start_row = range.start.row;
19390
19391                if range.start.row != range.end.row {
19392                    let mut found = false;
19393                    let mut row = range.start.row;
19394                    while row <= range.end.row {
19395                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19396                        {
19397                            found = true;
19398                            row = crease.range().end.row + 1;
19399                            to_fold.push(crease);
19400                        } else {
19401                            row += 1
19402                        }
19403                    }
19404                    if found {
19405                        continue;
19406                    }
19407                }
19408
19409                for row in (0..=range.start.row).rev() {
19410                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19411                        && crease.range().end.row >= buffer_start_row
19412                    {
19413                        to_fold.push(crease);
19414                        if row <= range.start.row {
19415                            break;
19416                        }
19417                    }
19418                }
19419            }
19420
19421            self.fold_creases(to_fold, true, window, cx);
19422        } else {
19423            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19424            let buffer_ids = self
19425                .selections
19426                .disjoint_anchor_ranges()
19427                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19428                .collect::<HashSet<_>>();
19429            for buffer_id in buffer_ids {
19430                self.fold_buffer(buffer_id, cx);
19431            }
19432        }
19433    }
19434
19435    pub fn toggle_fold_all(
19436        &mut self,
19437        _: &actions::ToggleFoldAll,
19438        window: &mut Window,
19439        cx: &mut Context<Self>,
19440    ) {
19441        let has_folds = if self.buffer.read(cx).is_singleton() {
19442            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19443            let has_folds = display_map
19444                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19445                .next()
19446                .is_some();
19447            has_folds
19448        } else {
19449            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19450            let has_folds = buffer_ids
19451                .iter()
19452                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19453            has_folds
19454        };
19455
19456        if has_folds {
19457            self.unfold_all(&actions::UnfoldAll, window, cx);
19458        } else {
19459            self.fold_all(&actions::FoldAll, window, cx);
19460        }
19461    }
19462
19463    fn fold_at_level(
19464        &mut self,
19465        fold_at: &FoldAtLevel,
19466        window: &mut Window,
19467        cx: &mut Context<Self>,
19468    ) {
19469        if !self.buffer.read(cx).is_singleton() {
19470            return;
19471        }
19472
19473        let fold_at_level = fold_at.0;
19474        let snapshot = self.buffer.read(cx).snapshot(cx);
19475        let mut to_fold = Vec::new();
19476        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19477
19478        let row_ranges_to_keep: Vec<Range<u32>> = self
19479            .selections
19480            .all::<Point>(&self.display_snapshot(cx))
19481            .into_iter()
19482            .map(|sel| sel.start.row..sel.end.row)
19483            .collect();
19484
19485        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19486            while start_row < end_row {
19487                match self
19488                    .snapshot(window, cx)
19489                    .crease_for_buffer_row(MultiBufferRow(start_row))
19490                {
19491                    Some(crease) => {
19492                        let nested_start_row = crease.range().start.row + 1;
19493                        let nested_end_row = crease.range().end.row;
19494
19495                        if current_level < fold_at_level {
19496                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19497                        } else if current_level == fold_at_level {
19498                            // Fold iff there is no selection completely contained within the fold region
19499                            if !row_ranges_to_keep.iter().any(|selection| {
19500                                selection.end >= nested_start_row
19501                                    && selection.start <= nested_end_row
19502                            }) {
19503                                to_fold.push(crease);
19504                            }
19505                        }
19506
19507                        start_row = nested_end_row + 1;
19508                    }
19509                    None => start_row += 1,
19510                }
19511            }
19512        }
19513
19514        self.fold_creases(to_fold, true, window, cx);
19515    }
19516
19517    pub fn fold_at_level_1(
19518        &mut self,
19519        _: &actions::FoldAtLevel1,
19520        window: &mut Window,
19521        cx: &mut Context<Self>,
19522    ) {
19523        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19524    }
19525
19526    pub fn fold_at_level_2(
19527        &mut self,
19528        _: &actions::FoldAtLevel2,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19533    }
19534
19535    pub fn fold_at_level_3(
19536        &mut self,
19537        _: &actions::FoldAtLevel3,
19538        window: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19542    }
19543
19544    pub fn fold_at_level_4(
19545        &mut self,
19546        _: &actions::FoldAtLevel4,
19547        window: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19551    }
19552
19553    pub fn fold_at_level_5(
19554        &mut self,
19555        _: &actions::FoldAtLevel5,
19556        window: &mut Window,
19557        cx: &mut Context<Self>,
19558    ) {
19559        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19560    }
19561
19562    pub fn fold_at_level_6(
19563        &mut self,
19564        _: &actions::FoldAtLevel6,
19565        window: &mut Window,
19566        cx: &mut Context<Self>,
19567    ) {
19568        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19569    }
19570
19571    pub fn fold_at_level_7(
19572        &mut self,
19573        _: &actions::FoldAtLevel7,
19574        window: &mut Window,
19575        cx: &mut Context<Self>,
19576    ) {
19577        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19578    }
19579
19580    pub fn fold_at_level_8(
19581        &mut self,
19582        _: &actions::FoldAtLevel8,
19583        window: &mut Window,
19584        cx: &mut Context<Self>,
19585    ) {
19586        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19587    }
19588
19589    pub fn fold_at_level_9(
19590        &mut self,
19591        _: &actions::FoldAtLevel9,
19592        window: &mut Window,
19593        cx: &mut Context<Self>,
19594    ) {
19595        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19596    }
19597
19598    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19599        if self.buffer.read(cx).is_singleton() {
19600            let mut fold_ranges = Vec::new();
19601            let snapshot = self.buffer.read(cx).snapshot(cx);
19602
19603            for row in 0..snapshot.max_row().0 {
19604                if let Some(foldable_range) = self
19605                    .snapshot(window, cx)
19606                    .crease_for_buffer_row(MultiBufferRow(row))
19607                {
19608                    fold_ranges.push(foldable_range);
19609                }
19610            }
19611
19612            self.fold_creases(fold_ranges, true, window, cx);
19613        } else {
19614            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19615                editor
19616                    .update_in(cx, |editor, _, cx| {
19617                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19618                            editor.fold_buffer(buffer_id, cx);
19619                        }
19620                    })
19621                    .ok();
19622            });
19623        }
19624        cx.emit(SearchEvent::ResultsCollapsedChanged(
19625            CollapseDirection::Collapsed,
19626        ));
19627    }
19628
19629    pub fn fold_function_bodies(
19630        &mut self,
19631        _: &actions::FoldFunctionBodies,
19632        window: &mut Window,
19633        cx: &mut Context<Self>,
19634    ) {
19635        let snapshot = self.buffer.read(cx).snapshot(cx);
19636
19637        let ranges = snapshot
19638            .text_object_ranges(
19639                MultiBufferOffset(0)..snapshot.len(),
19640                TreeSitterOptions::default(),
19641            )
19642            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19643            .collect::<Vec<_>>();
19644
19645        let creases = ranges
19646            .into_iter()
19647            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19648            .collect();
19649
19650        self.fold_creases(creases, true, window, cx);
19651    }
19652
19653    pub fn fold_recursive(
19654        &mut self,
19655        _: &actions::FoldRecursive,
19656        window: &mut Window,
19657        cx: &mut Context<Self>,
19658    ) {
19659        let mut to_fold = Vec::new();
19660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19661        let selections = self.selections.all_adjusted(&display_map);
19662
19663        for selection in selections {
19664            let range = selection.range().sorted();
19665            let buffer_start_row = range.start.row;
19666
19667            if range.start.row != range.end.row {
19668                let mut found = false;
19669                for row in range.start.row..=range.end.row {
19670                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19671                        found = true;
19672                        to_fold.push(crease);
19673                    }
19674                }
19675                if found {
19676                    continue;
19677                }
19678            }
19679
19680            for row in (0..=range.start.row).rev() {
19681                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19682                    if crease.range().end.row >= buffer_start_row {
19683                        to_fold.push(crease);
19684                    } else {
19685                        break;
19686                    }
19687                }
19688            }
19689        }
19690
19691        self.fold_creases(to_fold, true, window, cx);
19692    }
19693
19694    pub fn fold_at(
19695        &mut self,
19696        buffer_row: MultiBufferRow,
19697        window: &mut Window,
19698        cx: &mut Context<Self>,
19699    ) {
19700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19701
19702        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19703            let autoscroll = self
19704                .selections
19705                .all::<Point>(&display_map)
19706                .iter()
19707                .any(|selection| crease.range().overlaps(&selection.range()));
19708
19709            self.fold_creases(vec![crease], autoscroll, window, cx);
19710        }
19711    }
19712
19713    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19714        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19715            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19716            let buffer = display_map.buffer_snapshot();
19717            let selections = self.selections.all::<Point>(&display_map);
19718            let ranges = selections
19719                .iter()
19720                .map(|s| {
19721                    let range = s.display_range(&display_map).sorted();
19722                    let mut start = range.start.to_point(&display_map);
19723                    let mut end = range.end.to_point(&display_map);
19724                    start.column = 0;
19725                    end.column = buffer.line_len(MultiBufferRow(end.row));
19726                    start..end
19727                })
19728                .collect::<Vec<_>>();
19729
19730            self.unfold_ranges(&ranges, true, true, cx);
19731        } else {
19732            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19733            let buffer_ids = self
19734                .selections
19735                .disjoint_anchor_ranges()
19736                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19737                .collect::<HashSet<_>>();
19738            for buffer_id in buffer_ids {
19739                self.unfold_buffer(buffer_id, cx);
19740            }
19741        }
19742    }
19743
19744    pub fn unfold_recursive(
19745        &mut self,
19746        _: &UnfoldRecursive,
19747        _window: &mut Window,
19748        cx: &mut Context<Self>,
19749    ) {
19750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19751        let selections = self.selections.all::<Point>(&display_map);
19752        let ranges = selections
19753            .iter()
19754            .map(|s| {
19755                let mut range = s.display_range(&display_map).sorted();
19756                *range.start.column_mut() = 0;
19757                *range.end.column_mut() = display_map.line_len(range.end.row());
19758                let start = range.start.to_point(&display_map);
19759                let end = range.end.to_point(&display_map);
19760                start..end
19761            })
19762            .collect::<Vec<_>>();
19763
19764        self.unfold_ranges(&ranges, true, true, cx);
19765    }
19766
19767    pub fn unfold_at(
19768        &mut self,
19769        buffer_row: MultiBufferRow,
19770        _window: &mut Window,
19771        cx: &mut Context<Self>,
19772    ) {
19773        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19774
19775        let intersection_range = Point::new(buffer_row.0, 0)
19776            ..Point::new(
19777                buffer_row.0,
19778                display_map.buffer_snapshot().line_len(buffer_row),
19779            );
19780
19781        let autoscroll = self
19782            .selections
19783            .all::<Point>(&display_map)
19784            .iter()
19785            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19786
19787        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19788    }
19789
19790    pub fn unfold_all(
19791        &mut self,
19792        _: &actions::UnfoldAll,
19793        _window: &mut Window,
19794        cx: &mut Context<Self>,
19795    ) {
19796        if self.buffer.read(cx).is_singleton() {
19797            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19798            self.unfold_ranges(
19799                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19800                true,
19801                true,
19802                cx,
19803            );
19804        } else {
19805            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19806                editor
19807                    .update(cx, |editor, cx| {
19808                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19809                            editor.unfold_buffer(buffer_id, cx);
19810                        }
19811                    })
19812                    .ok();
19813            });
19814        }
19815        cx.emit(SearchEvent::ResultsCollapsedChanged(
19816            CollapseDirection::Expanded,
19817        ));
19818    }
19819
19820    pub fn fold_selected_ranges(
19821        &mut self,
19822        _: &FoldSelectedRanges,
19823        window: &mut Window,
19824        cx: &mut Context<Self>,
19825    ) {
19826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19827        let selections = self.selections.all_adjusted(&display_map);
19828        let ranges = selections
19829            .into_iter()
19830            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19831            .collect::<Vec<_>>();
19832        self.fold_creases(ranges, true, window, cx);
19833    }
19834
19835    pub fn fold_ranges<T: ToOffset + Clone>(
19836        &mut self,
19837        ranges: Vec<Range<T>>,
19838        auto_scroll: bool,
19839        window: &mut Window,
19840        cx: &mut Context<Self>,
19841    ) {
19842        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19843        let ranges = ranges
19844            .into_iter()
19845            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19846            .collect::<Vec<_>>();
19847        self.fold_creases(ranges, auto_scroll, window, cx);
19848    }
19849
19850    pub fn fold_creases<T: ToOffset + Clone>(
19851        &mut self,
19852        creases: Vec<Crease<T>>,
19853        auto_scroll: bool,
19854        _window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        if creases.is_empty() {
19858            return;
19859        }
19860
19861        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19862
19863        if auto_scroll {
19864            self.request_autoscroll(Autoscroll::fit(), cx);
19865        }
19866
19867        cx.notify();
19868
19869        self.scrollbar_marker_state.dirty = true;
19870        self.folds_did_change(cx);
19871    }
19872
19873    /// Removes any folds whose ranges intersect any of the given ranges.
19874    pub fn unfold_ranges<T: ToOffset + Clone>(
19875        &mut self,
19876        ranges: &[Range<T>],
19877        inclusive: bool,
19878        auto_scroll: bool,
19879        cx: &mut Context<Self>,
19880    ) {
19881        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19882            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19883        });
19884        self.folds_did_change(cx);
19885    }
19886
19887    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19888        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19889            return;
19890        }
19891
19892        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19893        self.display_map.update(cx, |display_map, cx| {
19894            display_map.fold_buffers([buffer_id], cx)
19895        });
19896
19897        let snapshot = self.display_snapshot(cx);
19898        self.selections.change_with(&snapshot, |selections| {
19899            selections.remove_selections_from_buffer(buffer_id);
19900        });
19901
19902        cx.emit(EditorEvent::BufferFoldToggled {
19903            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19904            folded: true,
19905        });
19906        cx.notify();
19907    }
19908
19909    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19910        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19911            return;
19912        }
19913        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19914        self.display_map.update(cx, |display_map, cx| {
19915            display_map.unfold_buffers([buffer_id], cx);
19916        });
19917        cx.emit(EditorEvent::BufferFoldToggled {
19918            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19919            folded: false,
19920        });
19921        cx.notify();
19922    }
19923
19924    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19925        self.display_map.read(cx).is_buffer_folded(buffer)
19926    }
19927
19928    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19929        self.display_map.read(cx).folded_buffers()
19930    }
19931
19932    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19933        self.display_map.update(cx, |display_map, cx| {
19934            display_map.disable_header_for_buffer(buffer_id, cx);
19935        });
19936        cx.notify();
19937    }
19938
19939    /// Removes any folds with the given ranges.
19940    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19941        &mut self,
19942        ranges: &[Range<T>],
19943        type_id: TypeId,
19944        auto_scroll: bool,
19945        cx: &mut Context<Self>,
19946    ) {
19947        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19948            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19949        });
19950        self.folds_did_change(cx);
19951    }
19952
19953    fn remove_folds_with<T: ToOffset + Clone>(
19954        &mut self,
19955        ranges: &[Range<T>],
19956        auto_scroll: bool,
19957        cx: &mut Context<Self>,
19958        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19959    ) {
19960        if ranges.is_empty() {
19961            return;
19962        }
19963
19964        let mut buffers_affected = HashSet::default();
19965        let multi_buffer = self.buffer().read(cx);
19966        for range in ranges {
19967            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19968                buffers_affected.insert(buffer.read(cx).remote_id());
19969            };
19970        }
19971
19972        self.display_map.update(cx, update);
19973
19974        if auto_scroll {
19975            self.request_autoscroll(Autoscroll::fit(), cx);
19976        }
19977
19978        cx.notify();
19979        self.scrollbar_marker_state.dirty = true;
19980        self.active_indent_guides_state.dirty = true;
19981    }
19982
19983    pub fn update_renderer_widths(
19984        &mut self,
19985        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19986        cx: &mut Context<Self>,
19987    ) -> bool {
19988        self.display_map
19989            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19990    }
19991
19992    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19993        self.display_map.read(cx).fold_placeholder.clone()
19994    }
19995
19996    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19997        self.buffer.update(cx, |buffer, cx| {
19998            buffer.set_all_diff_hunks_expanded(cx);
19999        });
20000    }
20001
20002    pub fn expand_all_diff_hunks(
20003        &mut self,
20004        _: &ExpandAllDiffHunks,
20005        _window: &mut Window,
20006        cx: &mut Context<Self>,
20007    ) {
20008        self.buffer.update(cx, |buffer, cx| {
20009            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20010        });
20011    }
20012
20013    pub fn collapse_all_diff_hunks(
20014        &mut self,
20015        _: &CollapseAllDiffHunks,
20016        _window: &mut Window,
20017        cx: &mut Context<Self>,
20018    ) {
20019        self.buffer.update(cx, |buffer, cx| {
20020            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20021        });
20022    }
20023
20024    pub fn toggle_selected_diff_hunks(
20025        &mut self,
20026        _: &ToggleSelectedDiffHunks,
20027        _window: &mut Window,
20028        cx: &mut Context<Self>,
20029    ) {
20030        let ranges: Vec<_> = self
20031            .selections
20032            .disjoint_anchors()
20033            .iter()
20034            .map(|s| s.range())
20035            .collect();
20036        self.toggle_diff_hunks_in_ranges(ranges, cx);
20037    }
20038
20039    pub fn diff_hunks_in_ranges<'a>(
20040        &'a self,
20041        ranges: &'a [Range<Anchor>],
20042        buffer: &'a MultiBufferSnapshot,
20043    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20044        ranges.iter().flat_map(move |range| {
20045            let end_excerpt_id = range.end.excerpt_id;
20046            let range = range.to_point(buffer);
20047            let mut peek_end = range.end;
20048            if range.end.row < buffer.max_row().0 {
20049                peek_end = Point::new(range.end.row + 1, 0);
20050            }
20051            buffer
20052                .diff_hunks_in_range(range.start..peek_end)
20053                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20054        })
20055    }
20056
20057    pub fn has_stageable_diff_hunks_in_ranges(
20058        &self,
20059        ranges: &[Range<Anchor>],
20060        snapshot: &MultiBufferSnapshot,
20061    ) -> bool {
20062        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20063        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20064    }
20065
20066    pub fn toggle_staged_selected_diff_hunks(
20067        &mut self,
20068        _: &::git::ToggleStaged,
20069        _: &mut Window,
20070        cx: &mut Context<Self>,
20071    ) {
20072        let snapshot = self.buffer.read(cx).snapshot(cx);
20073        let ranges: Vec<_> = self
20074            .selections
20075            .disjoint_anchors()
20076            .iter()
20077            .map(|s| s.range())
20078            .collect();
20079        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20080        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20081    }
20082
20083    pub fn set_render_diff_hunk_controls(
20084        &mut self,
20085        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20086        cx: &mut Context<Self>,
20087    ) {
20088        self.render_diff_hunk_controls = render_diff_hunk_controls;
20089        cx.notify();
20090    }
20091
20092    pub fn stage_and_next(
20093        &mut self,
20094        _: &::git::StageAndNext,
20095        window: &mut Window,
20096        cx: &mut Context<Self>,
20097    ) {
20098        self.do_stage_or_unstage_and_next(true, window, cx);
20099    }
20100
20101    pub fn unstage_and_next(
20102        &mut self,
20103        _: &::git::UnstageAndNext,
20104        window: &mut Window,
20105        cx: &mut Context<Self>,
20106    ) {
20107        self.do_stage_or_unstage_and_next(false, window, cx);
20108    }
20109
20110    pub fn stage_or_unstage_diff_hunks(
20111        &mut self,
20112        stage: bool,
20113        ranges: Vec<Range<Anchor>>,
20114        cx: &mut Context<Self>,
20115    ) {
20116        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20117        cx.spawn(async move |this, cx| {
20118            task.await?;
20119            this.update(cx, |this, cx| {
20120                let snapshot = this.buffer.read(cx).snapshot(cx);
20121                let chunk_by = this
20122                    .diff_hunks_in_ranges(&ranges, &snapshot)
20123                    .chunk_by(|hunk| hunk.buffer_id);
20124                for (buffer_id, hunks) in &chunk_by {
20125                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20126                }
20127            })
20128        })
20129        .detach_and_log_err(cx);
20130    }
20131
20132    fn save_buffers_for_ranges_if_needed(
20133        &mut self,
20134        ranges: &[Range<Anchor>],
20135        cx: &mut Context<Editor>,
20136    ) -> Task<Result<()>> {
20137        let multibuffer = self.buffer.read(cx);
20138        let snapshot = multibuffer.read(cx);
20139        let buffer_ids: HashSet<_> = ranges
20140            .iter()
20141            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20142            .collect();
20143        drop(snapshot);
20144
20145        let mut buffers = HashSet::default();
20146        for buffer_id in buffer_ids {
20147            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20148                let buffer = buffer_entity.read(cx);
20149                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20150                {
20151                    buffers.insert(buffer_entity);
20152                }
20153            }
20154        }
20155
20156        if let Some(project) = &self.project {
20157            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20158        } else {
20159            Task::ready(Ok(()))
20160        }
20161    }
20162
20163    fn do_stage_or_unstage_and_next(
20164        &mut self,
20165        stage: bool,
20166        window: &mut Window,
20167        cx: &mut Context<Self>,
20168    ) {
20169        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20170
20171        if ranges.iter().any(|range| range.start != range.end) {
20172            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20173            return;
20174        }
20175
20176        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20177        let snapshot = self.snapshot(window, cx);
20178        let position = self
20179            .selections
20180            .newest::<Point>(&snapshot.display_snapshot)
20181            .head();
20182        let mut row = snapshot
20183            .buffer_snapshot()
20184            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20185            .find(|hunk| hunk.row_range.start.0 > position.row)
20186            .map(|hunk| hunk.row_range.start);
20187
20188        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20189        // Outside of the project diff editor, wrap around to the beginning.
20190        if !all_diff_hunks_expanded {
20191            row = row.or_else(|| {
20192                snapshot
20193                    .buffer_snapshot()
20194                    .diff_hunks_in_range(Point::zero()..position)
20195                    .find(|hunk| hunk.row_range.end.0 < position.row)
20196                    .map(|hunk| hunk.row_range.start)
20197            });
20198        }
20199
20200        if let Some(row) = row {
20201            let destination = Point::new(row.0, 0);
20202            let autoscroll = Autoscroll::center();
20203
20204            self.unfold_ranges(&[destination..destination], false, false, cx);
20205            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20206                s.select_ranges([destination..destination]);
20207            });
20208        }
20209    }
20210
20211    fn do_stage_or_unstage(
20212        &self,
20213        stage: bool,
20214        buffer_id: BufferId,
20215        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20216        cx: &mut App,
20217    ) -> Option<()> {
20218        let project = self.project()?;
20219        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20220        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20221        let buffer_snapshot = buffer.read(cx).snapshot();
20222        let file_exists = buffer_snapshot
20223            .file()
20224            .is_some_and(|file| file.disk_state().exists());
20225        diff.update(cx, |diff, cx| {
20226            diff.stage_or_unstage_hunks(
20227                stage,
20228                &hunks
20229                    .map(|hunk| buffer_diff::DiffHunk {
20230                        buffer_range: hunk.buffer_range,
20231                        // We don't need to pass in word diffs here because they're only used for rendering and
20232                        // this function changes internal state
20233                        base_word_diffs: Vec::default(),
20234                        buffer_word_diffs: Vec::default(),
20235                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20236                            ..hunk.diff_base_byte_range.end.0,
20237                        secondary_status: hunk.status.secondary,
20238                        range: Point::zero()..Point::zero(), // unused
20239                    })
20240                    .collect::<Vec<_>>(),
20241                &buffer_snapshot,
20242                file_exists,
20243                cx,
20244            )
20245        });
20246        None
20247    }
20248
20249    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20250        let ranges: Vec<_> = self
20251            .selections
20252            .disjoint_anchors()
20253            .iter()
20254            .map(|s| s.range())
20255            .collect();
20256        self.buffer
20257            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20258    }
20259
20260    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20261        self.buffer.update(cx, |buffer, cx| {
20262            let ranges = vec![Anchor::min()..Anchor::max()];
20263            if !buffer.all_diff_hunks_expanded()
20264                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20265            {
20266                buffer.collapse_diff_hunks(ranges, cx);
20267                true
20268            } else {
20269                false
20270            }
20271        })
20272    }
20273
20274    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20275        if self.buffer.read(cx).all_diff_hunks_expanded() {
20276            return true;
20277        }
20278        let ranges = vec![Anchor::min()..Anchor::max()];
20279        self.buffer
20280            .read(cx)
20281            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20282    }
20283
20284    fn toggle_diff_hunks_in_ranges(
20285        &mut self,
20286        ranges: Vec<Range<Anchor>>,
20287        cx: &mut Context<Editor>,
20288    ) {
20289        self.buffer.update(cx, |buffer, cx| {
20290            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20291            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20292        })
20293    }
20294
20295    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20296        self.buffer.update(cx, |buffer, cx| {
20297            let snapshot = buffer.snapshot(cx);
20298            let excerpt_id = range.end.excerpt_id;
20299            let point_range = range.to_point(&snapshot);
20300            let expand = !buffer.single_hunk_is_expanded(range, cx);
20301            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20302        })
20303    }
20304
20305    pub(crate) fn apply_all_diff_hunks(
20306        &mut self,
20307        _: &ApplyAllDiffHunks,
20308        window: &mut Window,
20309        cx: &mut Context<Self>,
20310    ) {
20311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20312
20313        let buffers = self.buffer.read(cx).all_buffers();
20314        for branch_buffer in buffers {
20315            branch_buffer.update(cx, |branch_buffer, cx| {
20316                branch_buffer.merge_into_base(Vec::new(), cx);
20317            });
20318        }
20319
20320        if let Some(project) = self.project.clone() {
20321            self.save(
20322                SaveOptions {
20323                    format: true,
20324                    autosave: false,
20325                },
20326                project,
20327                window,
20328                cx,
20329            )
20330            .detach_and_log_err(cx);
20331        }
20332    }
20333
20334    pub(crate) fn apply_selected_diff_hunks(
20335        &mut self,
20336        _: &ApplyDiffHunk,
20337        window: &mut Window,
20338        cx: &mut Context<Self>,
20339    ) {
20340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20341        let snapshot = self.snapshot(window, cx);
20342        let hunks = snapshot.hunks_for_ranges(
20343            self.selections
20344                .all(&snapshot.display_snapshot)
20345                .into_iter()
20346                .map(|selection| selection.range()),
20347        );
20348        let mut ranges_by_buffer = HashMap::default();
20349        self.transact(window, cx, |editor, _window, cx| {
20350            for hunk in hunks {
20351                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20352                    ranges_by_buffer
20353                        .entry(buffer.clone())
20354                        .or_insert_with(Vec::new)
20355                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20356                }
20357            }
20358
20359            for (buffer, ranges) in ranges_by_buffer {
20360                buffer.update(cx, |buffer, cx| {
20361                    buffer.merge_into_base(ranges, cx);
20362                });
20363            }
20364        });
20365
20366        if let Some(project) = self.project.clone() {
20367            self.save(
20368                SaveOptions {
20369                    format: true,
20370                    autosave: false,
20371                },
20372                project,
20373                window,
20374                cx,
20375            )
20376            .detach_and_log_err(cx);
20377        }
20378    }
20379
20380    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20381        if hovered != self.gutter_hovered {
20382            self.gutter_hovered = hovered;
20383            cx.notify();
20384        }
20385    }
20386
20387    pub fn insert_blocks(
20388        &mut self,
20389        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20390        autoscroll: Option<Autoscroll>,
20391        cx: &mut Context<Self>,
20392    ) -> Vec<CustomBlockId> {
20393        let blocks = self
20394            .display_map
20395            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20396        if let Some(autoscroll) = autoscroll {
20397            self.request_autoscroll(autoscroll, cx);
20398        }
20399        cx.notify();
20400        blocks
20401    }
20402
20403    pub fn resize_blocks(
20404        &mut self,
20405        heights: HashMap<CustomBlockId, u32>,
20406        autoscroll: Option<Autoscroll>,
20407        cx: &mut Context<Self>,
20408    ) {
20409        self.display_map
20410            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20411        if let Some(autoscroll) = autoscroll {
20412            self.request_autoscroll(autoscroll, cx);
20413        }
20414        cx.notify();
20415    }
20416
20417    pub fn replace_blocks(
20418        &mut self,
20419        renderers: HashMap<CustomBlockId, RenderBlock>,
20420        autoscroll: Option<Autoscroll>,
20421        cx: &mut Context<Self>,
20422    ) {
20423        self.display_map
20424            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20425        if let Some(autoscroll) = autoscroll {
20426            self.request_autoscroll(autoscroll, cx);
20427        }
20428        cx.notify();
20429    }
20430
20431    pub fn remove_blocks(
20432        &mut self,
20433        block_ids: HashSet<CustomBlockId>,
20434        autoscroll: Option<Autoscroll>,
20435        cx: &mut Context<Self>,
20436    ) {
20437        self.display_map.update(cx, |display_map, cx| {
20438            display_map.remove_blocks(block_ids, cx)
20439        });
20440        if let Some(autoscroll) = autoscroll {
20441            self.request_autoscroll(autoscroll, cx);
20442        }
20443        cx.notify();
20444    }
20445
20446    pub fn row_for_block(
20447        &self,
20448        block_id: CustomBlockId,
20449        cx: &mut Context<Self>,
20450    ) -> Option<DisplayRow> {
20451        self.display_map
20452            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20453    }
20454
20455    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20456        self.focused_block = Some(focused_block);
20457    }
20458
20459    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20460        self.focused_block.take()
20461    }
20462
20463    pub fn insert_creases(
20464        &mut self,
20465        creases: impl IntoIterator<Item = Crease<Anchor>>,
20466        cx: &mut Context<Self>,
20467    ) -> Vec<CreaseId> {
20468        self.display_map
20469            .update(cx, |map, cx| map.insert_creases(creases, cx))
20470    }
20471
20472    pub fn remove_creases(
20473        &mut self,
20474        ids: impl IntoIterator<Item = CreaseId>,
20475        cx: &mut Context<Self>,
20476    ) -> Vec<(CreaseId, Range<Anchor>)> {
20477        self.display_map
20478            .update(cx, |map, cx| map.remove_creases(ids, cx))
20479    }
20480
20481    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20482        self.display_map
20483            .update(cx, |map, cx| map.snapshot(cx))
20484            .longest_row()
20485    }
20486
20487    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20488        self.display_map
20489            .update(cx, |map, cx| map.snapshot(cx))
20490            .max_point()
20491    }
20492
20493    pub fn text(&self, cx: &App) -> String {
20494        self.buffer.read(cx).read(cx).text()
20495    }
20496
20497    pub fn is_empty(&self, cx: &App) -> bool {
20498        self.buffer.read(cx).read(cx).is_empty()
20499    }
20500
20501    pub fn text_option(&self, cx: &App) -> Option<String> {
20502        let text = self.text(cx);
20503        let text = text.trim();
20504
20505        if text.is_empty() {
20506            return None;
20507        }
20508
20509        Some(text.to_string())
20510    }
20511
20512    pub fn set_text(
20513        &mut self,
20514        text: impl Into<Arc<str>>,
20515        window: &mut Window,
20516        cx: &mut Context<Self>,
20517    ) {
20518        self.transact(window, cx, |this, _, cx| {
20519            this.buffer
20520                .read(cx)
20521                .as_singleton()
20522                .expect("you can only call set_text on editors for singleton buffers")
20523                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20524        });
20525    }
20526
20527    pub fn display_text(&self, cx: &mut App) -> String {
20528        self.display_map
20529            .update(cx, |map, cx| map.snapshot(cx))
20530            .text()
20531    }
20532
20533    fn create_minimap(
20534        &self,
20535        minimap_settings: MinimapSettings,
20536        window: &mut Window,
20537        cx: &mut Context<Self>,
20538    ) -> Option<Entity<Self>> {
20539        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20540            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20541    }
20542
20543    fn initialize_new_minimap(
20544        &self,
20545        minimap_settings: MinimapSettings,
20546        window: &mut Window,
20547        cx: &mut Context<Self>,
20548    ) -> Entity<Self> {
20549        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20550        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20551
20552        let mut minimap = Editor::new_internal(
20553            EditorMode::Minimap {
20554                parent: cx.weak_entity(),
20555            },
20556            self.buffer.clone(),
20557            None,
20558            Some(self.display_map.clone()),
20559            window,
20560            cx,
20561        );
20562        minimap.scroll_manager.clone_state(&self.scroll_manager);
20563        minimap.set_text_style_refinement(TextStyleRefinement {
20564            font_size: Some(MINIMAP_FONT_SIZE),
20565            font_weight: Some(MINIMAP_FONT_WEIGHT),
20566            font_family: Some(MINIMAP_FONT_FAMILY),
20567            ..Default::default()
20568        });
20569        minimap.update_minimap_configuration(minimap_settings, cx);
20570        cx.new(|_| minimap)
20571    }
20572
20573    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20574        let current_line_highlight = minimap_settings
20575            .current_line_highlight
20576            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20577        self.set_current_line_highlight(Some(current_line_highlight));
20578    }
20579
20580    pub fn minimap(&self) -> Option<&Entity<Self>> {
20581        self.minimap
20582            .as_ref()
20583            .filter(|_| self.minimap_visibility.visible())
20584    }
20585
20586    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20587        let mut wrap_guides = smallvec![];
20588
20589        if self.show_wrap_guides == Some(false) {
20590            return wrap_guides;
20591        }
20592
20593        let settings = self.buffer.read(cx).language_settings(cx);
20594        if settings.show_wrap_guides {
20595            match self.soft_wrap_mode(cx) {
20596                SoftWrap::Column(soft_wrap) => {
20597                    wrap_guides.push((soft_wrap as usize, true));
20598                }
20599                SoftWrap::Bounded(soft_wrap) => {
20600                    wrap_guides.push((soft_wrap as usize, true));
20601                }
20602                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20603            }
20604            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20605        }
20606
20607        wrap_guides
20608    }
20609
20610    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20611        let settings = self.buffer.read(cx).language_settings(cx);
20612        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20613        match mode {
20614            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20615                SoftWrap::None
20616            }
20617            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20618            language_settings::SoftWrap::PreferredLineLength => {
20619                SoftWrap::Column(settings.preferred_line_length)
20620            }
20621            language_settings::SoftWrap::Bounded => {
20622                SoftWrap::Bounded(settings.preferred_line_length)
20623            }
20624        }
20625    }
20626
20627    pub fn set_soft_wrap_mode(
20628        &mut self,
20629        mode: language_settings::SoftWrap,
20630
20631        cx: &mut Context<Self>,
20632    ) {
20633        self.soft_wrap_mode_override = Some(mode);
20634        cx.notify();
20635    }
20636
20637    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20638        self.hard_wrap = hard_wrap;
20639        cx.notify();
20640    }
20641
20642    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20643        self.text_style_refinement = Some(style);
20644    }
20645
20646    /// called by the Element so we know what style we were most recently rendered with.
20647    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20648        // We intentionally do not inform the display map about the minimap style
20649        // so that wrapping is not recalculated and stays consistent for the editor
20650        // and its linked minimap.
20651        if !self.mode.is_minimap() {
20652            let font = style.text.font();
20653            let font_size = style.text.font_size.to_pixels(window.rem_size());
20654            let display_map = self
20655                .placeholder_display_map
20656                .as_ref()
20657                .filter(|_| self.is_empty(cx))
20658                .unwrap_or(&self.display_map);
20659
20660            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20661        }
20662        self.style = Some(style);
20663    }
20664
20665    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20666        if self.style.is_none() {
20667            self.style = Some(self.create_style(cx));
20668        }
20669        self.style.as_ref().unwrap()
20670    }
20671
20672    // Called by the element. This method is not designed to be called outside of the editor
20673    // element's layout code because it does not notify when rewrapping is computed synchronously.
20674    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20675        if self.is_empty(cx) {
20676            self.placeholder_display_map
20677                .as_ref()
20678                .map_or(false, |display_map| {
20679                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20680                })
20681        } else {
20682            self.display_map
20683                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20684        }
20685    }
20686
20687    pub fn set_soft_wrap(&mut self) {
20688        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20689    }
20690
20691    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20692        if self.soft_wrap_mode_override.is_some() {
20693            self.soft_wrap_mode_override.take();
20694        } else {
20695            let soft_wrap = match self.soft_wrap_mode(cx) {
20696                SoftWrap::GitDiff => return,
20697                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20698                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20699                    language_settings::SoftWrap::None
20700                }
20701            };
20702            self.soft_wrap_mode_override = Some(soft_wrap);
20703        }
20704        cx.notify();
20705    }
20706
20707    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20708        let Some(workspace) = self.workspace() else {
20709            return;
20710        };
20711        let fs = workspace.read(cx).app_state().fs.clone();
20712        let current_show = TabBarSettings::get_global(cx).show;
20713        update_settings_file(fs, cx, move |setting, _| {
20714            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20715        });
20716    }
20717
20718    pub fn toggle_indent_guides(
20719        &mut self,
20720        _: &ToggleIndentGuides,
20721        _: &mut Window,
20722        cx: &mut Context<Self>,
20723    ) {
20724        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20725            self.buffer
20726                .read(cx)
20727                .language_settings(cx)
20728                .indent_guides
20729                .enabled
20730        });
20731        self.show_indent_guides = Some(!currently_enabled);
20732        cx.notify();
20733    }
20734
20735    fn should_show_indent_guides(&self) -> Option<bool> {
20736        self.show_indent_guides
20737    }
20738
20739    pub fn disable_indent_guides_for_buffer(
20740        &mut self,
20741        buffer_id: BufferId,
20742        cx: &mut Context<Self>,
20743    ) {
20744        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20745        cx.notify();
20746    }
20747
20748    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20749        self.buffers_with_disabled_indent_guides
20750            .contains(&buffer_id)
20751    }
20752
20753    pub fn toggle_line_numbers(
20754        &mut self,
20755        _: &ToggleLineNumbers,
20756        _: &mut Window,
20757        cx: &mut Context<Self>,
20758    ) {
20759        let mut editor_settings = EditorSettings::get_global(cx).clone();
20760        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20761        EditorSettings::override_global(editor_settings, cx);
20762    }
20763
20764    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20765        if let Some(show_line_numbers) = self.show_line_numbers {
20766            return show_line_numbers;
20767        }
20768        EditorSettings::get_global(cx).gutter.line_numbers
20769    }
20770
20771    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20772        match (
20773            self.use_relative_line_numbers,
20774            EditorSettings::get_global(cx).relative_line_numbers,
20775        ) {
20776            (None, setting) => setting,
20777            (Some(false), _) => RelativeLineNumbers::Disabled,
20778            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20779            (Some(true), _) => RelativeLineNumbers::Enabled,
20780        }
20781    }
20782
20783    pub fn toggle_relative_line_numbers(
20784        &mut self,
20785        _: &ToggleRelativeLineNumbers,
20786        _: &mut Window,
20787        cx: &mut Context<Self>,
20788    ) {
20789        let is_relative = self.relative_line_numbers(cx);
20790        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20791    }
20792
20793    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20794        self.use_relative_line_numbers = is_relative;
20795        cx.notify();
20796    }
20797
20798    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20799        self.show_gutter = show_gutter;
20800        cx.notify();
20801    }
20802
20803    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20804        self.show_scrollbars = ScrollbarAxes {
20805            horizontal: show,
20806            vertical: show,
20807        };
20808        cx.notify();
20809    }
20810
20811    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20812        self.show_scrollbars.vertical = show;
20813        cx.notify();
20814    }
20815
20816    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20817        self.show_scrollbars.horizontal = show;
20818        cx.notify();
20819    }
20820
20821    pub fn set_minimap_visibility(
20822        &mut self,
20823        minimap_visibility: MinimapVisibility,
20824        window: &mut Window,
20825        cx: &mut Context<Self>,
20826    ) {
20827        if self.minimap_visibility != minimap_visibility {
20828            if minimap_visibility.visible() && self.minimap.is_none() {
20829                let minimap_settings = EditorSettings::get_global(cx).minimap;
20830                self.minimap =
20831                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20832            }
20833            self.minimap_visibility = minimap_visibility;
20834            cx.notify();
20835        }
20836    }
20837
20838    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20839        self.set_show_scrollbars(false, cx);
20840        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20841    }
20842
20843    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20844        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20845    }
20846
20847    /// Normally the text in full mode and auto height editors is padded on the
20848    /// left side by roughly half a character width for improved hit testing.
20849    ///
20850    /// Use this method to disable this for cases where this is not wanted (e.g.
20851    /// if you want to align the editor text with some other text above or below)
20852    /// or if you want to add this padding to single-line editors.
20853    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20854        self.offset_content = offset_content;
20855        cx.notify();
20856    }
20857
20858    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20859        self.show_line_numbers = Some(show_line_numbers);
20860        cx.notify();
20861    }
20862
20863    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20864        self.disable_expand_excerpt_buttons = true;
20865        cx.notify();
20866    }
20867
20868    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20869        self.delegate_expand_excerpts = delegate;
20870    }
20871
20872    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20873        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20874        cx.notify();
20875    }
20876
20877    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20878        self.show_code_actions = Some(show_code_actions);
20879        cx.notify();
20880    }
20881
20882    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20883        self.show_runnables = Some(show_runnables);
20884        cx.notify();
20885    }
20886
20887    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20888        self.show_breakpoints = Some(show_breakpoints);
20889        cx.notify();
20890    }
20891
20892    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
20893        self.show_diff_review_button = show;
20894        cx.notify();
20895    }
20896
20897    pub fn show_diff_review_button(&self) -> bool {
20898        self.show_diff_review_button
20899    }
20900
20901    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20902        if self.display_map.read(cx).masked != masked {
20903            self.display_map.update(cx, |map, _| map.masked = masked);
20904        }
20905        cx.notify()
20906    }
20907
20908    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20909        self.show_wrap_guides = Some(show_wrap_guides);
20910        cx.notify();
20911    }
20912
20913    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20914        self.show_indent_guides = Some(show_indent_guides);
20915        cx.notify();
20916    }
20917
20918    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20919        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20920            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20921                && let Some(dir) = file.abs_path(cx).parent()
20922            {
20923                return Some(dir.to_owned());
20924            }
20925        }
20926
20927        None
20928    }
20929
20930    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20931        self.active_excerpt(cx)?
20932            .1
20933            .read(cx)
20934            .file()
20935            .and_then(|f| f.as_local())
20936    }
20937
20938    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20939        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20940            let buffer = buffer.read(cx);
20941            if let Some(project_path) = buffer.project_path(cx) {
20942                let project = self.project()?.read(cx);
20943                project.absolute_path(&project_path, cx)
20944            } else {
20945                buffer
20946                    .file()
20947                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20948            }
20949        })
20950    }
20951
20952    pub fn reveal_in_finder(
20953        &mut self,
20954        _: &RevealInFileManager,
20955        _window: &mut Window,
20956        cx: &mut Context<Self>,
20957    ) {
20958        if let Some(target) = self.target_file(cx) {
20959            cx.reveal_path(&target.abs_path(cx));
20960        }
20961    }
20962
20963    pub fn copy_path(
20964        &mut self,
20965        _: &zed_actions::workspace::CopyPath,
20966        _window: &mut Window,
20967        cx: &mut Context<Self>,
20968    ) {
20969        if let Some(path) = self.target_file_abs_path(cx)
20970            && let Some(path) = path.to_str()
20971        {
20972            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20973        } else {
20974            cx.propagate();
20975        }
20976    }
20977
20978    pub fn copy_relative_path(
20979        &mut self,
20980        _: &zed_actions::workspace::CopyRelativePath,
20981        _window: &mut Window,
20982        cx: &mut Context<Self>,
20983    ) {
20984        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20985            let project = self.project()?.read(cx);
20986            let path = buffer.read(cx).file()?.path();
20987            let path = path.display(project.path_style(cx));
20988            Some(path)
20989        }) {
20990            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20991        } else {
20992            cx.propagate();
20993        }
20994    }
20995
20996    /// Returns the project path for the editor's buffer, if any buffer is
20997    /// opened in the editor.
20998    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20999        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
21000            buffer.read(cx).project_path(cx)
21001        } else {
21002            None
21003        }
21004    }
21005
21006    // Returns true if the editor handled a go-to-line request
21007    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
21008        maybe!({
21009            let breakpoint_store = self.breakpoint_store.as_ref()?;
21010
21011            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
21012            else {
21013                self.clear_row_highlights::<ActiveDebugLine>();
21014                return None;
21015            };
21016
21017            let position = active_stack_frame.position;
21018            let buffer_id = position.buffer_id?;
21019            let snapshot = self
21020                .project
21021                .as_ref()?
21022                .read(cx)
21023                .buffer_for_id(buffer_id, cx)?
21024                .read(cx)
21025                .snapshot();
21026
21027            let mut handled = false;
21028            for (id, ExcerptRange { context, .. }) in
21029                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
21030            {
21031                if context.start.cmp(&position, &snapshot).is_ge()
21032                    || context.end.cmp(&position, &snapshot).is_lt()
21033                {
21034                    continue;
21035                }
21036                let snapshot = self.buffer.read(cx).snapshot(cx);
21037                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
21038
21039                handled = true;
21040                self.clear_row_highlights::<ActiveDebugLine>();
21041
21042                self.go_to_line::<ActiveDebugLine>(
21043                    multibuffer_anchor,
21044                    Some(cx.theme().colors().editor_debugger_active_line_background),
21045                    window,
21046                    cx,
21047                );
21048
21049                cx.notify();
21050            }
21051
21052            handled.then_some(())
21053        })
21054        .is_some()
21055    }
21056
21057    pub fn copy_file_name_without_extension(
21058        &mut self,
21059        _: &CopyFileNameWithoutExtension,
21060        _: &mut Window,
21061        cx: &mut Context<Self>,
21062    ) {
21063        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21064            let file = buffer.read(cx).file()?;
21065            file.path().file_stem()
21066        }) {
21067            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
21068        }
21069    }
21070
21071    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
21072        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21073            let file = buffer.read(cx).file()?;
21074            Some(file.file_name(cx))
21075        }) {
21076            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
21077        }
21078    }
21079
21080    pub fn toggle_git_blame(
21081        &mut self,
21082        _: &::git::Blame,
21083        window: &mut Window,
21084        cx: &mut Context<Self>,
21085    ) {
21086        self.show_git_blame_gutter = !self.show_git_blame_gutter;
21087
21088        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
21089            self.start_git_blame(true, window, cx);
21090        }
21091
21092        cx.notify();
21093    }
21094
21095    pub fn toggle_git_blame_inline(
21096        &mut self,
21097        _: &ToggleGitBlameInline,
21098        window: &mut Window,
21099        cx: &mut Context<Self>,
21100    ) {
21101        self.toggle_git_blame_inline_internal(true, window, cx);
21102        cx.notify();
21103    }
21104
21105    pub fn open_git_blame_commit(
21106        &mut self,
21107        _: &OpenGitBlameCommit,
21108        window: &mut Window,
21109        cx: &mut Context<Self>,
21110    ) {
21111        self.open_git_blame_commit_internal(window, cx);
21112    }
21113
21114    fn open_git_blame_commit_internal(
21115        &mut self,
21116        window: &mut Window,
21117        cx: &mut Context<Self>,
21118    ) -> Option<()> {
21119        let blame = self.blame.as_ref()?;
21120        let snapshot = self.snapshot(window, cx);
21121        let cursor = self
21122            .selections
21123            .newest::<Point>(&snapshot.display_snapshot)
21124            .head();
21125        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
21126        let (_, blame_entry) = blame
21127            .update(cx, |blame, cx| {
21128                blame
21129                    .blame_for_rows(
21130                        &[RowInfo {
21131                            buffer_id: Some(buffer.remote_id()),
21132                            buffer_row: Some(point.row),
21133                            ..Default::default()
21134                        }],
21135                        cx,
21136                    )
21137                    .next()
21138            })
21139            .flatten()?;
21140        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21141        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
21142        let workspace = self.workspace()?.downgrade();
21143        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
21144        None
21145    }
21146
21147    pub fn git_blame_inline_enabled(&self) -> bool {
21148        self.git_blame_inline_enabled
21149    }
21150
21151    pub fn toggle_selection_menu(
21152        &mut self,
21153        _: &ToggleSelectionMenu,
21154        _: &mut Window,
21155        cx: &mut Context<Self>,
21156    ) {
21157        self.show_selection_menu = self
21158            .show_selection_menu
21159            .map(|show_selections_menu| !show_selections_menu)
21160            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
21161
21162        cx.notify();
21163    }
21164
21165    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
21166        self.show_selection_menu
21167            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
21168    }
21169
21170    fn start_git_blame(
21171        &mut self,
21172        user_triggered: bool,
21173        window: &mut Window,
21174        cx: &mut Context<Self>,
21175    ) {
21176        if let Some(project) = self.project() {
21177            if let Some(buffer) = self.buffer().read(cx).as_singleton()
21178                && buffer.read(cx).file().is_none()
21179            {
21180                return;
21181            }
21182
21183            let focused = self.focus_handle(cx).contains_focused(window, cx);
21184
21185            let project = project.clone();
21186            let blame = cx
21187                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
21188            self.blame_subscription =
21189                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
21190            self.blame = Some(blame);
21191        }
21192    }
21193
21194    fn toggle_git_blame_inline_internal(
21195        &mut self,
21196        user_triggered: bool,
21197        window: &mut Window,
21198        cx: &mut Context<Self>,
21199    ) {
21200        if self.git_blame_inline_enabled {
21201            self.git_blame_inline_enabled = false;
21202            self.show_git_blame_inline = false;
21203            self.show_git_blame_inline_delay_task.take();
21204        } else {
21205            self.git_blame_inline_enabled = true;
21206            self.start_git_blame_inline(user_triggered, window, cx);
21207        }
21208
21209        cx.notify();
21210    }
21211
21212    fn start_git_blame_inline(
21213        &mut self,
21214        user_triggered: bool,
21215        window: &mut Window,
21216        cx: &mut Context<Self>,
21217    ) {
21218        self.start_git_blame(user_triggered, window, cx);
21219
21220        if ProjectSettings::get_global(cx)
21221            .git
21222            .inline_blame_delay()
21223            .is_some()
21224        {
21225            self.start_inline_blame_timer(window, cx);
21226        } else {
21227            self.show_git_blame_inline = true
21228        }
21229    }
21230
21231    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21232        self.blame.as_ref()
21233    }
21234
21235    pub fn show_git_blame_gutter(&self) -> bool {
21236        self.show_git_blame_gutter
21237    }
21238
21239    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21240        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21241    }
21242
21243    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21244        self.show_git_blame_inline
21245            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21246            && !self.newest_selection_head_on_empty_line(cx)
21247            && self.has_blame_entries(cx)
21248    }
21249
21250    fn has_blame_entries(&self, cx: &App) -> bool {
21251        self.blame()
21252            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21253    }
21254
21255    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21256        let cursor_anchor = self.selections.newest_anchor().head();
21257
21258        let snapshot = self.buffer.read(cx).snapshot(cx);
21259        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21260
21261        snapshot.line_len(buffer_row) == 0
21262    }
21263
21264    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21265        let buffer_and_selection = maybe!({
21266            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21267            let selection_range = selection.range();
21268
21269            let multi_buffer = self.buffer().read(cx);
21270            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21271            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21272
21273            let (buffer, range, _) = if selection.reversed {
21274                buffer_ranges.first()
21275            } else {
21276                buffer_ranges.last()
21277            }?;
21278
21279            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21280            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21281
21282            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21283                let selection = start_row_in_buffer..end_row_in_buffer;
21284
21285                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21286            };
21287
21288            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21289
21290            Some((
21291                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21292                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21293                    ..buffer_diff_snapshot.row_to_base_text_row(
21294                        end_row_in_buffer,
21295                        Bias::Left,
21296                        buffer,
21297                    ),
21298            ))
21299        });
21300
21301        let Some((buffer, selection)) = buffer_and_selection else {
21302            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21303        };
21304
21305        let Some(project) = self.project() else {
21306            return Task::ready(Err(anyhow!("editor does not have project")));
21307        };
21308
21309        project.update(cx, |project, cx| {
21310            project.get_permalink_to_line(&buffer, selection, cx)
21311        })
21312    }
21313
21314    pub fn copy_permalink_to_line(
21315        &mut self,
21316        _: &CopyPermalinkToLine,
21317        window: &mut Window,
21318        cx: &mut Context<Self>,
21319    ) {
21320        let permalink_task = self.get_permalink_to_line(cx);
21321        let workspace = self.workspace();
21322
21323        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21324            Ok(permalink) => {
21325                cx.update(|_, cx| {
21326                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21327                })
21328                .ok();
21329            }
21330            Err(err) => {
21331                let message = format!("Failed to copy permalink: {err}");
21332
21333                anyhow::Result::<()>::Err(err).log_err();
21334
21335                if let Some(workspace) = workspace {
21336                    workspace
21337                        .update_in(cx, |workspace, _, cx| {
21338                            struct CopyPermalinkToLine;
21339
21340                            workspace.show_toast(
21341                                Toast::new(
21342                                    NotificationId::unique::<CopyPermalinkToLine>(),
21343                                    message,
21344                                ),
21345                                cx,
21346                            )
21347                        })
21348                        .ok();
21349                }
21350            }
21351        })
21352        .detach();
21353    }
21354
21355    pub fn copy_file_location(
21356        &mut self,
21357        _: &CopyFileLocation,
21358        _: &mut Window,
21359        cx: &mut Context<Self>,
21360    ) {
21361        let selection = self
21362            .selections
21363            .newest::<Point>(&self.display_snapshot(cx))
21364            .start
21365            .row
21366            + 1;
21367        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21368            let project = self.project()?.read(cx);
21369            let file = buffer.read(cx).file()?;
21370            let path = file.path().display(project.path_style(cx));
21371
21372            Some(format!("{path}:{selection}"))
21373        }) {
21374            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21375        }
21376    }
21377
21378    pub fn open_permalink_to_line(
21379        &mut self,
21380        _: &OpenPermalinkToLine,
21381        window: &mut Window,
21382        cx: &mut Context<Self>,
21383    ) {
21384        let permalink_task = self.get_permalink_to_line(cx);
21385        let workspace = self.workspace();
21386
21387        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21388            Ok(permalink) => {
21389                cx.update(|_, cx| {
21390                    cx.open_url(permalink.as_ref());
21391                })
21392                .ok();
21393            }
21394            Err(err) => {
21395                let message = format!("Failed to open permalink: {err}");
21396
21397                anyhow::Result::<()>::Err(err).log_err();
21398
21399                if let Some(workspace) = workspace {
21400                    workspace.update(cx, |workspace, cx| {
21401                        struct OpenPermalinkToLine;
21402
21403                        workspace.show_toast(
21404                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
21405                            cx,
21406                        )
21407                    });
21408                }
21409            }
21410        })
21411        .detach();
21412    }
21413
21414    pub fn insert_uuid_v4(
21415        &mut self,
21416        _: &InsertUuidV4,
21417        window: &mut Window,
21418        cx: &mut Context<Self>,
21419    ) {
21420        self.insert_uuid(UuidVersion::V4, window, cx);
21421    }
21422
21423    pub fn insert_uuid_v7(
21424        &mut self,
21425        _: &InsertUuidV7,
21426        window: &mut Window,
21427        cx: &mut Context<Self>,
21428    ) {
21429        self.insert_uuid(UuidVersion::V7, window, cx);
21430    }
21431
21432    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21434        self.transact(window, cx, |this, window, cx| {
21435            let edits = this
21436                .selections
21437                .all::<Point>(&this.display_snapshot(cx))
21438                .into_iter()
21439                .map(|selection| {
21440                    let uuid = match version {
21441                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21442                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21443                    };
21444
21445                    (selection.range(), uuid.to_string())
21446                });
21447            this.edit(edits, cx);
21448            this.refresh_edit_prediction(true, false, window, cx);
21449        });
21450    }
21451
21452    pub fn open_selections_in_multibuffer(
21453        &mut self,
21454        _: &OpenSelectionsInMultibuffer,
21455        window: &mut Window,
21456        cx: &mut Context<Self>,
21457    ) {
21458        let multibuffer = self.buffer.read(cx);
21459
21460        let Some(buffer) = multibuffer.as_singleton() else {
21461            return;
21462        };
21463
21464        let Some(workspace) = self.workspace() else {
21465            return;
21466        };
21467
21468        let title = multibuffer.title(cx).to_string();
21469
21470        let locations = self
21471            .selections
21472            .all_anchors(&self.display_snapshot(cx))
21473            .iter()
21474            .map(|selection| {
21475                (
21476                    buffer.clone(),
21477                    (selection.start.text_anchor..selection.end.text_anchor)
21478                        .to_point(buffer.read(cx)),
21479                )
21480            })
21481            .into_group_map();
21482
21483        cx.spawn_in(window, async move |_, cx| {
21484            workspace.update_in(cx, |workspace, window, cx| {
21485                Self::open_locations_in_multibuffer(
21486                    workspace,
21487                    locations,
21488                    format!("Selections for '{title}'"),
21489                    false,
21490                    false,
21491                    MultibufferSelectionMode::All,
21492                    window,
21493                    cx,
21494                );
21495            })
21496        })
21497        .detach();
21498    }
21499
21500    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21501    /// last highlight added will be used.
21502    ///
21503    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21504    pub fn highlight_rows<T: 'static>(
21505        &mut self,
21506        range: Range<Anchor>,
21507        color: Hsla,
21508        options: RowHighlightOptions,
21509        cx: &mut Context<Self>,
21510    ) {
21511        let snapshot = self.buffer().read(cx).snapshot(cx);
21512        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21513        let ix = row_highlights.binary_search_by(|highlight| {
21514            Ordering::Equal
21515                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21516                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21517        });
21518
21519        if let Err(mut ix) = ix {
21520            let index = post_inc(&mut self.highlight_order);
21521
21522            // If this range intersects with the preceding highlight, then merge it with
21523            // the preceding highlight. Otherwise insert a new highlight.
21524            let mut merged = false;
21525            if ix > 0 {
21526                let prev_highlight = &mut row_highlights[ix - 1];
21527                if prev_highlight
21528                    .range
21529                    .end
21530                    .cmp(&range.start, &snapshot)
21531                    .is_ge()
21532                {
21533                    ix -= 1;
21534                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21535                        prev_highlight.range.end = range.end;
21536                    }
21537                    merged = true;
21538                    prev_highlight.index = index;
21539                    prev_highlight.color = color;
21540                    prev_highlight.options = options;
21541                }
21542            }
21543
21544            if !merged {
21545                row_highlights.insert(
21546                    ix,
21547                    RowHighlight {
21548                        range,
21549                        index,
21550                        color,
21551                        options,
21552                        type_id: TypeId::of::<T>(),
21553                    },
21554                );
21555            }
21556
21557            // If any of the following highlights intersect with this one, merge them.
21558            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21559                let highlight = &row_highlights[ix];
21560                if next_highlight
21561                    .range
21562                    .start
21563                    .cmp(&highlight.range.end, &snapshot)
21564                    .is_le()
21565                {
21566                    if next_highlight
21567                        .range
21568                        .end
21569                        .cmp(&highlight.range.end, &snapshot)
21570                        .is_gt()
21571                    {
21572                        row_highlights[ix].range.end = next_highlight.range.end;
21573                    }
21574                    row_highlights.remove(ix + 1);
21575                } else {
21576                    break;
21577                }
21578            }
21579        }
21580    }
21581
21582    /// Remove any highlighted row ranges of the given type that intersect the
21583    /// given ranges.
21584    pub fn remove_highlighted_rows<T: 'static>(
21585        &mut self,
21586        ranges_to_remove: Vec<Range<Anchor>>,
21587        cx: &mut Context<Self>,
21588    ) {
21589        let snapshot = self.buffer().read(cx).snapshot(cx);
21590        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21591        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21592        row_highlights.retain(|highlight| {
21593            while let Some(range_to_remove) = ranges_to_remove.peek() {
21594                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21595                    Ordering::Less | Ordering::Equal => {
21596                        ranges_to_remove.next();
21597                    }
21598                    Ordering::Greater => {
21599                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21600                            Ordering::Less | Ordering::Equal => {
21601                                return false;
21602                            }
21603                            Ordering::Greater => break,
21604                        }
21605                    }
21606                }
21607            }
21608
21609            true
21610        })
21611    }
21612
21613    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21614    pub fn clear_row_highlights<T: 'static>(&mut self) {
21615        self.highlighted_rows.remove(&TypeId::of::<T>());
21616    }
21617
21618    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21619    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21620        self.highlighted_rows
21621            .get(&TypeId::of::<T>())
21622            .map_or(&[] as &[_], |vec| vec.as_slice())
21623            .iter()
21624            .map(|highlight| (highlight.range.clone(), highlight.color))
21625    }
21626
21627    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21628    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21629    /// Allows to ignore certain kinds of highlights.
21630    pub fn highlighted_display_rows(
21631        &self,
21632        window: &mut Window,
21633        cx: &mut App,
21634    ) -> BTreeMap<DisplayRow, LineHighlight> {
21635        let snapshot = self.snapshot(window, cx);
21636        let mut used_highlight_orders = HashMap::default();
21637        self.highlighted_rows
21638            .iter()
21639            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21640            .fold(
21641                BTreeMap::<DisplayRow, LineHighlight>::new(),
21642                |mut unique_rows, highlight| {
21643                    let start = highlight.range.start.to_display_point(&snapshot);
21644                    let end = highlight.range.end.to_display_point(&snapshot);
21645                    let start_row = start.row().0;
21646                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21647                    {
21648                        end.row().0.saturating_sub(1)
21649                    } else {
21650                        end.row().0
21651                    };
21652                    for row in start_row..=end_row {
21653                        let used_index =
21654                            used_highlight_orders.entry(row).or_insert(highlight.index);
21655                        if highlight.index >= *used_index {
21656                            *used_index = highlight.index;
21657                            unique_rows.insert(
21658                                DisplayRow(row),
21659                                LineHighlight {
21660                                    include_gutter: highlight.options.include_gutter,
21661                                    border: None,
21662                                    background: highlight.color.into(),
21663                                    type_id: Some(highlight.type_id),
21664                                },
21665                            );
21666                        }
21667                    }
21668                    unique_rows
21669                },
21670            )
21671    }
21672
21673    pub fn highlighted_display_row_for_autoscroll(
21674        &self,
21675        snapshot: &DisplaySnapshot,
21676    ) -> Option<DisplayRow> {
21677        self.highlighted_rows
21678            .values()
21679            .flat_map(|highlighted_rows| highlighted_rows.iter())
21680            .filter_map(|highlight| {
21681                if highlight.options.autoscroll {
21682                    Some(highlight.range.start.to_display_point(snapshot).row())
21683                } else {
21684                    None
21685                }
21686            })
21687            .min()
21688    }
21689
21690    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21691        self.highlight_background::<SearchWithinRange>(
21692            ranges,
21693            |_, colors| colors.colors().editor_document_highlight_read_background,
21694            cx,
21695        )
21696    }
21697
21698    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21699        self.breadcrumb_header = Some(new_header);
21700    }
21701
21702    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21703        self.clear_background_highlights::<SearchWithinRange>(cx);
21704    }
21705
21706    pub fn highlight_background<T: 'static>(
21707        &mut self,
21708        ranges: &[Range<Anchor>],
21709        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21710        cx: &mut Context<Self>,
21711    ) {
21712        self.background_highlights.insert(
21713            HighlightKey::Type(TypeId::of::<T>()),
21714            (Arc::new(color_fetcher), Arc::from(ranges)),
21715        );
21716        self.scrollbar_marker_state.dirty = true;
21717        cx.notify();
21718    }
21719
21720    pub fn highlight_background_key<T: 'static>(
21721        &mut self,
21722        key: usize,
21723        ranges: &[Range<Anchor>],
21724        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21725        cx: &mut Context<Self>,
21726    ) {
21727        self.background_highlights.insert(
21728            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21729            (Arc::new(color_fetcher), Arc::from(ranges)),
21730        );
21731        self.scrollbar_marker_state.dirty = true;
21732        cx.notify();
21733    }
21734
21735    pub fn clear_background_highlights<T: 'static>(
21736        &mut self,
21737        cx: &mut Context<Self>,
21738    ) -> Option<BackgroundHighlight> {
21739        let text_highlights = self
21740            .background_highlights
21741            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21742        if !text_highlights.1.is_empty() {
21743            self.scrollbar_marker_state.dirty = true;
21744            cx.notify();
21745        }
21746        Some(text_highlights)
21747    }
21748
21749    pub fn highlight_gutter<T: 'static>(
21750        &mut self,
21751        ranges: impl Into<Vec<Range<Anchor>>>,
21752        color_fetcher: fn(&App) -> Hsla,
21753        cx: &mut Context<Self>,
21754    ) {
21755        self.gutter_highlights
21756            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21757        cx.notify();
21758    }
21759
21760    pub fn clear_gutter_highlights<T: 'static>(
21761        &mut self,
21762        cx: &mut Context<Self>,
21763    ) -> Option<GutterHighlight> {
21764        cx.notify();
21765        self.gutter_highlights.remove(&TypeId::of::<T>())
21766    }
21767
21768    pub fn insert_gutter_highlight<T: 'static>(
21769        &mut self,
21770        range: Range<Anchor>,
21771        color_fetcher: fn(&App) -> Hsla,
21772        cx: &mut Context<Self>,
21773    ) {
21774        let snapshot = self.buffer().read(cx).snapshot(cx);
21775        let mut highlights = self
21776            .gutter_highlights
21777            .remove(&TypeId::of::<T>())
21778            .map(|(_, highlights)| highlights)
21779            .unwrap_or_default();
21780        let ix = highlights.binary_search_by(|highlight| {
21781            Ordering::Equal
21782                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21783                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21784        });
21785        if let Err(ix) = ix {
21786            highlights.insert(ix, range);
21787        }
21788        self.gutter_highlights
21789            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21790    }
21791
21792    pub fn remove_gutter_highlights<T: 'static>(
21793        &mut self,
21794        ranges_to_remove: Vec<Range<Anchor>>,
21795        cx: &mut Context<Self>,
21796    ) {
21797        let snapshot = self.buffer().read(cx).snapshot(cx);
21798        let Some((color_fetcher, mut gutter_highlights)) =
21799            self.gutter_highlights.remove(&TypeId::of::<T>())
21800        else {
21801            return;
21802        };
21803        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21804        gutter_highlights.retain(|highlight| {
21805            while let Some(range_to_remove) = ranges_to_remove.peek() {
21806                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21807                    Ordering::Less | Ordering::Equal => {
21808                        ranges_to_remove.next();
21809                    }
21810                    Ordering::Greater => {
21811                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21812                            Ordering::Less | Ordering::Equal => {
21813                                return false;
21814                            }
21815                            Ordering::Greater => break,
21816                        }
21817                    }
21818                }
21819            }
21820
21821            true
21822        });
21823        self.gutter_highlights
21824            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21825    }
21826
21827    #[cfg(feature = "test-support")]
21828    pub fn all_text_highlights(
21829        &self,
21830        window: &mut Window,
21831        cx: &mut Context<Self>,
21832    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21833        let snapshot = self.snapshot(window, cx);
21834        self.display_map.update(cx, |display_map, _| {
21835            display_map
21836                .all_text_highlights()
21837                .map(|highlight| {
21838                    let (style, ranges) = highlight.as_ref();
21839                    (
21840                        *style,
21841                        ranges
21842                            .iter()
21843                            .map(|range| range.clone().to_display_points(&snapshot))
21844                            .collect(),
21845                    )
21846                })
21847                .collect()
21848        })
21849    }
21850
21851    #[cfg(feature = "test-support")]
21852    pub fn all_text_background_highlights(
21853        &self,
21854        window: &mut Window,
21855        cx: &mut Context<Self>,
21856    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21857        let snapshot = self.snapshot(window, cx);
21858        let buffer = &snapshot.buffer_snapshot();
21859        let start = buffer.anchor_before(MultiBufferOffset(0));
21860        let end = buffer.anchor_after(buffer.len());
21861        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21862    }
21863
21864    #[cfg(any(test, feature = "test-support"))]
21865    pub fn sorted_background_highlights_in_range(
21866        &self,
21867        search_range: Range<Anchor>,
21868        display_snapshot: &DisplaySnapshot,
21869        theme: &Theme,
21870    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21871        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21872        res.sort_by(|a, b| {
21873            a.0.start
21874                .cmp(&b.0.start)
21875                .then_with(|| a.0.end.cmp(&b.0.end))
21876                .then_with(|| a.1.cmp(&b.1))
21877        });
21878        res
21879    }
21880
21881    #[cfg(feature = "test-support")]
21882    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21883        let snapshot = self.buffer().read(cx).snapshot(cx);
21884
21885        let highlights = self
21886            .background_highlights
21887            .get(&HighlightKey::Type(TypeId::of::<
21888                items::BufferSearchHighlights,
21889            >()));
21890
21891        if let Some((_color, ranges)) = highlights {
21892            ranges
21893                .iter()
21894                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21895                .collect_vec()
21896        } else {
21897            vec![]
21898        }
21899    }
21900
21901    fn document_highlights_for_position<'a>(
21902        &'a self,
21903        position: Anchor,
21904        buffer: &'a MultiBufferSnapshot,
21905    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21906        let read_highlights = self
21907            .background_highlights
21908            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21909            .map(|h| &h.1);
21910        let write_highlights = self
21911            .background_highlights
21912            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21913            .map(|h| &h.1);
21914        let left_position = position.bias_left(buffer);
21915        let right_position = position.bias_right(buffer);
21916        read_highlights
21917            .into_iter()
21918            .chain(write_highlights)
21919            .flat_map(move |ranges| {
21920                let start_ix = match ranges.binary_search_by(|probe| {
21921                    let cmp = probe.end.cmp(&left_position, buffer);
21922                    if cmp.is_ge() {
21923                        Ordering::Greater
21924                    } else {
21925                        Ordering::Less
21926                    }
21927                }) {
21928                    Ok(i) | Err(i) => i,
21929                };
21930
21931                ranges[start_ix..]
21932                    .iter()
21933                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21934            })
21935    }
21936
21937    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21938        self.background_highlights
21939            .get(&HighlightKey::Type(TypeId::of::<T>()))
21940            .is_some_and(|(_, highlights)| !highlights.is_empty())
21941    }
21942
21943    /// Returns all background highlights for a given range.
21944    ///
21945    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21946    pub fn background_highlights_in_range(
21947        &self,
21948        search_range: Range<Anchor>,
21949        display_snapshot: &DisplaySnapshot,
21950        theme: &Theme,
21951    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21952        let mut results = Vec::new();
21953        for (color_fetcher, ranges) in self.background_highlights.values() {
21954            let start_ix = match ranges.binary_search_by(|probe| {
21955                let cmp = probe
21956                    .end
21957                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21958                if cmp.is_gt() {
21959                    Ordering::Greater
21960                } else {
21961                    Ordering::Less
21962                }
21963            }) {
21964                Ok(i) | Err(i) => i,
21965            };
21966            for (index, range) in ranges[start_ix..].iter().enumerate() {
21967                if range
21968                    .start
21969                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21970                    .is_ge()
21971                {
21972                    break;
21973                }
21974
21975                let color = color_fetcher(&(start_ix + index), theme);
21976                let start = range.start.to_display_point(display_snapshot);
21977                let end = range.end.to_display_point(display_snapshot);
21978                results.push((start..end, color))
21979            }
21980        }
21981        results
21982    }
21983
21984    pub fn gutter_highlights_in_range(
21985        &self,
21986        search_range: Range<Anchor>,
21987        display_snapshot: &DisplaySnapshot,
21988        cx: &App,
21989    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21990        let mut results = Vec::new();
21991        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21992            let color = color_fetcher(cx);
21993            let start_ix = match ranges.binary_search_by(|probe| {
21994                let cmp = probe
21995                    .end
21996                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21997                if cmp.is_gt() {
21998                    Ordering::Greater
21999                } else {
22000                    Ordering::Less
22001                }
22002            }) {
22003                Ok(i) | Err(i) => i,
22004            };
22005            for range in &ranges[start_ix..] {
22006                if range
22007                    .start
22008                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
22009                    .is_ge()
22010                {
22011                    break;
22012                }
22013
22014                let start = range.start.to_display_point(display_snapshot);
22015                let end = range.end.to_display_point(display_snapshot);
22016                results.push((start..end, color))
22017            }
22018        }
22019        results
22020    }
22021
22022    /// Get the text ranges corresponding to the redaction query
22023    pub fn redacted_ranges(
22024        &self,
22025        search_range: Range<Anchor>,
22026        display_snapshot: &DisplaySnapshot,
22027        cx: &App,
22028    ) -> Vec<Range<DisplayPoint>> {
22029        display_snapshot
22030            .buffer_snapshot()
22031            .redacted_ranges(search_range, |file| {
22032                if let Some(file) = file {
22033                    file.is_private()
22034                        && EditorSettings::get(
22035                            Some(SettingsLocation {
22036                                worktree_id: file.worktree_id(cx),
22037                                path: file.path().as_ref(),
22038                            }),
22039                            cx,
22040                        )
22041                        .redact_private_values
22042                } else {
22043                    false
22044                }
22045            })
22046            .map(|range| {
22047                range.start.to_display_point(display_snapshot)
22048                    ..range.end.to_display_point(display_snapshot)
22049            })
22050            .collect()
22051    }
22052
22053    pub fn highlight_text_key<T: 'static>(
22054        &mut self,
22055        key: usize,
22056        ranges: Vec<Range<Anchor>>,
22057        style: HighlightStyle,
22058        merge: bool,
22059        cx: &mut Context<Self>,
22060    ) {
22061        self.display_map.update(cx, |map, cx| {
22062            map.highlight_text(
22063                HighlightKey::TypePlus(TypeId::of::<T>(), key),
22064                ranges,
22065                style,
22066                merge,
22067                cx,
22068            );
22069        });
22070        cx.notify();
22071    }
22072
22073    pub fn highlight_text<T: 'static>(
22074        &mut self,
22075        ranges: Vec<Range<Anchor>>,
22076        style: HighlightStyle,
22077        cx: &mut Context<Self>,
22078    ) {
22079        self.display_map.update(cx, |map, cx| {
22080            map.highlight_text(
22081                HighlightKey::Type(TypeId::of::<T>()),
22082                ranges,
22083                style,
22084                false,
22085                cx,
22086            )
22087        });
22088        cx.notify();
22089    }
22090
22091    pub fn text_highlights<'a, T: 'static>(
22092        &'a self,
22093        cx: &'a App,
22094    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
22095        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
22096    }
22097
22098    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
22099        let cleared = self
22100            .display_map
22101            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
22102        if cleared {
22103            cx.notify();
22104        }
22105    }
22106
22107    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
22108        (self.read_only(cx) || self.blink_manager.read(cx).visible())
22109            && self.focus_handle.is_focused(window)
22110    }
22111
22112    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
22113        self.show_cursor_when_unfocused = is_enabled;
22114        cx.notify();
22115    }
22116
22117    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
22118        cx.notify();
22119    }
22120
22121    fn on_debug_session_event(
22122        &mut self,
22123        _session: Entity<Session>,
22124        event: &SessionEvent,
22125        cx: &mut Context<Self>,
22126    ) {
22127        if let SessionEvent::InvalidateInlineValue = event {
22128            self.refresh_inline_values(cx);
22129        }
22130    }
22131
22132    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
22133        let Some(project) = self.project.clone() else {
22134            return;
22135        };
22136
22137        if !self.inline_value_cache.enabled {
22138            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
22139            self.splice_inlays(&inlays, Vec::new(), cx);
22140            return;
22141        }
22142
22143        let current_execution_position = self
22144            .highlighted_rows
22145            .get(&TypeId::of::<ActiveDebugLine>())
22146            .and_then(|lines| lines.last().map(|line| line.range.end));
22147
22148        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
22149            let inline_values = editor
22150                .update(cx, |editor, cx| {
22151                    let Some(current_execution_position) = current_execution_position else {
22152                        return Some(Task::ready(Ok(Vec::new())));
22153                    };
22154
22155                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
22156                        let snapshot = buffer.snapshot(cx);
22157
22158                        let excerpt = snapshot.excerpt_containing(
22159                            current_execution_position..current_execution_position,
22160                        )?;
22161
22162                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
22163                    })?;
22164
22165                    let range =
22166                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
22167
22168                    project.inline_values(buffer, range, cx)
22169                })
22170                .ok()
22171                .flatten()?
22172                .await
22173                .context("refreshing debugger inlays")
22174                .log_err()?;
22175
22176            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
22177
22178            for (buffer_id, inline_value) in inline_values
22179                .into_iter()
22180                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
22181            {
22182                buffer_inline_values
22183                    .entry(buffer_id)
22184                    .or_default()
22185                    .push(inline_value);
22186            }
22187
22188            editor
22189                .update(cx, |editor, cx| {
22190                    let snapshot = editor.buffer.read(cx).snapshot(cx);
22191                    let mut new_inlays = Vec::default();
22192
22193                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22194                        let buffer_id = buffer_snapshot.remote_id();
22195                        buffer_inline_values
22196                            .get(&buffer_id)
22197                            .into_iter()
22198                            .flatten()
22199                            .for_each(|hint| {
22200                                let inlay = Inlay::debugger(
22201                                    post_inc(&mut editor.next_inlay_id),
22202                                    Anchor::in_buffer(excerpt_id, hint.position),
22203                                    hint.text(),
22204                                );
22205                                if !inlay.text().chars().contains(&'\n') {
22206                                    new_inlays.push(inlay);
22207                                }
22208                            });
22209                    }
22210
22211                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22212                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22213
22214                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22215                })
22216                .ok()?;
22217            Some(())
22218        });
22219    }
22220
22221    fn on_buffer_event(
22222        &mut self,
22223        multibuffer: &Entity<MultiBuffer>,
22224        event: &multi_buffer::Event,
22225        window: &mut Window,
22226        cx: &mut Context<Self>,
22227    ) {
22228        match event {
22229            multi_buffer::Event::Edited { edited_buffer } => {
22230                self.scrollbar_marker_state.dirty = true;
22231                self.active_indent_guides_state.dirty = true;
22232                self.refresh_active_diagnostics(cx);
22233                self.refresh_code_actions(window, cx);
22234                self.refresh_single_line_folds(window, cx);
22235                self.refresh_matching_bracket_highlights(window, cx);
22236                if self.has_active_edit_prediction() {
22237                    self.update_visible_edit_prediction(window, cx);
22238                }
22239
22240                if let Some(buffer) = edited_buffer {
22241                    if buffer.read(cx).file().is_none() {
22242                        cx.emit(EditorEvent::TitleChanged);
22243                    }
22244
22245                    if self.project.is_some() {
22246                        let buffer_id = buffer.read(cx).remote_id();
22247                        self.register_buffer(buffer_id, cx);
22248                        self.update_lsp_data(Some(buffer_id), window, cx);
22249                        self.refresh_inlay_hints(
22250                            InlayHintRefreshReason::BufferEdited(buffer_id),
22251                            cx,
22252                        );
22253                    }
22254                }
22255
22256                cx.emit(EditorEvent::BufferEdited);
22257                cx.emit(SearchEvent::MatchesInvalidated);
22258
22259                let Some(project) = &self.project else { return };
22260                let (telemetry, is_via_ssh) = {
22261                    let project = project.read(cx);
22262                    let telemetry = project.client().telemetry().clone();
22263                    let is_via_ssh = project.is_via_remote_server();
22264                    (telemetry, is_via_ssh)
22265                };
22266                telemetry.log_edit_event("editor", is_via_ssh);
22267            }
22268            multi_buffer::Event::ExcerptsAdded {
22269                buffer,
22270                predecessor,
22271                excerpts,
22272            } => {
22273                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22274                let buffer_id = buffer.read(cx).remote_id();
22275                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22276                    && let Some(project) = &self.project
22277                {
22278                    update_uncommitted_diff_for_buffer(
22279                        cx.entity(),
22280                        project,
22281                        [buffer.clone()],
22282                        self.buffer.clone(),
22283                        cx,
22284                    )
22285                    .detach();
22286                }
22287                self.update_lsp_data(Some(buffer_id), window, cx);
22288                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22289                self.colorize_brackets(false, cx);
22290                self.refresh_selected_text_highlights(true, window, cx);
22291                cx.emit(EditorEvent::ExcerptsAdded {
22292                    buffer: buffer.clone(),
22293                    predecessor: *predecessor,
22294                    excerpts: excerpts.clone(),
22295                });
22296            }
22297            multi_buffer::Event::ExcerptsRemoved {
22298                ids,
22299                removed_buffer_ids,
22300            } => {
22301                if let Some(inlay_hints) = &mut self.inlay_hints {
22302                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22303                }
22304                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22305                for buffer_id in removed_buffer_ids {
22306                    self.registered_buffers.remove(buffer_id);
22307                }
22308                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22309                cx.emit(EditorEvent::ExcerptsRemoved {
22310                    ids: ids.clone(),
22311                    removed_buffer_ids: removed_buffer_ids.clone(),
22312                });
22313            }
22314            multi_buffer::Event::ExcerptsEdited {
22315                excerpt_ids,
22316                buffer_ids,
22317            } => {
22318                self.display_map.update(cx, |map, cx| {
22319                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22320                });
22321                cx.emit(EditorEvent::ExcerptsEdited {
22322                    ids: excerpt_ids.clone(),
22323                });
22324            }
22325            multi_buffer::Event::ExcerptsExpanded { ids } => {
22326                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22327                self.refresh_document_highlights(cx);
22328                for id in ids {
22329                    self.fetched_tree_sitter_chunks.remove(id);
22330                }
22331                self.colorize_brackets(false, cx);
22332                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22333            }
22334            multi_buffer::Event::Reparsed(buffer_id) => {
22335                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22336                self.refresh_selected_text_highlights(true, window, cx);
22337                self.colorize_brackets(true, cx);
22338                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22339
22340                cx.emit(EditorEvent::Reparsed(*buffer_id));
22341            }
22342            multi_buffer::Event::DiffHunksToggled => {
22343                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22344            }
22345            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22346                if !is_fresh_language {
22347                    self.registered_buffers.remove(&buffer_id);
22348                }
22349                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22350                cx.emit(EditorEvent::Reparsed(*buffer_id));
22351                cx.notify();
22352            }
22353            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22354            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22355            multi_buffer::Event::FileHandleChanged
22356            | multi_buffer::Event::Reloaded
22357            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22358            multi_buffer::Event::DiagnosticsUpdated => {
22359                self.update_diagnostics_state(window, cx);
22360            }
22361            _ => {}
22362        };
22363    }
22364
22365    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22366        if !self.diagnostics_enabled() {
22367            return;
22368        }
22369        self.refresh_active_diagnostics(cx);
22370        self.refresh_inline_diagnostics(true, window, cx);
22371        self.scrollbar_marker_state.dirty = true;
22372        cx.notify();
22373    }
22374
22375    pub fn start_temporary_diff_override(&mut self) {
22376        self.load_diff_task.take();
22377        self.temporary_diff_override = true;
22378    }
22379
22380    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22381        self.temporary_diff_override = false;
22382        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22383        self.buffer.update(cx, |buffer, cx| {
22384            buffer.set_all_diff_hunks_collapsed(cx);
22385        });
22386
22387        if let Some(project) = self.project.clone() {
22388            self.load_diff_task = Some(
22389                update_uncommitted_diff_for_buffer(
22390                    cx.entity(),
22391                    &project,
22392                    self.buffer.read(cx).all_buffers(),
22393                    self.buffer.clone(),
22394                    cx,
22395                )
22396                .shared(),
22397            );
22398        }
22399    }
22400
22401    fn on_display_map_changed(
22402        &mut self,
22403        _: Entity<DisplayMap>,
22404        _: &mut Window,
22405        cx: &mut Context<Self>,
22406    ) {
22407        cx.notify();
22408    }
22409
22410    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22411        if !self.mode.is_full() {
22412            return None;
22413        }
22414
22415        let theme_settings = theme::ThemeSettings::get_global(cx);
22416        let theme = cx.theme();
22417        let accent_colors = theme.accents().clone();
22418
22419        let accent_overrides = theme_settings
22420            .theme_overrides
22421            .get(theme.name.as_ref())
22422            .map(|theme_style| &theme_style.accents)
22423            .into_iter()
22424            .flatten()
22425            .chain(
22426                theme_settings
22427                    .experimental_theme_overrides
22428                    .as_ref()
22429                    .map(|overrides| &overrides.accents)
22430                    .into_iter()
22431                    .flatten(),
22432            )
22433            .flat_map(|accent| accent.0.clone())
22434            .collect();
22435
22436        Some(AccentData {
22437            colors: accent_colors,
22438            overrides: accent_overrides,
22439        })
22440    }
22441
22442    fn fetch_applicable_language_settings(
22443        &self,
22444        cx: &App,
22445    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22446        if !self.mode.is_full() {
22447            return HashMap::default();
22448        }
22449
22450        self.buffer().read(cx).all_buffers().into_iter().fold(
22451            HashMap::default(),
22452            |mut acc, buffer| {
22453                let buffer = buffer.read(cx);
22454                let language = buffer.language().map(|language| language.name());
22455                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22456                    let file = buffer.file();
22457                    v.insert(language_settings(language, file, cx).into_owned());
22458                }
22459                acc
22460            },
22461        )
22462    }
22463
22464    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22465        let new_language_settings = self.fetch_applicable_language_settings(cx);
22466        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22467        self.applicable_language_settings = new_language_settings;
22468
22469        let new_accents = self.fetch_accent_data(cx);
22470        let accents_changed = new_accents != self.accent_data;
22471        self.accent_data = new_accents;
22472
22473        if self.diagnostics_enabled() {
22474            let new_severity = EditorSettings::get_global(cx)
22475                .diagnostics_max_severity
22476                .unwrap_or(DiagnosticSeverity::Hint);
22477            self.set_max_diagnostics_severity(new_severity, cx);
22478        }
22479        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22480        self.update_edit_prediction_settings(cx);
22481        self.refresh_edit_prediction(true, false, window, cx);
22482        self.refresh_inline_values(cx);
22483        self.refresh_inlay_hints(
22484            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22485                self.selections.newest_anchor().head(),
22486                &self.buffer.read(cx).snapshot(cx),
22487                cx,
22488            )),
22489            cx,
22490        );
22491
22492        let old_cursor_shape = self.cursor_shape;
22493        let old_show_breadcrumbs = self.show_breadcrumbs;
22494
22495        {
22496            let editor_settings = EditorSettings::get_global(cx);
22497            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22498            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22499            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22500            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22501        }
22502
22503        if old_cursor_shape != self.cursor_shape {
22504            cx.emit(EditorEvent::CursorShapeChanged);
22505        }
22506
22507        if old_show_breadcrumbs != self.show_breadcrumbs {
22508            cx.emit(EditorEvent::BreadcrumbsChanged);
22509        }
22510
22511        let project_settings = ProjectSettings::get_global(cx);
22512        self.buffer_serialization = self
22513            .should_serialize_buffer()
22514            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22515
22516        if self.mode.is_full() {
22517            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22518            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22519            if self.show_inline_diagnostics != show_inline_diagnostics {
22520                self.show_inline_diagnostics = show_inline_diagnostics;
22521                self.refresh_inline_diagnostics(false, window, cx);
22522            }
22523
22524            if self.git_blame_inline_enabled != inline_blame_enabled {
22525                self.toggle_git_blame_inline_internal(false, window, cx);
22526            }
22527
22528            let minimap_settings = EditorSettings::get_global(cx).minimap;
22529            if self.minimap_visibility != MinimapVisibility::Disabled {
22530                if self.minimap_visibility.settings_visibility()
22531                    != minimap_settings.minimap_enabled()
22532                {
22533                    self.set_minimap_visibility(
22534                        MinimapVisibility::for_mode(self.mode(), cx),
22535                        window,
22536                        cx,
22537                    );
22538                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22539                    minimap_entity.update(cx, |minimap_editor, cx| {
22540                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22541                    })
22542                }
22543            }
22544
22545            if language_settings_changed || accents_changed {
22546                self.colorize_brackets(true, cx);
22547            }
22548
22549            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22550                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22551            }) {
22552                if !inlay_splice.is_empty() {
22553                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22554                }
22555                self.refresh_colors_for_visible_range(None, window, cx);
22556            }
22557        }
22558
22559        cx.notify();
22560    }
22561
22562    pub fn set_searchable(&mut self, searchable: bool) {
22563        self.searchable = searchable;
22564    }
22565
22566    pub fn searchable(&self) -> bool {
22567        self.searchable
22568    }
22569
22570    pub fn open_excerpts_in_split(
22571        &mut self,
22572        _: &OpenExcerptsSplit,
22573        window: &mut Window,
22574        cx: &mut Context<Self>,
22575    ) {
22576        self.open_excerpts_common(None, true, window, cx)
22577    }
22578
22579    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22580        self.open_excerpts_common(None, false, window, cx)
22581    }
22582
22583    fn open_excerpts_common(
22584        &mut self,
22585        jump_data: Option<JumpData>,
22586        split: bool,
22587        window: &mut Window,
22588        cx: &mut Context<Self>,
22589    ) {
22590        let Some(workspace) = self.workspace() else {
22591            cx.propagate();
22592            return;
22593        };
22594
22595        if self.buffer.read(cx).is_singleton() {
22596            cx.propagate();
22597            return;
22598        }
22599
22600        let mut new_selections_by_buffer = HashMap::default();
22601        match &jump_data {
22602            Some(JumpData::MultiBufferPoint {
22603                excerpt_id,
22604                position,
22605                anchor,
22606                line_offset_from_top,
22607            }) => {
22608                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22609                if let Some(buffer) = multi_buffer_snapshot
22610                    .buffer_id_for_excerpt(*excerpt_id)
22611                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22612                {
22613                    let buffer_snapshot = buffer.read(cx).snapshot();
22614                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22615                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22616                    } else {
22617                        buffer_snapshot.clip_point(*position, Bias::Left)
22618                    };
22619                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22620                    new_selections_by_buffer.insert(
22621                        buffer,
22622                        (
22623                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22624                            Some(*line_offset_from_top),
22625                        ),
22626                    );
22627                }
22628            }
22629            Some(JumpData::MultiBufferRow {
22630                row,
22631                line_offset_from_top,
22632            }) => {
22633                let point = MultiBufferPoint::new(row.0, 0);
22634                if let Some((buffer, buffer_point, _)) =
22635                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22636                {
22637                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22638                    new_selections_by_buffer
22639                        .entry(buffer)
22640                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22641                        .0
22642                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22643                }
22644            }
22645            None => {
22646                let selections = self
22647                    .selections
22648                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22649                let multi_buffer = self.buffer.read(cx);
22650                for selection in selections {
22651                    for (snapshot, range, _, anchor) in multi_buffer
22652                        .snapshot(cx)
22653                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22654                    {
22655                        if let Some(anchor) = anchor {
22656                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22657                            else {
22658                                continue;
22659                            };
22660                            let offset = text::ToOffset::to_offset(
22661                                &anchor.text_anchor,
22662                                &buffer_handle.read(cx).snapshot(),
22663                            );
22664                            let range = BufferOffset(offset)..BufferOffset(offset);
22665                            new_selections_by_buffer
22666                                .entry(buffer_handle)
22667                                .or_insert((Vec::new(), None))
22668                                .0
22669                                .push(range)
22670                        } else {
22671                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22672                            else {
22673                                continue;
22674                            };
22675                            new_selections_by_buffer
22676                                .entry(buffer_handle)
22677                                .or_insert((Vec::new(), None))
22678                                .0
22679                                .push(range)
22680                        }
22681                    }
22682                }
22683            }
22684        }
22685
22686        new_selections_by_buffer
22687            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
22688
22689        if new_selections_by_buffer.is_empty() {
22690            return;
22691        }
22692
22693        // We defer the pane interaction because we ourselves are a workspace item
22694        // and activating a new item causes the pane to call a method on us reentrantly,
22695        // which panics if we're on the stack.
22696        window.defer(cx, move |window, cx| {
22697            workspace.update(cx, |workspace, cx| {
22698                let pane = if split {
22699                    workspace.adjacent_pane(window, cx)
22700                } else {
22701                    workspace.active_pane().clone()
22702                };
22703
22704                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22705                    let buffer_read = buffer.read(cx);
22706                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22707                        (true, project::File::from_dyn(Some(file)).is_some())
22708                    } else {
22709                        (false, false)
22710                    };
22711
22712                    // If project file is none workspace.open_project_item will fail to open the excerpt
22713                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22714                    // so we check if there's a tab match in that case first
22715                    let editor = (!has_file || !is_project_file)
22716                        .then(|| {
22717                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22718                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22719                            // Instead, we try to activate the existing editor in the pane first.
22720                            let (editor, pane_item_index, pane_item_id) =
22721                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22722                                    let editor = item.downcast::<Editor>()?;
22723                                    let singleton_buffer =
22724                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22725                                    if singleton_buffer == buffer {
22726                                        Some((editor, i, item.item_id()))
22727                                    } else {
22728                                        None
22729                                    }
22730                                })?;
22731                            pane.update(cx, |pane, cx| {
22732                                pane.activate_item(pane_item_index, true, true, window, cx);
22733                                if !PreviewTabsSettings::get_global(cx)
22734                                    .enable_preview_from_multibuffer
22735                                {
22736                                    pane.unpreview_item_if_preview(pane_item_id);
22737                                }
22738                            });
22739                            Some(editor)
22740                        })
22741                        .flatten()
22742                        .unwrap_or_else(|| {
22743                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22744                                .enable_keep_preview_on_code_navigation;
22745                            let allow_new_preview =
22746                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22747                            workspace.open_project_item::<Self>(
22748                                pane.clone(),
22749                                buffer,
22750                                true,
22751                                true,
22752                                keep_old_preview,
22753                                allow_new_preview,
22754                                window,
22755                                cx,
22756                            )
22757                        });
22758
22759                    editor.update(cx, |editor, cx| {
22760                        if has_file && !is_project_file {
22761                            editor.set_read_only(true);
22762                        }
22763                        let autoscroll = match scroll_offset {
22764                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22765                            None => Autoscroll::newest(),
22766                        };
22767                        let nav_history = editor.nav_history.take();
22768                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22769                        let Some((&excerpt_id, _, buffer_snapshot)) =
22770                            multibuffer_snapshot.as_singleton()
22771                        else {
22772                            return;
22773                        };
22774                        editor.change_selections(
22775                            SelectionEffects::scroll(autoscroll),
22776                            window,
22777                            cx,
22778                            |s| {
22779                                s.select_ranges(ranges.into_iter().map(|range| {
22780                                    let range = buffer_snapshot.anchor_before(range.start)
22781                                        ..buffer_snapshot.anchor_after(range.end);
22782                                    multibuffer_snapshot
22783                                        .anchor_range_in_excerpt(excerpt_id, range)
22784                                        .unwrap()
22785                                }));
22786                            },
22787                        );
22788                        editor.nav_history = nav_history;
22789                    });
22790                }
22791            })
22792        });
22793    }
22794
22795    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22796        let snapshot = self.buffer.read(cx).read(cx);
22797        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22798        Some(
22799            ranges
22800                .iter()
22801                .map(move |range| {
22802                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22803                })
22804                .collect(),
22805        )
22806    }
22807
22808    fn selection_replacement_ranges(
22809        &self,
22810        range: Range<MultiBufferOffsetUtf16>,
22811        cx: &mut App,
22812    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22813        let selections = self
22814            .selections
22815            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22816        let newest_selection = selections
22817            .iter()
22818            .max_by_key(|selection| selection.id)
22819            .unwrap();
22820        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22821        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22822        let snapshot = self.buffer.read(cx).read(cx);
22823        selections
22824            .into_iter()
22825            .map(|mut selection| {
22826                selection.start.0.0 =
22827                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22828                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22829                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22830                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22831            })
22832            .collect()
22833    }
22834
22835    fn report_editor_event(
22836        &self,
22837        reported_event: ReportEditorEvent,
22838        file_extension: Option<String>,
22839        cx: &App,
22840    ) {
22841        if cfg!(any(test, feature = "test-support")) {
22842            return;
22843        }
22844
22845        let Some(project) = &self.project else { return };
22846
22847        // If None, we are in a file without an extension
22848        let file = self
22849            .buffer
22850            .read(cx)
22851            .as_singleton()
22852            .and_then(|b| b.read(cx).file());
22853        let file_extension = file_extension.or(file
22854            .as_ref()
22855            .and_then(|file| Path::new(file.file_name(cx)).extension())
22856            .and_then(|e| e.to_str())
22857            .map(|a| a.to_string()));
22858
22859        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22860            .map(|vim_mode| vim_mode.0)
22861            .unwrap_or(false);
22862
22863        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22864        let copilot_enabled = edit_predictions_provider
22865            == language::language_settings::EditPredictionProvider::Copilot;
22866        let copilot_enabled_for_language = self
22867            .buffer
22868            .read(cx)
22869            .language_settings(cx)
22870            .show_edit_predictions;
22871
22872        let project = project.read(cx);
22873        let event_type = reported_event.event_type();
22874
22875        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22876            telemetry::event!(
22877                event_type,
22878                type = if auto_saved {"autosave"} else {"manual"},
22879                file_extension,
22880                vim_mode,
22881                copilot_enabled,
22882                copilot_enabled_for_language,
22883                edit_predictions_provider,
22884                is_via_ssh = project.is_via_remote_server(),
22885            );
22886        } else {
22887            telemetry::event!(
22888                event_type,
22889                file_extension,
22890                vim_mode,
22891                copilot_enabled,
22892                copilot_enabled_for_language,
22893                edit_predictions_provider,
22894                is_via_ssh = project.is_via_remote_server(),
22895            );
22896        };
22897    }
22898
22899    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22900    /// with each line being an array of {text, highlight} objects.
22901    fn copy_highlight_json(
22902        &mut self,
22903        _: &CopyHighlightJson,
22904        window: &mut Window,
22905        cx: &mut Context<Self>,
22906    ) {
22907        #[derive(Serialize)]
22908        struct Chunk<'a> {
22909            text: String,
22910            highlight: Option<&'a str>,
22911        }
22912
22913        let snapshot = self.buffer.read(cx).snapshot(cx);
22914        let range = self
22915            .selected_text_range(false, window, cx)
22916            .and_then(|selection| {
22917                if selection.range.is_empty() {
22918                    None
22919                } else {
22920                    Some(
22921                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22922                            selection.range.start,
22923                        )))
22924                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22925                                selection.range.end,
22926                            ))),
22927                    )
22928                }
22929            })
22930            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22931
22932        let chunks = snapshot.chunks(range, true);
22933        let mut lines = Vec::new();
22934        let mut line: VecDeque<Chunk> = VecDeque::new();
22935
22936        let Some(style) = self.style.as_ref() else {
22937            return;
22938        };
22939
22940        for chunk in chunks {
22941            let highlight = chunk
22942                .syntax_highlight_id
22943                .and_then(|id| id.name(&style.syntax));
22944            let mut chunk_lines = chunk.text.split('\n').peekable();
22945            while let Some(text) = chunk_lines.next() {
22946                let mut merged_with_last_token = false;
22947                if let Some(last_token) = line.back_mut()
22948                    && last_token.highlight == highlight
22949                {
22950                    last_token.text.push_str(text);
22951                    merged_with_last_token = true;
22952                }
22953
22954                if !merged_with_last_token {
22955                    line.push_back(Chunk {
22956                        text: text.into(),
22957                        highlight,
22958                    });
22959                }
22960
22961                if chunk_lines.peek().is_some() {
22962                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22963                        line.pop_front();
22964                    }
22965                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22966                        line.pop_back();
22967                    }
22968
22969                    lines.push(mem::take(&mut line));
22970                }
22971            }
22972        }
22973
22974        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22975            return;
22976        };
22977        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22978    }
22979
22980    pub fn open_context_menu(
22981        &mut self,
22982        _: &OpenContextMenu,
22983        window: &mut Window,
22984        cx: &mut Context<Self>,
22985    ) {
22986        self.request_autoscroll(Autoscroll::newest(), cx);
22987        let position = self
22988            .selections
22989            .newest_display(&self.display_snapshot(cx))
22990            .start;
22991        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22992    }
22993
22994    pub fn replay_insert_event(
22995        &mut self,
22996        text: &str,
22997        relative_utf16_range: Option<Range<isize>>,
22998        window: &mut Window,
22999        cx: &mut Context<Self>,
23000    ) {
23001        if !self.input_enabled {
23002            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23003            return;
23004        }
23005        if let Some(relative_utf16_range) = relative_utf16_range {
23006            let selections = self
23007                .selections
23008                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
23009            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23010                let new_ranges = selections.into_iter().map(|range| {
23011                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
23012                        range
23013                            .head()
23014                            .0
23015                            .0
23016                            .saturating_add_signed(relative_utf16_range.start),
23017                    ));
23018                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
23019                        range
23020                            .head()
23021                            .0
23022                            .0
23023                            .saturating_add_signed(relative_utf16_range.end),
23024                    ));
23025                    start..end
23026                });
23027                s.select_ranges(new_ranges);
23028            });
23029        }
23030
23031        self.handle_input(text, window, cx);
23032    }
23033
23034    pub fn is_focused(&self, window: &Window) -> bool {
23035        self.focus_handle.is_focused(window)
23036    }
23037
23038    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23039        cx.emit(EditorEvent::Focused);
23040
23041        if let Some(descendant) = self
23042            .last_focused_descendant
23043            .take()
23044            .and_then(|descendant| descendant.upgrade())
23045        {
23046            window.focus(&descendant, cx);
23047        } else {
23048            if let Some(blame) = self.blame.as_ref() {
23049                blame.update(cx, GitBlame::focus)
23050            }
23051
23052            self.blink_manager.update(cx, BlinkManager::enable);
23053            self.show_cursor_names(window, cx);
23054            self.buffer.update(cx, |buffer, cx| {
23055                buffer.finalize_last_transaction(cx);
23056                if self.leader_id.is_none() {
23057                    buffer.set_active_selections(
23058                        &self.selections.disjoint_anchors_arc(),
23059                        self.selections.line_mode(),
23060                        self.cursor_shape,
23061                        cx,
23062                    );
23063                }
23064            });
23065
23066            if let Some(position_map) = self.last_position_map.clone() {
23067                EditorElement::mouse_moved(
23068                    self,
23069                    &MouseMoveEvent {
23070                        position: window.mouse_position(),
23071                        pressed_button: None,
23072                        modifiers: window.modifiers(),
23073                    },
23074                    &position_map,
23075                    window,
23076                    cx,
23077                );
23078            }
23079        }
23080    }
23081
23082    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23083        cx.emit(EditorEvent::FocusedIn)
23084    }
23085
23086    fn handle_focus_out(
23087        &mut self,
23088        event: FocusOutEvent,
23089        _window: &mut Window,
23090        cx: &mut Context<Self>,
23091    ) {
23092        if event.blurred != self.focus_handle {
23093            self.last_focused_descendant = Some(event.blurred);
23094        }
23095        self.selection_drag_state = SelectionDragState::None;
23096        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
23097    }
23098
23099    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23100        self.blink_manager.update(cx, BlinkManager::disable);
23101        self.buffer
23102            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
23103
23104        if let Some(blame) = self.blame.as_ref() {
23105            blame.update(cx, GitBlame::blur)
23106        }
23107        if !self.hover_state.focused(window, cx) {
23108            hide_hover(self, cx);
23109        }
23110        if !self
23111            .context_menu
23112            .borrow()
23113            .as_ref()
23114            .is_some_and(|context_menu| context_menu.focused(window, cx))
23115        {
23116            self.hide_context_menu(window, cx);
23117        }
23118        self.take_active_edit_prediction(cx);
23119        cx.emit(EditorEvent::Blurred);
23120        cx.notify();
23121    }
23122
23123    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23124        let mut pending: String = window
23125            .pending_input_keystrokes()
23126            .into_iter()
23127            .flatten()
23128            .filter_map(|keystroke| keystroke.key_char.clone())
23129            .collect();
23130
23131        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
23132            pending = "".to_string();
23133        }
23134
23135        let existing_pending = self
23136            .text_highlights::<PendingInput>(cx)
23137            .map(|(_, ranges)| ranges.to_vec());
23138        if existing_pending.is_none() && pending.is_empty() {
23139            return;
23140        }
23141        let transaction =
23142            self.transact(window, cx, |this, window, cx| {
23143                let selections = this
23144                    .selections
23145                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
23146                let edits = selections
23147                    .iter()
23148                    .map(|selection| (selection.end..selection.end, pending.clone()));
23149                this.edit(edits, cx);
23150                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23151                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
23152                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
23153                    }));
23154                });
23155                if let Some(existing_ranges) = existing_pending {
23156                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
23157                    this.edit(edits, cx);
23158                }
23159            });
23160
23161        let snapshot = self.snapshot(window, cx);
23162        let ranges = self
23163            .selections
23164            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
23165            .into_iter()
23166            .map(|selection| {
23167                snapshot.buffer_snapshot().anchor_after(selection.end)
23168                    ..snapshot
23169                        .buffer_snapshot()
23170                        .anchor_before(selection.end + pending.len())
23171            })
23172            .collect();
23173
23174        if pending.is_empty() {
23175            self.clear_highlights::<PendingInput>(cx);
23176        } else {
23177            self.highlight_text::<PendingInput>(
23178                ranges,
23179                HighlightStyle {
23180                    underline: Some(UnderlineStyle {
23181                        thickness: px(1.),
23182                        color: None,
23183                        wavy: false,
23184                    }),
23185                    ..Default::default()
23186                },
23187                cx,
23188            );
23189        }
23190
23191        self.ime_transaction = self.ime_transaction.or(transaction);
23192        if let Some(transaction) = self.ime_transaction {
23193            self.buffer.update(cx, |buffer, cx| {
23194                buffer.group_until_transaction(transaction, cx);
23195            });
23196        }
23197
23198        if self.text_highlights::<PendingInput>(cx).is_none() {
23199            self.ime_transaction.take();
23200        }
23201    }
23202
23203    pub fn register_action_renderer(
23204        &mut self,
23205        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23206    ) -> Subscription {
23207        let id = self.next_editor_action_id.post_inc();
23208        self.editor_actions
23209            .borrow_mut()
23210            .insert(id, Box::new(listener));
23211
23212        let editor_actions = self.editor_actions.clone();
23213        Subscription::new(move || {
23214            editor_actions.borrow_mut().remove(&id);
23215        })
23216    }
23217
23218    pub fn register_action<A: Action>(
23219        &mut self,
23220        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23221    ) -> Subscription {
23222        let id = self.next_editor_action_id.post_inc();
23223        let listener = Arc::new(listener);
23224        self.editor_actions.borrow_mut().insert(
23225            id,
23226            Box::new(move |_, window, _| {
23227                let listener = listener.clone();
23228                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23229                    let action = action.downcast_ref().unwrap();
23230                    if phase == DispatchPhase::Bubble {
23231                        listener(action, window, cx)
23232                    }
23233                })
23234            }),
23235        );
23236
23237        let editor_actions = self.editor_actions.clone();
23238        Subscription::new(move || {
23239            editor_actions.borrow_mut().remove(&id);
23240        })
23241    }
23242
23243    pub fn file_header_size(&self) -> u32 {
23244        FILE_HEADER_HEIGHT
23245    }
23246
23247    pub fn restore(
23248        &mut self,
23249        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23250        window: &mut Window,
23251        cx: &mut Context<Self>,
23252    ) {
23253        self.buffer().update(cx, |multi_buffer, cx| {
23254            for (buffer_id, changes) in revert_changes {
23255                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23256                    buffer.update(cx, |buffer, cx| {
23257                        buffer.edit(
23258                            changes
23259                                .into_iter()
23260                                .map(|(range, text)| (range, text.to_string())),
23261                            None,
23262                            cx,
23263                        );
23264                    });
23265                }
23266            }
23267        });
23268        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23269            selections.refresh()
23270        });
23271    }
23272
23273    pub fn to_pixel_point(
23274        &mut self,
23275        source: multi_buffer::Anchor,
23276        editor_snapshot: &EditorSnapshot,
23277        window: &mut Window,
23278        cx: &App,
23279    ) -> Option<gpui::Point<Pixels>> {
23280        let source_point = source.to_display_point(editor_snapshot);
23281        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23282    }
23283
23284    pub fn display_to_pixel_point(
23285        &mut self,
23286        source: DisplayPoint,
23287        editor_snapshot: &EditorSnapshot,
23288        window: &mut Window,
23289        cx: &App,
23290    ) -> Option<gpui::Point<Pixels>> {
23291        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23292        let text_layout_details = self.text_layout_details(window);
23293        let scroll_top = text_layout_details
23294            .scroll_anchor
23295            .scroll_position(editor_snapshot)
23296            .y;
23297
23298        if source.row().as_f64() < scroll_top.floor() {
23299            return None;
23300        }
23301        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23302        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23303        Some(gpui::Point::new(source_x, source_y))
23304    }
23305
23306    pub fn has_visible_completions_menu(&self) -> bool {
23307        !self.edit_prediction_preview_is_active()
23308            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23309                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23310            })
23311    }
23312
23313    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23314        if self.mode.is_minimap() {
23315            return;
23316        }
23317        self.addons
23318            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23319    }
23320
23321    pub fn unregister_addon<T: Addon>(&mut self) {
23322        self.addons.remove(&std::any::TypeId::of::<T>());
23323    }
23324
23325    pub fn addon<T: Addon>(&self) -> Option<&T> {
23326        let type_id = std::any::TypeId::of::<T>();
23327        self.addons
23328            .get(&type_id)
23329            .and_then(|item| item.to_any().downcast_ref::<T>())
23330    }
23331
23332    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23333        let type_id = std::any::TypeId::of::<T>();
23334        self.addons
23335            .get_mut(&type_id)
23336            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23337    }
23338
23339    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23340        let text_layout_details = self.text_layout_details(window);
23341        let style = &text_layout_details.editor_style;
23342        let font_id = window.text_system().resolve_font(&style.text.font());
23343        let font_size = style.text.font_size.to_pixels(window.rem_size());
23344        let line_height = style.text.line_height_in_pixels(window.rem_size());
23345        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23346        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23347
23348        CharacterDimensions {
23349            em_width,
23350            em_advance,
23351            line_height,
23352        }
23353    }
23354
23355    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23356        self.load_diff_task.clone()
23357    }
23358
23359    fn read_metadata_from_db(
23360        &mut self,
23361        item_id: u64,
23362        workspace_id: WorkspaceId,
23363        window: &mut Window,
23364        cx: &mut Context<Editor>,
23365    ) {
23366        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23367            && !self.mode.is_minimap()
23368            && WorkspaceSettings::get(None, cx).restore_on_startup
23369                != RestoreOnStartupBehavior::EmptyTab
23370        {
23371            let buffer_snapshot = OnceCell::new();
23372
23373            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23374                && !folds.is_empty()
23375            {
23376                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23377                let snapshot_len = snapshot.len().0;
23378
23379                // Helper: search for fingerprint in buffer, return offset if found
23380                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
23381                    // Ensure we start at a character boundary (defensive)
23382                    let search_start = snapshot
23383                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
23384                        .0;
23385                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
23386
23387                    let mut byte_offset = search_start;
23388                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
23389                        if byte_offset > search_end {
23390                            break;
23391                        }
23392                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
23393                            return Some(byte_offset);
23394                        }
23395                        byte_offset += ch.len_utf8();
23396                    }
23397                    None
23398                };
23399
23400                // Track search position to handle duplicate fingerprints correctly.
23401                // Folds are stored in document order, so we advance after each match.
23402                let mut search_start = 0usize;
23403
23404                let valid_folds: Vec<_> = folds
23405                    .into_iter()
23406                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
23407                        // Skip folds without fingerprints (old data before migration)
23408                        let sfp = start_fp?;
23409                        let efp = end_fp?;
23410                        let efp_len = efp.len();
23411
23412                        // Fast path: check if fingerprints match at stored offsets
23413                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
23414                        let start_matches = stored_start < snapshot_len
23415                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
23416                        let efp_check_pos = stored_end.saturating_sub(efp_len);
23417                        let end_matches = efp_check_pos >= stored_start
23418                            && stored_end <= snapshot_len
23419                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
23420
23421                        let (new_start, new_end) = if start_matches && end_matches {
23422                            // Offsets unchanged, use stored values
23423                            (stored_start, stored_end)
23424                        } else if sfp == efp {
23425                            // Short fold: identical fingerprints can only match once per search
23426                            // Use stored fold length to compute new_end
23427                            let new_start = find_fingerprint(&sfp, search_start)?;
23428                            let fold_len = stored_end - stored_start;
23429                            let new_end = new_start + fold_len;
23430                            (new_start, new_end)
23431                        } else {
23432                            // Slow path: search for fingerprints in buffer
23433                            let new_start = find_fingerprint(&sfp, search_start)?;
23434                            // Search for end_fp after start, then add efp_len to get actual fold end
23435                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
23436                            let new_end = efp_pos + efp_len;
23437                            (new_start, new_end)
23438                        };
23439
23440                        // Advance search position for next fold
23441                        search_start = new_end;
23442
23443                        // Validate fold makes sense (end must be after start)
23444                        if new_end <= new_start {
23445                            return None;
23446                        }
23447
23448                        Some(
23449                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
23450                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
23451                        )
23452                    })
23453                    .collect();
23454
23455                if !valid_folds.is_empty() {
23456                    self.fold_ranges(valid_folds, false, window, cx);
23457
23458                    // Migrate folds to current entity_id before workspace cleanup runs.
23459                    // Entity IDs change between sessions, but workspace cleanup deletes
23460                    // old editor rows (cascading to folds) based on current entity IDs.
23461                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
23462                    if new_editor_id != item_id {
23463                        cx.spawn(async move |_, _| {
23464                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
23465                                .await
23466                                .log_err();
23467                        })
23468                        .detach();
23469                    }
23470                }
23471            }
23472
23473            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23474                && !selections.is_empty()
23475            {
23476                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23477                // skip adding the initial selection to selection history
23478                self.selection_history.mode = SelectionHistoryMode::Skipping;
23479                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23480                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23481                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23482                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23483                    }));
23484                });
23485                self.selection_history.mode = SelectionHistoryMode::Normal;
23486            };
23487        }
23488
23489        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23490    }
23491
23492    fn update_lsp_data(
23493        &mut self,
23494        for_buffer: Option<BufferId>,
23495        window: &mut Window,
23496        cx: &mut Context<'_, Self>,
23497    ) {
23498        self.pull_diagnostics(for_buffer, window, cx);
23499        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23500    }
23501
23502    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23503        if self.ignore_lsp_data() {
23504            return;
23505        }
23506        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23507            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23508        }
23509    }
23510
23511    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23512        if self.ignore_lsp_data() {
23513            return;
23514        }
23515
23516        if !self.registered_buffers.contains_key(&buffer_id)
23517            && let Some(project) = self.project.as_ref()
23518        {
23519            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23520                project.update(cx, |project, cx| {
23521                    self.registered_buffers.insert(
23522                        buffer_id,
23523                        project.register_buffer_with_language_servers(&buffer, cx),
23524                    );
23525                });
23526            } else {
23527                self.registered_buffers.remove(&buffer_id);
23528            }
23529        }
23530    }
23531
23532    fn ignore_lsp_data(&self) -> bool {
23533        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23534        // skip any LSP updates for it.
23535        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23536    }
23537
23538    fn create_style(&self, cx: &App) -> EditorStyle {
23539        let settings = ThemeSettings::get_global(cx);
23540
23541        let mut text_style = match self.mode {
23542            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23543                color: cx.theme().colors().editor_foreground,
23544                font_family: settings.ui_font.family.clone(),
23545                font_features: settings.ui_font.features.clone(),
23546                font_fallbacks: settings.ui_font.fallbacks.clone(),
23547                font_size: rems(0.875).into(),
23548                font_weight: settings.ui_font.weight,
23549                line_height: relative(settings.buffer_line_height.value()),
23550                ..Default::default()
23551            },
23552            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23553                color: cx.theme().colors().editor_foreground,
23554                font_family: settings.buffer_font.family.clone(),
23555                font_features: settings.buffer_font.features.clone(),
23556                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23557                font_size: settings.buffer_font_size(cx).into(),
23558                font_weight: settings.buffer_font.weight,
23559                line_height: relative(settings.buffer_line_height.value()),
23560                ..Default::default()
23561            },
23562        };
23563        if let Some(text_style_refinement) = &self.text_style_refinement {
23564            text_style.refine(text_style_refinement)
23565        }
23566
23567        let background = match self.mode {
23568            EditorMode::SingleLine => cx.theme().system().transparent,
23569            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23570            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23571            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23572        };
23573
23574        EditorStyle {
23575            background,
23576            border: cx.theme().colors().border,
23577            local_player: cx.theme().players().local(),
23578            text: text_style,
23579            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23580            syntax: cx.theme().syntax().clone(),
23581            status: cx.theme().status().clone(),
23582            inlay_hints_style: make_inlay_hints_style(cx),
23583            edit_prediction_styles: make_suggestion_styles(cx),
23584            unnecessary_code_fade: settings.unnecessary_code_fade,
23585            show_underlines: self.diagnostics_enabled(),
23586        }
23587    }
23588    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23589        let cursor = self.selections.newest_anchor().head();
23590        let multibuffer = self.buffer().read(cx);
23591        let is_singleton = multibuffer.is_singleton();
23592        let (buffer_id, symbols) = multibuffer
23593            .read(cx)
23594            .symbols_containing(cursor, Some(variant.syntax()))?;
23595        let buffer = multibuffer.buffer(buffer_id)?;
23596
23597        let buffer = buffer.read(cx);
23598        let settings = ThemeSettings::get_global(cx);
23599        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23600        let mut breadcrumbs = if is_singleton {
23601            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23602                buffer
23603                    .snapshot()
23604                    .resolve_file_path(
23605                        self.project
23606                            .as_ref()
23607                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23608                            .unwrap_or_default(),
23609                        cx,
23610                    )
23611                    .unwrap_or_else(|| {
23612                        if multibuffer.is_singleton() {
23613                            multibuffer.title(cx).to_string()
23614                        } else {
23615                            "untitled".to_string()
23616                        }
23617                    })
23618            });
23619            vec![BreadcrumbText {
23620                text,
23621                highlights: None,
23622                font: Some(settings.buffer_font.clone()),
23623            }]
23624        } else {
23625            vec![]
23626        };
23627
23628        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23629            text: symbol.text,
23630            highlights: Some(symbol.highlight_ranges),
23631            font: Some(settings.buffer_font.clone()),
23632        }));
23633        Some(breadcrumbs)
23634    }
23635}
23636
23637fn edit_for_markdown_paste<'a>(
23638    buffer: &MultiBufferSnapshot,
23639    range: Range<MultiBufferOffset>,
23640    to_insert: &'a str,
23641    url: Option<url::Url>,
23642) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23643    if url.is_none() {
23644        return (range, Cow::Borrowed(to_insert));
23645    };
23646
23647    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23648
23649    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23650        Cow::Borrowed(to_insert)
23651    } else {
23652        Cow::Owned(format!("[{old_text}]({to_insert})"))
23653    };
23654    (range, new_text)
23655}
23656
23657fn process_completion_for_edit(
23658    completion: &Completion,
23659    intent: CompletionIntent,
23660    buffer: &Entity<Buffer>,
23661    cursor_position: &text::Anchor,
23662    cx: &mut Context<Editor>,
23663) -> CompletionEdit {
23664    let buffer = buffer.read(cx);
23665    let buffer_snapshot = buffer.snapshot();
23666    let (snippet, new_text) = if completion.is_snippet() {
23667        let mut snippet_source = completion.new_text.clone();
23668        // Workaround for typescript language server issues so that methods don't expand within
23669        // strings and functions with type expressions. The previous point is used because the query
23670        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23671        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23672        let previous_point = if previous_point.column > 0 {
23673            cursor_position.to_previous_offset(&buffer_snapshot)
23674        } else {
23675            cursor_position.to_offset(&buffer_snapshot)
23676        };
23677        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23678            && scope.prefers_label_for_snippet_in_completion()
23679            && let Some(label) = completion.label()
23680            && matches!(
23681                completion.kind(),
23682                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23683            )
23684        {
23685            snippet_source = label;
23686        }
23687        match Snippet::parse(&snippet_source).log_err() {
23688            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23689            None => (None, completion.new_text.clone()),
23690        }
23691    } else {
23692        (None, completion.new_text.clone())
23693    };
23694
23695    let mut range_to_replace = {
23696        let replace_range = &completion.replace_range;
23697        if let CompletionSource::Lsp {
23698            insert_range: Some(insert_range),
23699            ..
23700        } = &completion.source
23701        {
23702            debug_assert_eq!(
23703                insert_range.start, replace_range.start,
23704                "insert_range and replace_range should start at the same position"
23705            );
23706            debug_assert!(
23707                insert_range
23708                    .start
23709                    .cmp(cursor_position, &buffer_snapshot)
23710                    .is_le(),
23711                "insert_range should start before or at cursor position"
23712            );
23713            debug_assert!(
23714                replace_range
23715                    .start
23716                    .cmp(cursor_position, &buffer_snapshot)
23717                    .is_le(),
23718                "replace_range should start before or at cursor position"
23719            );
23720
23721            let should_replace = match intent {
23722                CompletionIntent::CompleteWithInsert => false,
23723                CompletionIntent::CompleteWithReplace => true,
23724                CompletionIntent::Complete | CompletionIntent::Compose => {
23725                    let insert_mode =
23726                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23727                            .completions
23728                            .lsp_insert_mode;
23729                    match insert_mode {
23730                        LspInsertMode::Insert => false,
23731                        LspInsertMode::Replace => true,
23732                        LspInsertMode::ReplaceSubsequence => {
23733                            let mut text_to_replace = buffer.chars_for_range(
23734                                buffer.anchor_before(replace_range.start)
23735                                    ..buffer.anchor_after(replace_range.end),
23736                            );
23737                            let mut current_needle = text_to_replace.next();
23738                            for haystack_ch in completion.label.text.chars() {
23739                                if let Some(needle_ch) = current_needle
23740                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23741                                {
23742                                    current_needle = text_to_replace.next();
23743                                }
23744                            }
23745                            current_needle.is_none()
23746                        }
23747                        LspInsertMode::ReplaceSuffix => {
23748                            if replace_range
23749                                .end
23750                                .cmp(cursor_position, &buffer_snapshot)
23751                                .is_gt()
23752                            {
23753                                let range_after_cursor = *cursor_position..replace_range.end;
23754                                let text_after_cursor = buffer
23755                                    .text_for_range(
23756                                        buffer.anchor_before(range_after_cursor.start)
23757                                            ..buffer.anchor_after(range_after_cursor.end),
23758                                    )
23759                                    .collect::<String>()
23760                                    .to_ascii_lowercase();
23761                                completion
23762                                    .label
23763                                    .text
23764                                    .to_ascii_lowercase()
23765                                    .ends_with(&text_after_cursor)
23766                            } else {
23767                                true
23768                            }
23769                        }
23770                    }
23771                }
23772            };
23773
23774            if should_replace {
23775                replace_range.clone()
23776            } else {
23777                insert_range.clone()
23778            }
23779        } else {
23780            replace_range.clone()
23781        }
23782    };
23783
23784    if range_to_replace
23785        .end
23786        .cmp(cursor_position, &buffer_snapshot)
23787        .is_lt()
23788    {
23789        range_to_replace.end = *cursor_position;
23790    }
23791
23792    let replace_range = range_to_replace.to_offset(buffer);
23793    CompletionEdit {
23794        new_text,
23795        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23796        snippet,
23797    }
23798}
23799
23800struct CompletionEdit {
23801    new_text: String,
23802    replace_range: Range<BufferOffset>,
23803    snippet: Option<Snippet>,
23804}
23805
23806fn comment_delimiter_for_newline(
23807    start_point: &Point,
23808    buffer: &MultiBufferSnapshot,
23809    language: &LanguageScope,
23810) -> Option<Arc<str>> {
23811    let delimiters = language.line_comment_prefixes();
23812    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23813    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23814
23815    let num_of_whitespaces = snapshot
23816        .chars_for_range(range.clone())
23817        .take_while(|c| c.is_whitespace())
23818        .count();
23819    let comment_candidate = snapshot
23820        .chars_for_range(range.clone())
23821        .skip(num_of_whitespaces)
23822        .take(max_len_of_delimiter)
23823        .collect::<String>();
23824    let (delimiter, trimmed_len) = delimiters
23825        .iter()
23826        .filter_map(|delimiter| {
23827            let prefix = delimiter.trim_end();
23828            if comment_candidate.starts_with(prefix) {
23829                Some((delimiter, prefix.len()))
23830            } else {
23831                None
23832            }
23833        })
23834        .max_by_key(|(_, len)| *len)?;
23835
23836    if let Some(BlockCommentConfig {
23837        start: block_start, ..
23838    }) = language.block_comment()
23839    {
23840        let block_start_trimmed = block_start.trim_end();
23841        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23842            let line_content = snapshot
23843                .chars_for_range(range)
23844                .skip(num_of_whitespaces)
23845                .take(block_start_trimmed.len())
23846                .collect::<String>();
23847
23848            if line_content.starts_with(block_start_trimmed) {
23849                return None;
23850            }
23851        }
23852    }
23853
23854    let cursor_is_placed_after_comment_marker =
23855        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23856    if cursor_is_placed_after_comment_marker {
23857        Some(delimiter.clone())
23858    } else {
23859        None
23860    }
23861}
23862
23863fn documentation_delimiter_for_newline(
23864    start_point: &Point,
23865    buffer: &MultiBufferSnapshot,
23866    language: &LanguageScope,
23867    newline_config: &mut NewlineConfig,
23868) -> Option<Arc<str>> {
23869    let BlockCommentConfig {
23870        start: start_tag,
23871        end: end_tag,
23872        prefix: delimiter,
23873        tab_size: len,
23874    } = language.documentation_comment()?;
23875    let is_within_block_comment = buffer
23876        .language_scope_at(*start_point)
23877        .is_some_and(|scope| scope.override_name() == Some("comment"));
23878    if !is_within_block_comment {
23879        return None;
23880    }
23881
23882    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23883
23884    let num_of_whitespaces = snapshot
23885        .chars_for_range(range.clone())
23886        .take_while(|c| c.is_whitespace())
23887        .count();
23888
23889    // 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.
23890    let column = start_point.column;
23891    let cursor_is_after_start_tag = {
23892        let start_tag_len = start_tag.len();
23893        let start_tag_line = snapshot
23894            .chars_for_range(range.clone())
23895            .skip(num_of_whitespaces)
23896            .take(start_tag_len)
23897            .collect::<String>();
23898        if start_tag_line.starts_with(start_tag.as_ref()) {
23899            num_of_whitespaces + start_tag_len <= column as usize
23900        } else {
23901            false
23902        }
23903    };
23904
23905    let cursor_is_after_delimiter = {
23906        let delimiter_trim = delimiter.trim_end();
23907        let delimiter_line = snapshot
23908            .chars_for_range(range.clone())
23909            .skip(num_of_whitespaces)
23910            .take(delimiter_trim.len())
23911            .collect::<String>();
23912        if delimiter_line.starts_with(delimiter_trim) {
23913            num_of_whitespaces + delimiter_trim.len() <= column as usize
23914        } else {
23915            false
23916        }
23917    };
23918
23919    let mut needs_extra_line = false;
23920    let mut extra_line_additional_indent = IndentSize::spaces(0);
23921
23922    let cursor_is_before_end_tag_if_exists = {
23923        let mut char_position = 0u32;
23924        let mut end_tag_offset = None;
23925
23926        'outer: for chunk in snapshot.text_for_range(range) {
23927            if let Some(byte_pos) = chunk.find(&**end_tag) {
23928                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23929                end_tag_offset = Some(char_position + chars_before_match);
23930                break 'outer;
23931            }
23932            char_position += chunk.chars().count() as u32;
23933        }
23934
23935        if let Some(end_tag_offset) = end_tag_offset {
23936            let cursor_is_before_end_tag = column <= end_tag_offset;
23937            if cursor_is_after_start_tag {
23938                if cursor_is_before_end_tag {
23939                    needs_extra_line = true;
23940                }
23941                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23942                if cursor_is_at_start_of_end_tag {
23943                    extra_line_additional_indent.len = *len;
23944                }
23945            }
23946            cursor_is_before_end_tag
23947        } else {
23948            true
23949        }
23950    };
23951
23952    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23953        && cursor_is_before_end_tag_if_exists
23954    {
23955        let additional_indent = if cursor_is_after_start_tag {
23956            IndentSize::spaces(*len)
23957        } else {
23958            IndentSize::spaces(0)
23959        };
23960
23961        *newline_config = NewlineConfig::Newline {
23962            additional_indent,
23963            extra_line_additional_indent: if needs_extra_line {
23964                Some(extra_line_additional_indent)
23965            } else {
23966                None
23967            },
23968            prevent_auto_indent: true,
23969        };
23970        Some(delimiter.clone())
23971    } else {
23972        None
23973    }
23974}
23975
23976const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23977
23978fn list_delimiter_for_newline(
23979    start_point: &Point,
23980    buffer: &MultiBufferSnapshot,
23981    language: &LanguageScope,
23982    newline_config: &mut NewlineConfig,
23983) -> Option<Arc<str>> {
23984    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23985
23986    let num_of_whitespaces = snapshot
23987        .chars_for_range(range.clone())
23988        .take_while(|c| c.is_whitespace())
23989        .count();
23990
23991    let task_list_entries: Vec<_> = language
23992        .task_list()
23993        .into_iter()
23994        .flat_map(|config| {
23995            config
23996                .prefixes
23997                .iter()
23998                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23999        })
24000        .collect();
24001    let unordered_list_entries: Vec<_> = language
24002        .unordered_list()
24003        .iter()
24004        .map(|marker| (marker.as_ref(), marker.as_ref()))
24005        .collect();
24006
24007    let all_entries: Vec<_> = task_list_entries
24008        .into_iter()
24009        .chain(unordered_list_entries)
24010        .collect();
24011
24012    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
24013        let candidate: String = snapshot
24014            .chars_for_range(range.clone())
24015            .skip(num_of_whitespaces)
24016            .take(max_prefix_len)
24017            .collect();
24018
24019        if let Some((prefix, continuation)) = all_entries
24020            .iter()
24021            .filter(|(prefix, _)| candidate.starts_with(*prefix))
24022            .max_by_key(|(prefix, _)| prefix.len())
24023        {
24024            let end_of_prefix = num_of_whitespaces + prefix.len();
24025            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
24026            let has_content_after_marker = snapshot
24027                .chars_for_range(range)
24028                .skip(end_of_prefix)
24029                .any(|c| !c.is_whitespace());
24030
24031            if has_content_after_marker && cursor_is_after_prefix {
24032                return Some((*continuation).into());
24033            }
24034
24035            if start_point.column as usize == end_of_prefix {
24036                if num_of_whitespaces == 0 {
24037                    *newline_config = NewlineConfig::ClearCurrentLine;
24038                } else {
24039                    *newline_config = NewlineConfig::UnindentCurrentLine {
24040                        continuation: (*continuation).into(),
24041                    };
24042                }
24043            }
24044
24045            return None;
24046        }
24047    }
24048
24049    let candidate: String = snapshot
24050        .chars_for_range(range.clone())
24051        .skip(num_of_whitespaces)
24052        .take(ORDERED_LIST_MAX_MARKER_LEN)
24053        .collect();
24054
24055    for ordered_config in language.ordered_list() {
24056        let regex = match Regex::new(&ordered_config.pattern) {
24057            Ok(r) => r,
24058            Err(_) => continue,
24059        };
24060
24061        if let Some(captures) = regex.captures(&candidate) {
24062            let full_match = captures.get(0)?;
24063            let marker_len = full_match.len();
24064            let end_of_prefix = num_of_whitespaces + marker_len;
24065            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
24066
24067            let has_content_after_marker = snapshot
24068                .chars_for_range(range)
24069                .skip(end_of_prefix)
24070                .any(|c| !c.is_whitespace());
24071
24072            if has_content_after_marker && cursor_is_after_prefix {
24073                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
24074                let continuation = ordered_config
24075                    .format
24076                    .replace("{1}", &(number + 1).to_string());
24077                return Some(continuation.into());
24078            }
24079
24080            if start_point.column as usize == end_of_prefix {
24081                let continuation = ordered_config.format.replace("{1}", "1");
24082                if num_of_whitespaces == 0 {
24083                    *newline_config = NewlineConfig::ClearCurrentLine;
24084                } else {
24085                    *newline_config = NewlineConfig::UnindentCurrentLine {
24086                        continuation: continuation.into(),
24087                    };
24088                }
24089            }
24090
24091            return None;
24092        }
24093    }
24094
24095    None
24096}
24097
24098fn is_list_prefix_row(
24099    row: MultiBufferRow,
24100    buffer: &MultiBufferSnapshot,
24101    language: &LanguageScope,
24102) -> bool {
24103    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
24104        return false;
24105    };
24106
24107    let num_of_whitespaces = snapshot
24108        .chars_for_range(range.clone())
24109        .take_while(|c| c.is_whitespace())
24110        .count();
24111
24112    let task_list_prefixes: Vec<_> = language
24113        .task_list()
24114        .into_iter()
24115        .flat_map(|config| {
24116            config
24117                .prefixes
24118                .iter()
24119                .map(|p| p.as_ref())
24120                .collect::<Vec<_>>()
24121        })
24122        .collect();
24123    let unordered_list_markers: Vec<_> = language
24124        .unordered_list()
24125        .iter()
24126        .map(|marker| marker.as_ref())
24127        .collect();
24128    let all_prefixes: Vec<_> = task_list_prefixes
24129        .into_iter()
24130        .chain(unordered_list_markers)
24131        .collect();
24132    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
24133        let candidate: String = snapshot
24134            .chars_for_range(range.clone())
24135            .skip(num_of_whitespaces)
24136            .take(max_prefix_len)
24137            .collect();
24138        if all_prefixes
24139            .iter()
24140            .any(|prefix| candidate.starts_with(*prefix))
24141        {
24142            return true;
24143        }
24144    }
24145
24146    let ordered_list_candidate: String = snapshot
24147        .chars_for_range(range)
24148        .skip(num_of_whitespaces)
24149        .take(ORDERED_LIST_MAX_MARKER_LEN)
24150        .collect();
24151    for ordered_config in language.ordered_list() {
24152        let regex = match Regex::new(&ordered_config.pattern) {
24153            Ok(r) => r,
24154            Err(_) => continue,
24155        };
24156        if let Some(captures) = regex.captures(&ordered_list_candidate) {
24157            return captures.get(0).is_some();
24158        }
24159    }
24160
24161    false
24162}
24163
24164#[derive(Debug)]
24165enum NewlineConfig {
24166    /// Insert newline with optional additional indent and optional extra blank line
24167    Newline {
24168        additional_indent: IndentSize,
24169        extra_line_additional_indent: Option<IndentSize>,
24170        prevent_auto_indent: bool,
24171    },
24172    /// Clear the current line
24173    ClearCurrentLine,
24174    /// Unindent the current line and add continuation
24175    UnindentCurrentLine { continuation: Arc<str> },
24176}
24177
24178impl NewlineConfig {
24179    fn has_extra_line(&self) -> bool {
24180        matches!(
24181            self,
24182            Self::Newline {
24183                extra_line_additional_indent: Some(_),
24184                ..
24185            }
24186        )
24187    }
24188
24189    fn insert_extra_newline_brackets(
24190        buffer: &MultiBufferSnapshot,
24191        range: Range<MultiBufferOffset>,
24192        language: &language::LanguageScope,
24193    ) -> bool {
24194        let leading_whitespace_len = buffer
24195            .reversed_chars_at(range.start)
24196            .take_while(|c| c.is_whitespace() && *c != '\n')
24197            .map(|c| c.len_utf8())
24198            .sum::<usize>();
24199        let trailing_whitespace_len = buffer
24200            .chars_at(range.end)
24201            .take_while(|c| c.is_whitespace() && *c != '\n')
24202            .map(|c| c.len_utf8())
24203            .sum::<usize>();
24204        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
24205
24206        language.brackets().any(|(pair, enabled)| {
24207            let pair_start = pair.start.trim_end();
24208            let pair_end = pair.end.trim_start();
24209
24210            enabled
24211                && pair.newline
24212                && buffer.contains_str_at(range.end, pair_end)
24213                && buffer.contains_str_at(
24214                    range.start.saturating_sub_usize(pair_start.len()),
24215                    pair_start,
24216                )
24217        })
24218    }
24219
24220    fn insert_extra_newline_tree_sitter(
24221        buffer: &MultiBufferSnapshot,
24222        range: Range<MultiBufferOffset>,
24223    ) -> bool {
24224        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
24225            [(buffer, range, _)] => (*buffer, range.clone()),
24226            _ => return false,
24227        };
24228        let pair = {
24229            let mut result: Option<BracketMatch<usize>> = None;
24230
24231            for pair in buffer
24232                .all_bracket_ranges(range.start.0..range.end.0)
24233                .filter(move |pair| {
24234                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
24235                })
24236            {
24237                let len = pair.close_range.end - pair.open_range.start;
24238
24239                if let Some(existing) = &result {
24240                    let existing_len = existing.close_range.end - existing.open_range.start;
24241                    if len > existing_len {
24242                        continue;
24243                    }
24244                }
24245
24246                result = Some(pair);
24247            }
24248
24249            result
24250        };
24251        let Some(pair) = pair else {
24252            return false;
24253        };
24254        pair.newline_only
24255            && buffer
24256                .chars_for_range(pair.open_range.end..range.start.0)
24257                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
24258                .all(|c| c.is_whitespace() && c != '\n')
24259    }
24260}
24261
24262fn update_uncommitted_diff_for_buffer(
24263    editor: Entity<Editor>,
24264    project: &Entity<Project>,
24265    buffers: impl IntoIterator<Item = Entity<Buffer>>,
24266    buffer: Entity<MultiBuffer>,
24267    cx: &mut App,
24268) -> Task<()> {
24269    let mut tasks = Vec::new();
24270    project.update(cx, |project, cx| {
24271        for buffer in buffers {
24272            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
24273                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
24274            }
24275        }
24276    });
24277    cx.spawn(async move |cx| {
24278        let diffs = future::join_all(tasks).await;
24279        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
24280            return;
24281        }
24282
24283        buffer.update(cx, |buffer, cx| {
24284            for diff in diffs.into_iter().flatten() {
24285                buffer.add_diff(diff, cx);
24286            }
24287        });
24288    })
24289}
24290
24291fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
24292    let tab_size = tab_size.get() as usize;
24293    let mut width = offset;
24294
24295    for ch in text.chars() {
24296        width += if ch == '\t' {
24297            tab_size - (width % tab_size)
24298        } else {
24299            1
24300        };
24301    }
24302
24303    width - offset
24304}
24305
24306#[cfg(test)]
24307mod tests {
24308    use super::*;
24309
24310    #[test]
24311    fn test_string_size_with_expanded_tabs() {
24312        let nz = |val| NonZeroU32::new(val).unwrap();
24313        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24314        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24315        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24316        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24317        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24318        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24319        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24320        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24321    }
24322}
24323
24324/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24325struct WordBreakingTokenizer<'a> {
24326    input: &'a str,
24327}
24328
24329impl<'a> WordBreakingTokenizer<'a> {
24330    fn new(input: &'a str) -> Self {
24331        Self { input }
24332    }
24333}
24334
24335fn is_char_ideographic(ch: char) -> bool {
24336    use unicode_script::Script::*;
24337    use unicode_script::UnicodeScript;
24338    matches!(ch.script(), Han | Tangut | Yi)
24339}
24340
24341fn is_grapheme_ideographic(text: &str) -> bool {
24342    text.chars().any(is_char_ideographic)
24343}
24344
24345fn is_grapheme_whitespace(text: &str) -> bool {
24346    text.chars().any(|x| x.is_whitespace())
24347}
24348
24349fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24350    text.chars()
24351        .next()
24352        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24353}
24354
24355#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24356enum WordBreakToken<'a> {
24357    Word { token: &'a str, grapheme_len: usize },
24358    InlineWhitespace { token: &'a str, grapheme_len: usize },
24359    Newline,
24360}
24361
24362impl<'a> Iterator for WordBreakingTokenizer<'a> {
24363    /// Yields a span, the count of graphemes in the token, and whether it was
24364    /// whitespace. Note that it also breaks at word boundaries.
24365    type Item = WordBreakToken<'a>;
24366
24367    fn next(&mut self) -> Option<Self::Item> {
24368        use unicode_segmentation::UnicodeSegmentation;
24369        if self.input.is_empty() {
24370            return None;
24371        }
24372
24373        let mut iter = self.input.graphemes(true).peekable();
24374        let mut offset = 0;
24375        let mut grapheme_len = 0;
24376        if let Some(first_grapheme) = iter.next() {
24377            let is_newline = first_grapheme == "\n";
24378            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24379            offset += first_grapheme.len();
24380            grapheme_len += 1;
24381            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24382                if let Some(grapheme) = iter.peek().copied()
24383                    && should_stay_with_preceding_ideograph(grapheme)
24384                {
24385                    offset += grapheme.len();
24386                    grapheme_len += 1;
24387                }
24388            } else {
24389                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24390                let mut next_word_bound = words.peek().copied();
24391                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24392                    next_word_bound = words.next();
24393                }
24394                while let Some(grapheme) = iter.peek().copied() {
24395                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24396                        break;
24397                    };
24398                    if is_grapheme_whitespace(grapheme) != is_whitespace
24399                        || (grapheme == "\n") != is_newline
24400                    {
24401                        break;
24402                    };
24403                    offset += grapheme.len();
24404                    grapheme_len += 1;
24405                    iter.next();
24406                }
24407            }
24408            let token = &self.input[..offset];
24409            self.input = &self.input[offset..];
24410            if token == "\n" {
24411                Some(WordBreakToken::Newline)
24412            } else if is_whitespace {
24413                Some(WordBreakToken::InlineWhitespace {
24414                    token,
24415                    grapheme_len,
24416                })
24417            } else {
24418                Some(WordBreakToken::Word {
24419                    token,
24420                    grapheme_len,
24421                })
24422            }
24423        } else {
24424            None
24425        }
24426    }
24427}
24428
24429#[test]
24430fn test_word_breaking_tokenizer() {
24431    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24432        ("", &[]),
24433        ("  ", &[whitespace("  ", 2)]),
24434        ("Ʒ", &[word("Ʒ", 1)]),
24435        ("Ǽ", &[word("Ǽ", 1)]),
24436        ("", &[word("", 1)]),
24437        ("⋑⋑", &[word("⋑⋑", 2)]),
24438        (
24439            "原理,进而",
24440            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24441        ),
24442        (
24443            "hello world",
24444            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24445        ),
24446        (
24447            "hello, world",
24448            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24449        ),
24450        (
24451            "  hello world",
24452            &[
24453                whitespace("  ", 2),
24454                word("hello", 5),
24455                whitespace(" ", 1),
24456                word("world", 5),
24457            ],
24458        ),
24459        (
24460            "这是什么 \n 钢笔",
24461            &[
24462                word("", 1),
24463                word("", 1),
24464                word("", 1),
24465                word("", 1),
24466                whitespace(" ", 1),
24467                newline(),
24468                whitespace(" ", 1),
24469                word("", 1),
24470                word("", 1),
24471            ],
24472        ),
24473        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24474    ];
24475
24476    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24477        WordBreakToken::Word {
24478            token,
24479            grapheme_len,
24480        }
24481    }
24482
24483    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24484        WordBreakToken::InlineWhitespace {
24485            token,
24486            grapheme_len,
24487        }
24488    }
24489
24490    fn newline() -> WordBreakToken<'static> {
24491        WordBreakToken::Newline
24492    }
24493
24494    for (input, result) in tests {
24495        assert_eq!(
24496            WordBreakingTokenizer::new(input)
24497                .collect::<Vec<_>>()
24498                .as_slice(),
24499            *result,
24500        );
24501    }
24502}
24503
24504fn wrap_with_prefix(
24505    first_line_prefix: String,
24506    subsequent_lines_prefix: String,
24507    unwrapped_text: String,
24508    wrap_column: usize,
24509    tab_size: NonZeroU32,
24510    preserve_existing_whitespace: bool,
24511) -> String {
24512    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24513    let subsequent_lines_prefix_len =
24514        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24515    let mut wrapped_text = String::new();
24516    let mut current_line = first_line_prefix;
24517    let mut is_first_line = true;
24518
24519    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24520    let mut current_line_len = first_line_prefix_len;
24521    let mut in_whitespace = false;
24522    for token in tokenizer {
24523        let have_preceding_whitespace = in_whitespace;
24524        match token {
24525            WordBreakToken::Word {
24526                token,
24527                grapheme_len,
24528            } => {
24529                in_whitespace = false;
24530                let current_prefix_len = if is_first_line {
24531                    first_line_prefix_len
24532                } else {
24533                    subsequent_lines_prefix_len
24534                };
24535                if current_line_len + grapheme_len > wrap_column
24536                    && current_line_len != current_prefix_len
24537                {
24538                    wrapped_text.push_str(current_line.trim_end());
24539                    wrapped_text.push('\n');
24540                    is_first_line = false;
24541                    current_line = subsequent_lines_prefix.clone();
24542                    current_line_len = subsequent_lines_prefix_len;
24543                }
24544                current_line.push_str(token);
24545                current_line_len += grapheme_len;
24546            }
24547            WordBreakToken::InlineWhitespace {
24548                mut token,
24549                mut grapheme_len,
24550            } => {
24551                in_whitespace = true;
24552                if have_preceding_whitespace && !preserve_existing_whitespace {
24553                    continue;
24554                }
24555                if !preserve_existing_whitespace {
24556                    // Keep a single whitespace grapheme as-is
24557                    if let Some(first) =
24558                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24559                    {
24560                        token = first;
24561                    } else {
24562                        token = " ";
24563                    }
24564                    grapheme_len = 1;
24565                }
24566                let current_prefix_len = if is_first_line {
24567                    first_line_prefix_len
24568                } else {
24569                    subsequent_lines_prefix_len
24570                };
24571                if current_line_len + grapheme_len > wrap_column {
24572                    wrapped_text.push_str(current_line.trim_end());
24573                    wrapped_text.push('\n');
24574                    is_first_line = false;
24575                    current_line = subsequent_lines_prefix.clone();
24576                    current_line_len = subsequent_lines_prefix_len;
24577                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24578                    current_line.push_str(token);
24579                    current_line_len += grapheme_len;
24580                }
24581            }
24582            WordBreakToken::Newline => {
24583                in_whitespace = true;
24584                let current_prefix_len = if is_first_line {
24585                    first_line_prefix_len
24586                } else {
24587                    subsequent_lines_prefix_len
24588                };
24589                if preserve_existing_whitespace {
24590                    wrapped_text.push_str(current_line.trim_end());
24591                    wrapped_text.push('\n');
24592                    is_first_line = false;
24593                    current_line = subsequent_lines_prefix.clone();
24594                    current_line_len = subsequent_lines_prefix_len;
24595                } else if have_preceding_whitespace {
24596                    continue;
24597                } else if current_line_len + 1 > wrap_column
24598                    && current_line_len != current_prefix_len
24599                {
24600                    wrapped_text.push_str(current_line.trim_end());
24601                    wrapped_text.push('\n');
24602                    is_first_line = false;
24603                    current_line = subsequent_lines_prefix.clone();
24604                    current_line_len = subsequent_lines_prefix_len;
24605                } else if current_line_len != current_prefix_len {
24606                    current_line.push(' ');
24607                    current_line_len += 1;
24608                }
24609            }
24610        }
24611    }
24612
24613    if !current_line.is_empty() {
24614        wrapped_text.push_str(&current_line);
24615    }
24616    wrapped_text
24617}
24618
24619#[test]
24620fn test_wrap_with_prefix() {
24621    assert_eq!(
24622        wrap_with_prefix(
24623            "# ".to_string(),
24624            "# ".to_string(),
24625            "abcdefg".to_string(),
24626            4,
24627            NonZeroU32::new(4).unwrap(),
24628            false,
24629        ),
24630        "# abcdefg"
24631    );
24632    assert_eq!(
24633        wrap_with_prefix(
24634            "".to_string(),
24635            "".to_string(),
24636            "\thello world".to_string(),
24637            8,
24638            NonZeroU32::new(4).unwrap(),
24639            false,
24640        ),
24641        "hello\nworld"
24642    );
24643    assert_eq!(
24644        wrap_with_prefix(
24645            "// ".to_string(),
24646            "// ".to_string(),
24647            "xx \nyy zz aa bb cc".to_string(),
24648            12,
24649            NonZeroU32::new(4).unwrap(),
24650            false,
24651        ),
24652        "// xx yy zz\n// aa bb cc"
24653    );
24654    assert_eq!(
24655        wrap_with_prefix(
24656            String::new(),
24657            String::new(),
24658            "这是什么 \n 钢笔".to_string(),
24659            3,
24660            NonZeroU32::new(4).unwrap(),
24661            false,
24662        ),
24663        "这是什\n么 钢\n"
24664    );
24665    assert_eq!(
24666        wrap_with_prefix(
24667            String::new(),
24668            String::new(),
24669            format!("foo{}bar", '\u{2009}'), // thin space
24670            80,
24671            NonZeroU32::new(4).unwrap(),
24672            false,
24673        ),
24674        format!("foo{}bar", '\u{2009}')
24675    );
24676}
24677
24678pub trait CollaborationHub {
24679    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24680    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24681    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24682}
24683
24684impl CollaborationHub for Entity<Project> {
24685    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24686        self.read(cx).collaborators()
24687    }
24688
24689    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24690        self.read(cx).user_store().read(cx).participant_indices()
24691    }
24692
24693    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24694        let this = self.read(cx);
24695        let user_ids = this.collaborators().values().map(|c| c.user_id);
24696        this.user_store().read(cx).participant_names(user_ids, cx)
24697    }
24698}
24699
24700pub trait SemanticsProvider {
24701    fn hover(
24702        &self,
24703        buffer: &Entity<Buffer>,
24704        position: text::Anchor,
24705        cx: &mut App,
24706    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24707
24708    fn inline_values(
24709        &self,
24710        buffer_handle: Entity<Buffer>,
24711        range: Range<text::Anchor>,
24712        cx: &mut App,
24713    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24714
24715    fn applicable_inlay_chunks(
24716        &self,
24717        buffer: &Entity<Buffer>,
24718        ranges: &[Range<text::Anchor>],
24719        cx: &mut App,
24720    ) -> Vec<Range<BufferRow>>;
24721
24722    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24723
24724    fn inlay_hints(
24725        &self,
24726        invalidate: InvalidationStrategy,
24727        buffer: Entity<Buffer>,
24728        ranges: Vec<Range<text::Anchor>>,
24729        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24730        cx: &mut App,
24731    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24732
24733    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24734
24735    fn document_highlights(
24736        &self,
24737        buffer: &Entity<Buffer>,
24738        position: text::Anchor,
24739        cx: &mut App,
24740    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24741
24742    fn definitions(
24743        &self,
24744        buffer: &Entity<Buffer>,
24745        position: text::Anchor,
24746        kind: GotoDefinitionKind,
24747        cx: &mut App,
24748    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24749
24750    fn range_for_rename(
24751        &self,
24752        buffer: &Entity<Buffer>,
24753        position: text::Anchor,
24754        cx: &mut App,
24755    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24756
24757    fn perform_rename(
24758        &self,
24759        buffer: &Entity<Buffer>,
24760        position: text::Anchor,
24761        new_name: String,
24762        cx: &mut App,
24763    ) -> Option<Task<Result<ProjectTransaction>>>;
24764}
24765
24766pub trait CompletionProvider {
24767    fn completions(
24768        &self,
24769        excerpt_id: ExcerptId,
24770        buffer: &Entity<Buffer>,
24771        buffer_position: text::Anchor,
24772        trigger: CompletionContext,
24773        window: &mut Window,
24774        cx: &mut Context<Editor>,
24775    ) -> Task<Result<Vec<CompletionResponse>>>;
24776
24777    fn resolve_completions(
24778        &self,
24779        _buffer: Entity<Buffer>,
24780        _completion_indices: Vec<usize>,
24781        _completions: Rc<RefCell<Box<[Completion]>>>,
24782        _cx: &mut Context<Editor>,
24783    ) -> Task<Result<bool>> {
24784        Task::ready(Ok(false))
24785    }
24786
24787    fn apply_additional_edits_for_completion(
24788        &self,
24789        _buffer: Entity<Buffer>,
24790        _completions: Rc<RefCell<Box<[Completion]>>>,
24791        _completion_index: usize,
24792        _push_to_history: bool,
24793        _cx: &mut Context<Editor>,
24794    ) -> Task<Result<Option<language::Transaction>>> {
24795        Task::ready(Ok(None))
24796    }
24797
24798    fn is_completion_trigger(
24799        &self,
24800        buffer: &Entity<Buffer>,
24801        position: language::Anchor,
24802        text: &str,
24803        trigger_in_words: bool,
24804        cx: &mut Context<Editor>,
24805    ) -> bool;
24806
24807    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24808
24809    fn sort_completions(&self) -> bool {
24810        true
24811    }
24812
24813    fn filter_completions(&self) -> bool {
24814        true
24815    }
24816
24817    fn show_snippets(&self) -> bool {
24818        false
24819    }
24820}
24821
24822pub trait CodeActionProvider {
24823    fn id(&self) -> Arc<str>;
24824
24825    fn code_actions(
24826        &self,
24827        buffer: &Entity<Buffer>,
24828        range: Range<text::Anchor>,
24829        window: &mut Window,
24830        cx: &mut App,
24831    ) -> Task<Result<Vec<CodeAction>>>;
24832
24833    fn apply_code_action(
24834        &self,
24835        buffer_handle: Entity<Buffer>,
24836        action: CodeAction,
24837        excerpt_id: ExcerptId,
24838        push_to_history: bool,
24839        window: &mut Window,
24840        cx: &mut App,
24841    ) -> Task<Result<ProjectTransaction>>;
24842}
24843
24844impl CodeActionProvider for Entity<Project> {
24845    fn id(&self) -> Arc<str> {
24846        "project".into()
24847    }
24848
24849    fn code_actions(
24850        &self,
24851        buffer: &Entity<Buffer>,
24852        range: Range<text::Anchor>,
24853        _window: &mut Window,
24854        cx: &mut App,
24855    ) -> Task<Result<Vec<CodeAction>>> {
24856        self.update(cx, |project, cx| {
24857            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24858            let code_actions = project.code_actions(buffer, range, None, cx);
24859            cx.background_spawn(async move {
24860                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24861                Ok(code_lens_actions
24862                    .context("code lens fetch")?
24863                    .into_iter()
24864                    .flatten()
24865                    .chain(
24866                        code_actions
24867                            .context("code action fetch")?
24868                            .into_iter()
24869                            .flatten(),
24870                    )
24871                    .collect())
24872            })
24873        })
24874    }
24875
24876    fn apply_code_action(
24877        &self,
24878        buffer_handle: Entity<Buffer>,
24879        action: CodeAction,
24880        _excerpt_id: ExcerptId,
24881        push_to_history: bool,
24882        _window: &mut Window,
24883        cx: &mut App,
24884    ) -> Task<Result<ProjectTransaction>> {
24885        self.update(cx, |project, cx| {
24886            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24887        })
24888    }
24889}
24890
24891fn snippet_completions(
24892    project: &Project,
24893    buffer: &Entity<Buffer>,
24894    buffer_anchor: text::Anchor,
24895    classifier: CharClassifier,
24896    cx: &mut App,
24897) -> Task<Result<CompletionResponse>> {
24898    let languages = buffer.read(cx).languages_at(buffer_anchor);
24899    let snippet_store = project.snippets().read(cx);
24900
24901    let scopes: Vec<_> = languages
24902        .iter()
24903        .filter_map(|language| {
24904            let language_name = language.lsp_id();
24905            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24906
24907            if snippets.is_empty() {
24908                None
24909            } else {
24910                Some((language.default_scope(), snippets))
24911            }
24912        })
24913        .collect();
24914
24915    if scopes.is_empty() {
24916        return Task::ready(Ok(CompletionResponse {
24917            completions: vec![],
24918            display_options: CompletionDisplayOptions::default(),
24919            is_incomplete: false,
24920        }));
24921    }
24922
24923    let snapshot = buffer.read(cx).text_snapshot();
24924    let executor = cx.background_executor().clone();
24925
24926    cx.background_spawn(async move {
24927        let is_word_char = |c| classifier.is_word(c);
24928
24929        let mut is_incomplete = false;
24930        let mut completions: Vec<Completion> = Vec::new();
24931
24932        const MAX_PREFIX_LEN: usize = 128;
24933        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24934        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24935        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24936
24937        let max_buffer_window: String = snapshot
24938            .text_for_range(window_start..buffer_offset)
24939            .collect();
24940
24941        if max_buffer_window.is_empty() {
24942            return Ok(CompletionResponse {
24943                completions: vec![],
24944                display_options: CompletionDisplayOptions::default(),
24945                is_incomplete: true,
24946            });
24947        }
24948
24949        for (_scope, snippets) in scopes.into_iter() {
24950            // Sort snippets by word count to match longer snippet prefixes first.
24951            let mut sorted_snippet_candidates = snippets
24952                .iter()
24953                .enumerate()
24954                .flat_map(|(snippet_ix, snippet)| {
24955                    snippet
24956                        .prefix
24957                        .iter()
24958                        .enumerate()
24959                        .map(move |(prefix_ix, prefix)| {
24960                            let word_count =
24961                                snippet_candidate_suffixes(prefix, is_word_char).count();
24962                            ((snippet_ix, prefix_ix), prefix, word_count)
24963                        })
24964                })
24965                .collect_vec();
24966            sorted_snippet_candidates
24967                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24968
24969            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24970
24971            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24972                .take(
24973                    sorted_snippet_candidates
24974                        .first()
24975                        .map(|(_, _, word_count)| *word_count)
24976                        .unwrap_or_default(),
24977                )
24978                .collect_vec();
24979
24980            const MAX_RESULTS: usize = 100;
24981            // Each match also remembers how many characters from the buffer it consumed
24982            let mut matches: Vec<(StringMatch, usize)> = vec![];
24983
24984            let mut snippet_list_cutoff_index = 0;
24985            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24986                let word_count = buffer_index + 1;
24987                // Increase `snippet_list_cutoff_index` until we have all of the
24988                // snippets with sufficiently many words.
24989                while sorted_snippet_candidates
24990                    .get(snippet_list_cutoff_index)
24991                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24992                        *snippet_word_count >= word_count
24993                    })
24994                {
24995                    snippet_list_cutoff_index += 1;
24996                }
24997
24998                // Take only the candidates with at least `word_count` many words
24999                let snippet_candidates_at_word_len =
25000                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
25001
25002                let candidates = snippet_candidates_at_word_len
25003                    .iter()
25004                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
25005                    .enumerate() // index in `sorted_snippet_candidates`
25006                    // First char must match
25007                    .filter(|(_ix, prefix)| {
25008                        itertools::equal(
25009                            prefix
25010                                .chars()
25011                                .next()
25012                                .into_iter()
25013                                .flat_map(|c| c.to_lowercase()),
25014                            buffer_window
25015                                .chars()
25016                                .next()
25017                                .into_iter()
25018                                .flat_map(|c| c.to_lowercase()),
25019                        )
25020                    })
25021                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
25022                    .collect::<Vec<StringMatchCandidate>>();
25023
25024                matches.extend(
25025                    fuzzy::match_strings(
25026                        &candidates,
25027                        &buffer_window,
25028                        buffer_window.chars().any(|c| c.is_uppercase()),
25029                        true,
25030                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
25031                        &Default::default(),
25032                        executor.clone(),
25033                    )
25034                    .await
25035                    .into_iter()
25036                    .map(|string_match| (string_match, buffer_window.len())),
25037                );
25038
25039                if matches.len() >= MAX_RESULTS {
25040                    break;
25041                }
25042            }
25043
25044            let to_lsp = |point: &text::Anchor| {
25045                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
25046                point_to_lsp(end)
25047            };
25048            let lsp_end = to_lsp(&buffer_anchor);
25049
25050            if matches.len() >= MAX_RESULTS {
25051                is_incomplete = true;
25052            }
25053
25054            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
25055                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
25056                    sorted_snippet_candidates[string_match.candidate_id];
25057                let snippet = &snippets[snippet_index];
25058                let start = buffer_offset - buffer_window_len;
25059                let start = snapshot.anchor_before(start);
25060                let range = start..buffer_anchor;
25061                let lsp_start = to_lsp(&start);
25062                let lsp_range = lsp::Range {
25063                    start: lsp_start,
25064                    end: lsp_end,
25065                };
25066                Completion {
25067                    replace_range: range,
25068                    new_text: snippet.body.clone(),
25069                    source: CompletionSource::Lsp {
25070                        insert_range: None,
25071                        server_id: LanguageServerId(usize::MAX),
25072                        resolved: true,
25073                        lsp_completion: Box::new(lsp::CompletionItem {
25074                            label: snippet.prefix.first().unwrap().clone(),
25075                            kind: Some(CompletionItemKind::SNIPPET),
25076                            label_details: snippet.description.as_ref().map(|description| {
25077                                lsp::CompletionItemLabelDetails {
25078                                    detail: Some(description.clone()),
25079                                    description: None,
25080                                }
25081                            }),
25082                            insert_text_format: Some(InsertTextFormat::SNIPPET),
25083                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
25084                                lsp::InsertReplaceEdit {
25085                                    new_text: snippet.body.clone(),
25086                                    insert: lsp_range,
25087                                    replace: lsp_range,
25088                                },
25089                            )),
25090                            filter_text: Some(snippet.body.clone()),
25091                            sort_text: Some(char::MAX.to_string()),
25092                            ..lsp::CompletionItem::default()
25093                        }),
25094                        lsp_defaults: None,
25095                    },
25096                    label: CodeLabel {
25097                        text: matching_prefix.clone(),
25098                        runs: Vec::new(),
25099                        filter_range: 0..matching_prefix.len(),
25100                    },
25101                    icon_path: None,
25102                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
25103                        single_line: snippet.name.clone().into(),
25104                        plain_text: snippet
25105                            .description
25106                            .clone()
25107                            .map(|description| description.into()),
25108                    }),
25109                    insert_text_mode: None,
25110                    confirm: None,
25111                    match_start: Some(start),
25112                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
25113                }
25114            }));
25115        }
25116
25117        Ok(CompletionResponse {
25118            completions,
25119            display_options: CompletionDisplayOptions::default(),
25120            is_incomplete,
25121        })
25122    })
25123}
25124
25125impl CompletionProvider for Entity<Project> {
25126    fn completions(
25127        &self,
25128        _excerpt_id: ExcerptId,
25129        buffer: &Entity<Buffer>,
25130        buffer_position: text::Anchor,
25131        options: CompletionContext,
25132        _window: &mut Window,
25133        cx: &mut Context<Editor>,
25134    ) -> Task<Result<Vec<CompletionResponse>>> {
25135        self.update(cx, |project, cx| {
25136            let task = project.completions(buffer, buffer_position, options, cx);
25137            cx.background_spawn(task)
25138        })
25139    }
25140
25141    fn resolve_completions(
25142        &self,
25143        buffer: Entity<Buffer>,
25144        completion_indices: Vec<usize>,
25145        completions: Rc<RefCell<Box<[Completion]>>>,
25146        cx: &mut Context<Editor>,
25147    ) -> Task<Result<bool>> {
25148        self.update(cx, |project, cx| {
25149            project.lsp_store().update(cx, |lsp_store, cx| {
25150                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
25151            })
25152        })
25153    }
25154
25155    fn apply_additional_edits_for_completion(
25156        &self,
25157        buffer: Entity<Buffer>,
25158        completions: Rc<RefCell<Box<[Completion]>>>,
25159        completion_index: usize,
25160        push_to_history: bool,
25161        cx: &mut Context<Editor>,
25162    ) -> Task<Result<Option<language::Transaction>>> {
25163        self.update(cx, |project, cx| {
25164            project.lsp_store().update(cx, |lsp_store, cx| {
25165                lsp_store.apply_additional_edits_for_completion(
25166                    buffer,
25167                    completions,
25168                    completion_index,
25169                    push_to_history,
25170                    cx,
25171                )
25172            })
25173        })
25174    }
25175
25176    fn is_completion_trigger(
25177        &self,
25178        buffer: &Entity<Buffer>,
25179        position: language::Anchor,
25180        text: &str,
25181        trigger_in_words: bool,
25182        cx: &mut Context<Editor>,
25183    ) -> bool {
25184        let mut chars = text.chars();
25185        let char = if let Some(char) = chars.next() {
25186            char
25187        } else {
25188            return false;
25189        };
25190        if chars.next().is_some() {
25191            return false;
25192        }
25193
25194        let buffer = buffer.read(cx);
25195        let snapshot = buffer.snapshot();
25196        let classifier = snapshot
25197            .char_classifier_at(position)
25198            .scope_context(Some(CharScopeContext::Completion));
25199        if trigger_in_words && classifier.is_word(char) {
25200            return true;
25201        }
25202
25203        buffer.completion_triggers().contains(text)
25204    }
25205
25206    fn show_snippets(&self) -> bool {
25207        true
25208    }
25209}
25210
25211impl SemanticsProvider for Entity<Project> {
25212    fn hover(
25213        &self,
25214        buffer: &Entity<Buffer>,
25215        position: text::Anchor,
25216        cx: &mut App,
25217    ) -> Option<Task<Option<Vec<project::Hover>>>> {
25218        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
25219    }
25220
25221    fn document_highlights(
25222        &self,
25223        buffer: &Entity<Buffer>,
25224        position: text::Anchor,
25225        cx: &mut App,
25226    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
25227        Some(self.update(cx, |project, cx| {
25228            project.document_highlights(buffer, position, cx)
25229        }))
25230    }
25231
25232    fn definitions(
25233        &self,
25234        buffer: &Entity<Buffer>,
25235        position: text::Anchor,
25236        kind: GotoDefinitionKind,
25237        cx: &mut App,
25238    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
25239        Some(self.update(cx, |project, cx| match kind {
25240            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
25241            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
25242            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
25243            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
25244        }))
25245    }
25246
25247    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
25248        self.update(cx, |project, cx| {
25249            if project
25250                .active_debug_session(cx)
25251                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
25252            {
25253                return true;
25254            }
25255
25256            buffer.update(cx, |buffer, cx| {
25257                project.any_language_server_supports_inlay_hints(buffer, cx)
25258            })
25259        })
25260    }
25261
25262    fn inline_values(
25263        &self,
25264        buffer_handle: Entity<Buffer>,
25265        range: Range<text::Anchor>,
25266        cx: &mut App,
25267    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
25268        self.update(cx, |project, cx| {
25269            let (session, active_stack_frame) = project.active_debug_session(cx)?;
25270
25271            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
25272        })
25273    }
25274
25275    fn applicable_inlay_chunks(
25276        &self,
25277        buffer: &Entity<Buffer>,
25278        ranges: &[Range<text::Anchor>],
25279        cx: &mut App,
25280    ) -> Vec<Range<BufferRow>> {
25281        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25282            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
25283        })
25284    }
25285
25286    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
25287        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
25288            lsp_store.invalidate_inlay_hints(for_buffers)
25289        });
25290    }
25291
25292    fn inlay_hints(
25293        &self,
25294        invalidate: InvalidationStrategy,
25295        buffer: Entity<Buffer>,
25296        ranges: Vec<Range<text::Anchor>>,
25297        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25298        cx: &mut App,
25299    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25300        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25301            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25302        }))
25303    }
25304
25305    fn range_for_rename(
25306        &self,
25307        buffer: &Entity<Buffer>,
25308        position: text::Anchor,
25309        cx: &mut App,
25310    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25311        Some(self.update(cx, |project, cx| {
25312            let buffer = buffer.clone();
25313            let task = project.prepare_rename(buffer.clone(), position, cx);
25314            cx.spawn(async move |_, cx| {
25315                Ok(match task.await? {
25316                    PrepareRenameResponse::Success(range) => Some(range),
25317                    PrepareRenameResponse::InvalidPosition => None,
25318                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25319                        // Fallback on using TreeSitter info to determine identifier range
25320                        buffer.read_with(cx, |buffer, _| {
25321                            let snapshot = buffer.snapshot();
25322                            let (range, kind) = snapshot.surrounding_word(position, None);
25323                            if kind != Some(CharKind::Word) {
25324                                return None;
25325                            }
25326                            Some(
25327                                snapshot.anchor_before(range.start)
25328                                    ..snapshot.anchor_after(range.end),
25329                            )
25330                        })
25331                    }
25332                })
25333            })
25334        }))
25335    }
25336
25337    fn perform_rename(
25338        &self,
25339        buffer: &Entity<Buffer>,
25340        position: text::Anchor,
25341        new_name: String,
25342        cx: &mut App,
25343    ) -> Option<Task<Result<ProjectTransaction>>> {
25344        Some(self.update(cx, |project, cx| {
25345            project.perform_rename(buffer.clone(), position, new_name, cx)
25346        }))
25347    }
25348}
25349
25350fn consume_contiguous_rows(
25351    contiguous_row_selections: &mut Vec<Selection<Point>>,
25352    selection: &Selection<Point>,
25353    display_map: &DisplaySnapshot,
25354    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25355) -> (MultiBufferRow, MultiBufferRow) {
25356    contiguous_row_selections.push(selection.clone());
25357    let start_row = starting_row(selection, display_map);
25358    let mut end_row = ending_row(selection, display_map);
25359
25360    while let Some(next_selection) = selections.peek() {
25361        if next_selection.start.row <= end_row.0 {
25362            end_row = ending_row(next_selection, display_map);
25363            contiguous_row_selections.push(selections.next().unwrap().clone());
25364        } else {
25365            break;
25366        }
25367    }
25368    (start_row, end_row)
25369}
25370
25371fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25372    if selection.start.column > 0 {
25373        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25374    } else {
25375        MultiBufferRow(selection.start.row)
25376    }
25377}
25378
25379fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25380    if next_selection.end.column > 0 || next_selection.is_empty() {
25381        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25382    } else {
25383        MultiBufferRow(next_selection.end.row)
25384    }
25385}
25386
25387impl EditorSnapshot {
25388    pub fn remote_selections_in_range<'a>(
25389        &'a self,
25390        range: &'a Range<Anchor>,
25391        collaboration_hub: &dyn CollaborationHub,
25392        cx: &'a App,
25393    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25394        let participant_names = collaboration_hub.user_names(cx);
25395        let participant_indices = collaboration_hub.user_participant_indices(cx);
25396        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25397        let collaborators_by_replica_id = collaborators_by_peer_id
25398            .values()
25399            .map(|collaborator| (collaborator.replica_id, collaborator))
25400            .collect::<HashMap<_, _>>();
25401        self.buffer_snapshot()
25402            .selections_in_range(range, false)
25403            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25404                if replica_id == ReplicaId::AGENT {
25405                    Some(RemoteSelection {
25406                        replica_id,
25407                        selection,
25408                        cursor_shape,
25409                        line_mode,
25410                        collaborator_id: CollaboratorId::Agent,
25411                        user_name: Some("Agent".into()),
25412                        color: cx.theme().players().agent(),
25413                    })
25414                } else {
25415                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25416                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25417                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25418                    Some(RemoteSelection {
25419                        replica_id,
25420                        selection,
25421                        cursor_shape,
25422                        line_mode,
25423                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25424                        user_name,
25425                        color: if let Some(index) = participant_index {
25426                            cx.theme().players().color_for_participant(index.0)
25427                        } else {
25428                            cx.theme().players().absent()
25429                        },
25430                    })
25431                }
25432            })
25433    }
25434
25435    pub fn hunks_for_ranges(
25436        &self,
25437        ranges: impl IntoIterator<Item = Range<Point>>,
25438    ) -> Vec<MultiBufferDiffHunk> {
25439        let mut hunks = Vec::new();
25440        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25441            HashMap::default();
25442        for query_range in ranges {
25443            let query_rows =
25444                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25445            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25446                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25447            ) {
25448                // Include deleted hunks that are adjacent to the query range, because
25449                // otherwise they would be missed.
25450                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25451                if hunk.status().is_deleted() {
25452                    intersects_range |= hunk.row_range.start == query_rows.end;
25453                    intersects_range |= hunk.row_range.end == query_rows.start;
25454                }
25455                if intersects_range {
25456                    if !processed_buffer_rows
25457                        .entry(hunk.buffer_id)
25458                        .or_default()
25459                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25460                    {
25461                        continue;
25462                    }
25463                    hunks.push(hunk);
25464                }
25465            }
25466        }
25467
25468        hunks
25469    }
25470
25471    fn display_diff_hunks_for_rows<'a>(
25472        &'a self,
25473        display_rows: Range<DisplayRow>,
25474        folded_buffers: &'a HashSet<BufferId>,
25475    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25476        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25477        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25478
25479        self.buffer_snapshot()
25480            .diff_hunks_in_range(buffer_start..buffer_end)
25481            .filter_map(|hunk| {
25482                if folded_buffers.contains(&hunk.buffer_id) {
25483                    return None;
25484                }
25485
25486                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25487                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25488
25489                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25490                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25491
25492                let display_hunk = if hunk_display_start.column() != 0 {
25493                    DisplayDiffHunk::Folded {
25494                        display_row: hunk_display_start.row(),
25495                    }
25496                } else {
25497                    let mut end_row = hunk_display_end.row();
25498                    if hunk_display_end.column() > 0 {
25499                        end_row.0 += 1;
25500                    }
25501                    let is_created_file = hunk.is_created_file();
25502
25503                    DisplayDiffHunk::Unfolded {
25504                        status: hunk.status(),
25505                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25506                            ..hunk.diff_base_byte_range.end.0,
25507                        word_diffs: hunk.word_diffs,
25508                        display_row_range: hunk_display_start.row()..end_row,
25509                        multi_buffer_range: Anchor::range_in_buffer(
25510                            hunk.excerpt_id,
25511                            hunk.buffer_range,
25512                        ),
25513                        is_created_file,
25514                    }
25515                };
25516
25517                Some(display_hunk)
25518            })
25519    }
25520
25521    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25522        self.display_snapshot
25523            .buffer_snapshot()
25524            .language_at(position)
25525    }
25526
25527    pub fn is_focused(&self) -> bool {
25528        self.is_focused
25529    }
25530
25531    pub fn placeholder_text(&self) -> Option<String> {
25532        self.placeholder_display_snapshot
25533            .as_ref()
25534            .map(|display_map| display_map.text())
25535    }
25536
25537    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25538        self.scroll_anchor.scroll_position(&self.display_snapshot)
25539    }
25540
25541    pub fn gutter_dimensions(
25542        &self,
25543        font_id: FontId,
25544        font_size: Pixels,
25545        style: &EditorStyle,
25546        window: &mut Window,
25547        cx: &App,
25548    ) -> GutterDimensions {
25549        if self.show_gutter
25550            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25551            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25552        {
25553            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25554                matches!(
25555                    ProjectSettings::get_global(cx).git.git_gutter,
25556                    GitGutterSetting::TrackedFiles
25557                )
25558            });
25559            let gutter_settings = EditorSettings::get_global(cx).gutter;
25560            let show_line_numbers = self
25561                .show_line_numbers
25562                .unwrap_or(gutter_settings.line_numbers);
25563            let line_gutter_width = if show_line_numbers {
25564                // Avoid flicker-like gutter resizes when the line number gains another digit by
25565                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25566                let min_width_for_number_on_gutter =
25567                    ch_advance * gutter_settings.min_line_number_digits as f32;
25568                self.max_line_number_width(style, window)
25569                    .max(min_width_for_number_on_gutter)
25570            } else {
25571                0.0.into()
25572            };
25573
25574            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25575            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25576
25577            let git_blame_entries_width =
25578                self.git_blame_gutter_max_author_length
25579                    .map(|max_author_length| {
25580                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25581                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25582
25583                        /// The number of characters to dedicate to gaps and margins.
25584                        const SPACING_WIDTH: usize = 4;
25585
25586                        let max_char_count = max_author_length.min(renderer.max_author_length())
25587                            + ::git::SHORT_SHA_LENGTH
25588                            + MAX_RELATIVE_TIMESTAMP.len()
25589                            + SPACING_WIDTH;
25590
25591                        ch_advance * max_char_count
25592                    });
25593
25594            let is_singleton = self.buffer_snapshot().is_singleton();
25595
25596            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25597            left_padding += if !is_singleton {
25598                ch_width * 4.0
25599            } else if show_runnables || show_breakpoints {
25600                ch_width * 3.0
25601            } else if show_git_gutter && show_line_numbers {
25602                ch_width * 2.0
25603            } else if show_git_gutter || show_line_numbers {
25604                ch_width
25605            } else {
25606                px(0.)
25607            };
25608
25609            let shows_folds = is_singleton && gutter_settings.folds;
25610
25611            let right_padding = if shows_folds && show_line_numbers {
25612                ch_width * 4.0
25613            } else if shows_folds || (!is_singleton && show_line_numbers) {
25614                ch_width * 3.0
25615            } else if show_line_numbers {
25616                ch_width
25617            } else {
25618                px(0.)
25619            };
25620
25621            GutterDimensions {
25622                left_padding,
25623                right_padding,
25624                width: line_gutter_width + left_padding + right_padding,
25625                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25626                git_blame_entries_width,
25627            }
25628        } else if self.offset_content {
25629            GutterDimensions::default_with_margin(font_id, font_size, cx)
25630        } else {
25631            GutterDimensions::default()
25632        }
25633    }
25634
25635    pub fn render_crease_toggle(
25636        &self,
25637        buffer_row: MultiBufferRow,
25638        row_contains_cursor: bool,
25639        editor: Entity<Editor>,
25640        window: &mut Window,
25641        cx: &mut App,
25642    ) -> Option<AnyElement> {
25643        let folded = self.is_line_folded(buffer_row);
25644        let mut is_foldable = false;
25645
25646        if let Some(crease) = self
25647            .crease_snapshot
25648            .query_row(buffer_row, self.buffer_snapshot())
25649        {
25650            is_foldable = true;
25651            match crease {
25652                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25653                    if let Some(render_toggle) = render_toggle {
25654                        let toggle_callback =
25655                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25656                                if folded {
25657                                    editor.update(cx, |editor, cx| {
25658                                        editor.fold_at(buffer_row, window, cx)
25659                                    });
25660                                } else {
25661                                    editor.update(cx, |editor, cx| {
25662                                        editor.unfold_at(buffer_row, window, cx)
25663                                    });
25664                                }
25665                            });
25666                        return Some((render_toggle)(
25667                            buffer_row,
25668                            folded,
25669                            toggle_callback,
25670                            window,
25671                            cx,
25672                        ));
25673                    }
25674                }
25675            }
25676        }
25677
25678        is_foldable |= self.starts_indent(buffer_row);
25679
25680        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25681            Some(
25682                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25683                    .toggle_state(folded)
25684                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25685                        if folded {
25686                            this.unfold_at(buffer_row, window, cx);
25687                        } else {
25688                            this.fold_at(buffer_row, window, cx);
25689                        }
25690                    }))
25691                    .into_any_element(),
25692            )
25693        } else {
25694            None
25695        }
25696    }
25697
25698    pub fn render_crease_trailer(
25699        &self,
25700        buffer_row: MultiBufferRow,
25701        window: &mut Window,
25702        cx: &mut App,
25703    ) -> Option<AnyElement> {
25704        let folded = self.is_line_folded(buffer_row);
25705        if let Crease::Inline { render_trailer, .. } = self
25706            .crease_snapshot
25707            .query_row(buffer_row, self.buffer_snapshot())?
25708        {
25709            let render_trailer = render_trailer.as_ref()?;
25710            Some(render_trailer(buffer_row, folded, window, cx))
25711        } else {
25712            None
25713        }
25714    }
25715
25716    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25717        let digit_count = self.widest_line_number().ilog10() + 1;
25718        column_pixels(style, digit_count as usize, window)
25719    }
25720
25721    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25722    ///
25723    /// This is positive if `base` is before `line`.
25724    fn relative_line_delta(
25725        &self,
25726        current_selection_head: DisplayRow,
25727        first_visible_row: DisplayRow,
25728        consider_wrapped_lines: bool,
25729    ) -> i64 {
25730        let current_selection_head = current_selection_head.as_display_point().to_point(self);
25731        let first_visible_row = first_visible_row.as_display_point().to_point(self);
25732
25733        if consider_wrapped_lines {
25734            let wrap_snapshot = self.wrap_snapshot();
25735            let base_wrap_row = wrap_snapshot
25736                .make_wrap_point(current_selection_head, Bias::Left)
25737                .row();
25738            let wrap_row = wrap_snapshot
25739                .make_wrap_point(first_visible_row, Bias::Left)
25740                .row();
25741            wrap_row.0 as i64 - base_wrap_row.0 as i64
25742        } else {
25743            let folds = if current_selection_head < first_visible_row {
25744                self.folds_in_range(current_selection_head..first_visible_row)
25745            } else {
25746                self.folds_in_range(first_visible_row..current_selection_head)
25747            };
25748
25749            let folded_lines = folds
25750                .map(|fold| {
25751                    let range = fold.range.0.to_point(self);
25752                    range.end.row.saturating_sub(range.start.row)
25753                })
25754                .sum::<u32>() as i64;
25755
25756            first_visible_row.row as i64 - current_selection_head.row as i64 + folded_lines
25757        }
25758    }
25759
25760    /// Returns the unsigned relative line number to display for each row in `rows`.
25761    ///
25762    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25763    pub fn calculate_relative_line_numbers(
25764        &self,
25765        rows: &Range<DisplayRow>,
25766        current_selection_head: DisplayRow,
25767        count_wrapped_lines: bool,
25768    ) -> HashMap<DisplayRow, u32> {
25769        let initial_offset =
25770            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
25771        let current_selection_point = current_selection_head.as_display_point().to_point(self);
25772
25773        self.row_infos(rows.start)
25774            .take(rows.len())
25775            .enumerate()
25776            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25777            .filter(|(_row, row_info)| {
25778                row_info.buffer_row.is_some()
25779                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25780            })
25781            .enumerate()
25782            .filter(|(_, (row, row_info))| {
25783                // We want to check here that
25784                // - the row is not the current selection head to ensure the current
25785                // line has absolute numbering
25786                // - similarly, should the selection head live in a soft-wrapped line
25787                // and we are not counting those, that the parent line keeps its
25788                // absolute number
25789                // - lastly, if we are in a deleted line, it is fine to number this
25790                // relative with 0, as otherwise it would have no line number at all
25791                (*row != current_selection_head
25792                    && (count_wrapped_lines
25793                        || row_info.buffer_row != Some(current_selection_point.row)))
25794                    || row_info
25795                        .diff_status
25796                        .is_some_and(|status| status.is_deleted())
25797            })
25798            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
25799            .collect()
25800    }
25801}
25802
25803pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25804    let font_size = style.text.font_size.to_pixels(window.rem_size());
25805    let layout = window.text_system().shape_line(
25806        SharedString::from(" ".repeat(column)),
25807        font_size,
25808        &[TextRun {
25809            len: column,
25810            font: style.text.font(),
25811            color: Hsla::default(),
25812            ..Default::default()
25813        }],
25814        None,
25815    );
25816
25817    layout.width
25818}
25819
25820impl Deref for EditorSnapshot {
25821    type Target = DisplaySnapshot;
25822
25823    fn deref(&self) -> &Self::Target {
25824        &self.display_snapshot
25825    }
25826}
25827
25828#[derive(Clone, Debug, PartialEq, Eq)]
25829pub enum EditorEvent {
25830    InputIgnored {
25831        text: Arc<str>,
25832    },
25833    InputHandled {
25834        utf16_range_to_replace: Option<Range<isize>>,
25835        text: Arc<str>,
25836    },
25837    ExcerptsAdded {
25838        buffer: Entity<Buffer>,
25839        predecessor: ExcerptId,
25840        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25841    },
25842    ExcerptsRemoved {
25843        ids: Vec<ExcerptId>,
25844        removed_buffer_ids: Vec<BufferId>,
25845    },
25846    BufferFoldToggled {
25847        ids: Vec<ExcerptId>,
25848        folded: bool,
25849    },
25850    ExcerptsEdited {
25851        ids: Vec<ExcerptId>,
25852    },
25853    ExcerptsExpanded {
25854        ids: Vec<ExcerptId>,
25855    },
25856    ExpandExcerptsRequested {
25857        excerpt_ids: Vec<ExcerptId>,
25858        lines: u32,
25859        direction: ExpandExcerptDirection,
25860    },
25861    BufferEdited,
25862    Edited {
25863        transaction_id: clock::Lamport,
25864    },
25865    Reparsed(BufferId),
25866    Focused,
25867    FocusedIn,
25868    Blurred,
25869    DirtyChanged,
25870    Saved,
25871    TitleChanged,
25872    SelectionsChanged {
25873        local: bool,
25874    },
25875    ScrollPositionChanged {
25876        local: bool,
25877        autoscroll: bool,
25878    },
25879    TransactionUndone {
25880        transaction_id: clock::Lamport,
25881    },
25882    TransactionBegun {
25883        transaction_id: clock::Lamport,
25884    },
25885    CursorShapeChanged,
25886    BreadcrumbsChanged,
25887    PushedToNavHistory {
25888        anchor: Anchor,
25889        is_deactivate: bool,
25890    },
25891}
25892
25893impl EventEmitter<EditorEvent> for Editor {}
25894
25895impl Focusable for Editor {
25896    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25897        self.focus_handle.clone()
25898    }
25899}
25900
25901impl Render for Editor {
25902    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25903        EditorElement::new(&cx.entity(), self.create_style(cx))
25904    }
25905}
25906
25907impl EntityInputHandler for Editor {
25908    fn text_for_range(
25909        &mut self,
25910        range_utf16: Range<usize>,
25911        adjusted_range: &mut Option<Range<usize>>,
25912        _: &mut Window,
25913        cx: &mut Context<Self>,
25914    ) -> Option<String> {
25915        let snapshot = self.buffer.read(cx).read(cx);
25916        let start = snapshot.clip_offset_utf16(
25917            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25918            Bias::Left,
25919        );
25920        let end = snapshot.clip_offset_utf16(
25921            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25922            Bias::Right,
25923        );
25924        if (start.0.0..end.0.0) != range_utf16 {
25925            adjusted_range.replace(start.0.0..end.0.0);
25926        }
25927        Some(snapshot.text_for_range(start..end).collect())
25928    }
25929
25930    fn selected_text_range(
25931        &mut self,
25932        ignore_disabled_input: bool,
25933        _: &mut Window,
25934        cx: &mut Context<Self>,
25935    ) -> Option<UTF16Selection> {
25936        // Prevent the IME menu from appearing when holding down an alphabetic key
25937        // while input is disabled.
25938        if !ignore_disabled_input && !self.input_enabled {
25939            return None;
25940        }
25941
25942        let selection = self
25943            .selections
25944            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25945        let range = selection.range();
25946
25947        Some(UTF16Selection {
25948            range: range.start.0.0..range.end.0.0,
25949            reversed: selection.reversed,
25950        })
25951    }
25952
25953    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25954        let snapshot = self.buffer.read(cx).read(cx);
25955        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25956        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25957    }
25958
25959    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25960        self.clear_highlights::<InputComposition>(cx);
25961        self.ime_transaction.take();
25962    }
25963
25964    fn replace_text_in_range(
25965        &mut self,
25966        range_utf16: Option<Range<usize>>,
25967        text: &str,
25968        window: &mut Window,
25969        cx: &mut Context<Self>,
25970    ) {
25971        if !self.input_enabled {
25972            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25973            return;
25974        }
25975
25976        self.transact(window, cx, |this, window, cx| {
25977            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25978                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25979                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25980                Some(this.selection_replacement_ranges(range_utf16, cx))
25981            } else {
25982                this.marked_text_ranges(cx)
25983            };
25984
25985            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25986                let newest_selection_id = this.selections.newest_anchor().id;
25987                this.selections
25988                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25989                    .iter()
25990                    .zip(ranges_to_replace.iter())
25991                    .find_map(|(selection, range)| {
25992                        if selection.id == newest_selection_id {
25993                            Some(
25994                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25995                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25996                            )
25997                        } else {
25998                            None
25999                        }
26000                    })
26001            });
26002
26003            cx.emit(EditorEvent::InputHandled {
26004                utf16_range_to_replace: range_to_replace,
26005                text: text.into(),
26006            });
26007
26008            if let Some(new_selected_ranges) = new_selected_ranges {
26009                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
26010                    selections.select_ranges(new_selected_ranges)
26011                });
26012                this.backspace(&Default::default(), window, cx);
26013            }
26014
26015            this.handle_input(text, window, cx);
26016        });
26017
26018        if let Some(transaction) = self.ime_transaction {
26019            self.buffer.update(cx, |buffer, cx| {
26020                buffer.group_until_transaction(transaction, cx);
26021            });
26022        }
26023
26024        self.unmark_text(window, cx);
26025    }
26026
26027    fn replace_and_mark_text_in_range(
26028        &mut self,
26029        range_utf16: Option<Range<usize>>,
26030        text: &str,
26031        new_selected_range_utf16: Option<Range<usize>>,
26032        window: &mut Window,
26033        cx: &mut Context<Self>,
26034    ) {
26035        if !self.input_enabled {
26036            return;
26037        }
26038
26039        let transaction = self.transact(window, cx, |this, window, cx| {
26040            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
26041                let snapshot = this.buffer.read(cx).read(cx);
26042                if let Some(relative_range_utf16) = range_utf16.as_ref() {
26043                    for marked_range in &mut marked_ranges {
26044                        marked_range.end = marked_range.start + relative_range_utf16.end;
26045                        marked_range.start += relative_range_utf16.start;
26046                        marked_range.start =
26047                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
26048                        marked_range.end =
26049                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
26050                    }
26051                }
26052                Some(marked_ranges)
26053            } else if let Some(range_utf16) = range_utf16 {
26054                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
26055                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
26056                Some(this.selection_replacement_ranges(range_utf16, cx))
26057            } else {
26058                None
26059            };
26060
26061            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
26062                let newest_selection_id = this.selections.newest_anchor().id;
26063                this.selections
26064                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
26065                    .iter()
26066                    .zip(ranges_to_replace.iter())
26067                    .find_map(|(selection, range)| {
26068                        if selection.id == newest_selection_id {
26069                            Some(
26070                                (range.start.0.0 as isize - selection.head().0.0 as isize)
26071                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
26072                            )
26073                        } else {
26074                            None
26075                        }
26076                    })
26077            });
26078
26079            cx.emit(EditorEvent::InputHandled {
26080                utf16_range_to_replace: range_to_replace,
26081                text: text.into(),
26082            });
26083
26084            if let Some(ranges) = ranges_to_replace {
26085                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
26086                    s.select_ranges(ranges)
26087                });
26088            }
26089
26090            let marked_ranges = {
26091                let snapshot = this.buffer.read(cx).read(cx);
26092                this.selections
26093                    .disjoint_anchors_arc()
26094                    .iter()
26095                    .map(|selection| {
26096                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
26097                    })
26098                    .collect::<Vec<_>>()
26099            };
26100
26101            if text.is_empty() {
26102                this.unmark_text(window, cx);
26103            } else {
26104                this.highlight_text::<InputComposition>(
26105                    marked_ranges.clone(),
26106                    HighlightStyle {
26107                        underline: Some(UnderlineStyle {
26108                            thickness: px(1.),
26109                            color: None,
26110                            wavy: false,
26111                        }),
26112                        ..Default::default()
26113                    },
26114                    cx,
26115                );
26116            }
26117
26118            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
26119            let use_autoclose = this.use_autoclose;
26120            let use_auto_surround = this.use_auto_surround;
26121            this.set_use_autoclose(false);
26122            this.set_use_auto_surround(false);
26123            this.handle_input(text, window, cx);
26124            this.set_use_autoclose(use_autoclose);
26125            this.set_use_auto_surround(use_auto_surround);
26126
26127            if let Some(new_selected_range) = new_selected_range_utf16 {
26128                let snapshot = this.buffer.read(cx).read(cx);
26129                let new_selected_ranges = marked_ranges
26130                    .into_iter()
26131                    .map(|marked_range| {
26132                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
26133                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
26134                            insertion_start.0 + new_selected_range.start,
26135                        ));
26136                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
26137                            insertion_start.0 + new_selected_range.end,
26138                        ));
26139                        snapshot.clip_offset_utf16(new_start, Bias::Left)
26140                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
26141                    })
26142                    .collect::<Vec<_>>();
26143
26144                drop(snapshot);
26145                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
26146                    selections.select_ranges(new_selected_ranges)
26147                });
26148            }
26149        });
26150
26151        self.ime_transaction = self.ime_transaction.or(transaction);
26152        if let Some(transaction) = self.ime_transaction {
26153            self.buffer.update(cx, |buffer, cx| {
26154                buffer.group_until_transaction(transaction, cx);
26155            });
26156        }
26157
26158        if self.text_highlights::<InputComposition>(cx).is_none() {
26159            self.ime_transaction.take();
26160        }
26161    }
26162
26163    fn bounds_for_range(
26164        &mut self,
26165        range_utf16: Range<usize>,
26166        element_bounds: gpui::Bounds<Pixels>,
26167        window: &mut Window,
26168        cx: &mut Context<Self>,
26169    ) -> Option<gpui::Bounds<Pixels>> {
26170        let text_layout_details = self.text_layout_details(window);
26171        let CharacterDimensions {
26172            em_width,
26173            em_advance,
26174            line_height,
26175        } = self.character_dimensions(window);
26176
26177        let snapshot = self.snapshot(window, cx);
26178        let scroll_position = snapshot.scroll_position();
26179        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
26180
26181        let start =
26182            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
26183        let x = Pixels::from(
26184            ScrollOffset::from(
26185                snapshot.x_for_display_point(start, &text_layout_details)
26186                    + self.gutter_dimensions.full_width(),
26187            ) - scroll_left,
26188        );
26189        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
26190
26191        Some(Bounds {
26192            origin: element_bounds.origin + point(x, y),
26193            size: size(em_width, line_height),
26194        })
26195    }
26196
26197    fn character_index_for_point(
26198        &mut self,
26199        point: gpui::Point<Pixels>,
26200        _window: &mut Window,
26201        _cx: &mut Context<Self>,
26202    ) -> Option<usize> {
26203        let position_map = self.last_position_map.as_ref()?;
26204        if !position_map.text_hitbox.contains(&point) {
26205            return None;
26206        }
26207        let display_point = position_map.point_for_position(point).previous_valid;
26208        let anchor = position_map
26209            .snapshot
26210            .display_point_to_anchor(display_point, Bias::Left);
26211        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
26212        Some(utf16_offset.0.0)
26213    }
26214
26215    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
26216        self.input_enabled
26217    }
26218}
26219
26220trait SelectionExt {
26221    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
26222    fn spanned_rows(
26223        &self,
26224        include_end_if_at_line_start: bool,
26225        map: &DisplaySnapshot,
26226    ) -> Range<MultiBufferRow>;
26227}
26228
26229impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
26230    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
26231        let start = self
26232            .start
26233            .to_point(map.buffer_snapshot())
26234            .to_display_point(map);
26235        let end = self
26236            .end
26237            .to_point(map.buffer_snapshot())
26238            .to_display_point(map);
26239        if self.reversed {
26240            end..start
26241        } else {
26242            start..end
26243        }
26244    }
26245
26246    fn spanned_rows(
26247        &self,
26248        include_end_if_at_line_start: bool,
26249        map: &DisplaySnapshot,
26250    ) -> Range<MultiBufferRow> {
26251        let start = self.start.to_point(map.buffer_snapshot());
26252        let mut end = self.end.to_point(map.buffer_snapshot());
26253        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
26254            end.row -= 1;
26255        }
26256
26257        let buffer_start = map.prev_line_boundary(start).0;
26258        let buffer_end = map.next_line_boundary(end).0;
26259        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
26260    }
26261}
26262
26263impl<T: InvalidationRegion> InvalidationStack<T> {
26264    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
26265    where
26266        S: Clone + ToOffset,
26267    {
26268        while let Some(region) = self.last() {
26269            let all_selections_inside_invalidation_ranges =
26270                if selections.len() == region.ranges().len() {
26271                    selections
26272                        .iter()
26273                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
26274                        .all(|(selection, invalidation_range)| {
26275                            let head = selection.head().to_offset(buffer);
26276                            invalidation_range.start <= head && invalidation_range.end >= head
26277                        })
26278                } else {
26279                    false
26280                };
26281
26282            if all_selections_inside_invalidation_ranges {
26283                break;
26284            } else {
26285                self.pop();
26286            }
26287        }
26288    }
26289}
26290
26291impl<T> Default for InvalidationStack<T> {
26292    fn default() -> Self {
26293        Self(Default::default())
26294    }
26295}
26296
26297impl<T> Deref for InvalidationStack<T> {
26298    type Target = Vec<T>;
26299
26300    fn deref(&self) -> &Self::Target {
26301        &self.0
26302    }
26303}
26304
26305impl<T> DerefMut for InvalidationStack<T> {
26306    fn deref_mut(&mut self) -> &mut Self::Target {
26307        &mut self.0
26308    }
26309}
26310
26311impl InvalidationRegion for SnippetState {
26312    fn ranges(&self) -> &[Range<Anchor>] {
26313        &self.ranges[self.active_index]
26314    }
26315}
26316
26317fn edit_prediction_edit_text(
26318    current_snapshot: &BufferSnapshot,
26319    edits: &[(Range<Anchor>, impl AsRef<str>)],
26320    edit_preview: &EditPreview,
26321    include_deletions: bool,
26322    cx: &App,
26323) -> HighlightedText {
26324    let edits = edits
26325        .iter()
26326        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26327        .collect::<Vec<_>>();
26328
26329    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26330}
26331
26332fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26333    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26334    // Just show the raw edit text with basic styling
26335    let mut text = String::new();
26336    let mut highlights = Vec::new();
26337
26338    let insertion_highlight_style = HighlightStyle {
26339        color: Some(cx.theme().colors().text),
26340        ..Default::default()
26341    };
26342
26343    for (_, edit_text) in edits {
26344        let start_offset = text.len();
26345        text.push_str(edit_text);
26346        let end_offset = text.len();
26347
26348        if start_offset < end_offset {
26349            highlights.push((start_offset..end_offset, insertion_highlight_style));
26350        }
26351    }
26352
26353    HighlightedText {
26354        text: text.into(),
26355        highlights,
26356    }
26357}
26358
26359pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26360    match severity {
26361        lsp::DiagnosticSeverity::ERROR => colors.error,
26362        lsp::DiagnosticSeverity::WARNING => colors.warning,
26363        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26364        lsp::DiagnosticSeverity::HINT => colors.info,
26365        _ => colors.ignored,
26366    }
26367}
26368
26369pub fn styled_runs_for_code_label<'a>(
26370    label: &'a CodeLabel,
26371    syntax_theme: &'a theme::SyntaxTheme,
26372    local_player: &'a theme::PlayerColor,
26373) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26374    let fade_out = HighlightStyle {
26375        fade_out: Some(0.35),
26376        ..Default::default()
26377    };
26378
26379    let mut prev_end = label.filter_range.end;
26380    label
26381        .runs
26382        .iter()
26383        .enumerate()
26384        .flat_map(move |(ix, (range, highlight_id))| {
26385            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26386                HighlightStyle {
26387                    color: Some(local_player.cursor),
26388                    ..Default::default()
26389                }
26390            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26391                HighlightStyle {
26392                    background_color: Some(local_player.selection),
26393                    ..Default::default()
26394                }
26395            } else if let Some(style) = highlight_id.style(syntax_theme) {
26396                style
26397            } else {
26398                return Default::default();
26399            };
26400            let muted_style = style.highlight(fade_out);
26401
26402            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26403            if range.start >= label.filter_range.end {
26404                if range.start > prev_end {
26405                    runs.push((prev_end..range.start, fade_out));
26406                }
26407                runs.push((range.clone(), muted_style));
26408            } else if range.end <= label.filter_range.end {
26409                runs.push((range.clone(), style));
26410            } else {
26411                runs.push((range.start..label.filter_range.end, style));
26412                runs.push((label.filter_range.end..range.end, muted_style));
26413            }
26414            prev_end = cmp::max(prev_end, range.end);
26415
26416            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26417                runs.push((prev_end..label.text.len(), fade_out));
26418            }
26419
26420            runs
26421        })
26422}
26423
26424pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26425    let mut prev_index = 0;
26426    let mut prev_codepoint: Option<char> = None;
26427    text.char_indices()
26428        .chain([(text.len(), '\0')])
26429        .filter_map(move |(index, codepoint)| {
26430            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26431            let is_boundary = index == text.len()
26432                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26433                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26434            if is_boundary {
26435                let chunk = &text[prev_index..index];
26436                prev_index = index;
26437                Some(chunk)
26438            } else {
26439                None
26440            }
26441        })
26442}
26443
26444/// Given a string of text immediately before the cursor, iterates over possible
26445/// strings a snippet could match to. More precisely: returns an iterator over
26446/// suffixes of `text` created by splitting at word boundaries (before & after
26447/// every non-word character).
26448///
26449/// Shorter suffixes are returned first.
26450pub(crate) fn snippet_candidate_suffixes(
26451    text: &str,
26452    is_word_char: impl Fn(char) -> bool,
26453) -> impl std::iter::Iterator<Item = &str> {
26454    let mut prev_index = text.len();
26455    let mut prev_codepoint = None;
26456    text.char_indices()
26457        .rev()
26458        .chain([(0, '\0')])
26459        .filter_map(move |(index, codepoint)| {
26460            let prev_index = std::mem::replace(&mut prev_index, index);
26461            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26462            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26463                None
26464            } else {
26465                let chunk = &text[prev_index..]; // go to end of string
26466                Some(chunk)
26467            }
26468        })
26469}
26470
26471pub trait RangeToAnchorExt: Sized {
26472    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26473
26474    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26475        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26476        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26477    }
26478}
26479
26480impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26481    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26482        let start_offset = self.start.to_offset(snapshot);
26483        let end_offset = self.end.to_offset(snapshot);
26484        if start_offset == end_offset {
26485            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26486        } else {
26487            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26488        }
26489    }
26490}
26491
26492pub trait RowExt {
26493    fn as_f64(&self) -> f64;
26494
26495    fn next_row(&self) -> Self;
26496
26497    fn previous_row(&self) -> Self;
26498
26499    fn minus(&self, other: Self) -> u32;
26500}
26501
26502impl RowExt for DisplayRow {
26503    fn as_f64(&self) -> f64 {
26504        self.0 as _
26505    }
26506
26507    fn next_row(&self) -> Self {
26508        Self(self.0 + 1)
26509    }
26510
26511    fn previous_row(&self) -> Self {
26512        Self(self.0.saturating_sub(1))
26513    }
26514
26515    fn minus(&self, other: Self) -> u32 {
26516        self.0 - other.0
26517    }
26518}
26519
26520impl RowExt for MultiBufferRow {
26521    fn as_f64(&self) -> f64 {
26522        self.0 as _
26523    }
26524
26525    fn next_row(&self) -> Self {
26526        Self(self.0 + 1)
26527    }
26528
26529    fn previous_row(&self) -> Self {
26530        Self(self.0.saturating_sub(1))
26531    }
26532
26533    fn minus(&self, other: Self) -> u32 {
26534        self.0 - other.0
26535    }
26536}
26537
26538trait RowRangeExt {
26539    type Row;
26540
26541    fn len(&self) -> usize;
26542
26543    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26544}
26545
26546impl RowRangeExt for Range<MultiBufferRow> {
26547    type Row = MultiBufferRow;
26548
26549    fn len(&self) -> usize {
26550        (self.end.0 - self.start.0) as usize
26551    }
26552
26553    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26554        (self.start.0..self.end.0).map(MultiBufferRow)
26555    }
26556}
26557
26558impl RowRangeExt for Range<DisplayRow> {
26559    type Row = DisplayRow;
26560
26561    fn len(&self) -> usize {
26562        (self.end.0 - self.start.0) as usize
26563    }
26564
26565    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26566        (self.start.0..self.end.0).map(DisplayRow)
26567    }
26568}
26569
26570/// If select range has more than one line, we
26571/// just point the cursor to range.start.
26572fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26573    if range.start.row == range.end.row {
26574        range
26575    } else {
26576        range.start..range.start
26577    }
26578}
26579pub struct KillRing(ClipboardItem);
26580impl Global for KillRing {}
26581
26582const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26583
26584enum BreakpointPromptEditAction {
26585    Log,
26586    Condition,
26587    HitCondition,
26588}
26589
26590struct BreakpointPromptEditor {
26591    pub(crate) prompt: Entity<Editor>,
26592    editor: WeakEntity<Editor>,
26593    breakpoint_anchor: Anchor,
26594    breakpoint: Breakpoint,
26595    edit_action: BreakpointPromptEditAction,
26596    block_ids: HashSet<CustomBlockId>,
26597    editor_margins: Arc<Mutex<EditorMargins>>,
26598    _subscriptions: Vec<Subscription>,
26599}
26600
26601impl BreakpointPromptEditor {
26602    const MAX_LINES: u8 = 4;
26603
26604    fn new(
26605        editor: WeakEntity<Editor>,
26606        breakpoint_anchor: Anchor,
26607        breakpoint: Breakpoint,
26608        edit_action: BreakpointPromptEditAction,
26609        window: &mut Window,
26610        cx: &mut Context<Self>,
26611    ) -> Self {
26612        let base_text = match edit_action {
26613            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26614            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26615            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26616        }
26617        .map(|msg| msg.to_string())
26618        .unwrap_or_default();
26619
26620        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26621        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26622
26623        let prompt = cx.new(|cx| {
26624            let mut prompt = Editor::new(
26625                EditorMode::AutoHeight {
26626                    min_lines: 1,
26627                    max_lines: Some(Self::MAX_LINES as usize),
26628                },
26629                buffer,
26630                None,
26631                window,
26632                cx,
26633            );
26634            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26635            prompt.set_show_cursor_when_unfocused(false, cx);
26636            prompt.set_placeholder_text(
26637                match edit_action {
26638                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26639                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26640                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26641                },
26642                window,
26643                cx,
26644            );
26645
26646            prompt
26647        });
26648
26649        Self {
26650            prompt,
26651            editor,
26652            breakpoint_anchor,
26653            breakpoint,
26654            edit_action,
26655            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26656            block_ids: Default::default(),
26657            _subscriptions: vec![],
26658        }
26659    }
26660
26661    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26662        self.block_ids.extend(block_ids)
26663    }
26664
26665    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26666        if let Some(editor) = self.editor.upgrade() {
26667            let message = self
26668                .prompt
26669                .read(cx)
26670                .buffer
26671                .read(cx)
26672                .as_singleton()
26673                .expect("A multi buffer in breakpoint prompt isn't possible")
26674                .read(cx)
26675                .as_rope()
26676                .to_string();
26677
26678            editor.update(cx, |editor, cx| {
26679                editor.edit_breakpoint_at_anchor(
26680                    self.breakpoint_anchor,
26681                    self.breakpoint.clone(),
26682                    match self.edit_action {
26683                        BreakpointPromptEditAction::Log => {
26684                            BreakpointEditAction::EditLogMessage(message.into())
26685                        }
26686                        BreakpointPromptEditAction::Condition => {
26687                            BreakpointEditAction::EditCondition(message.into())
26688                        }
26689                        BreakpointPromptEditAction::HitCondition => {
26690                            BreakpointEditAction::EditHitCondition(message.into())
26691                        }
26692                    },
26693                    cx,
26694                );
26695
26696                editor.remove_blocks(self.block_ids.clone(), None, cx);
26697                cx.focus_self(window);
26698            });
26699        }
26700    }
26701
26702    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26703        self.editor
26704            .update(cx, |editor, cx| {
26705                editor.remove_blocks(self.block_ids.clone(), None, cx);
26706                window.focus(&editor.focus_handle, cx);
26707            })
26708            .log_err();
26709    }
26710
26711    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26712        let settings = ThemeSettings::get_global(cx);
26713        let text_style = TextStyle {
26714            color: if self.prompt.read(cx).read_only(cx) {
26715                cx.theme().colors().text_disabled
26716            } else {
26717                cx.theme().colors().text
26718            },
26719            font_family: settings.buffer_font.family.clone(),
26720            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26721            font_size: settings.buffer_font_size(cx).into(),
26722            font_weight: settings.buffer_font.weight,
26723            line_height: relative(settings.buffer_line_height.value()),
26724            ..Default::default()
26725        };
26726        EditorElement::new(
26727            &self.prompt,
26728            EditorStyle {
26729                background: cx.theme().colors().editor_background,
26730                local_player: cx.theme().players().local(),
26731                text: text_style,
26732                ..Default::default()
26733            },
26734        )
26735    }
26736}
26737
26738impl Render for BreakpointPromptEditor {
26739    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26740        let editor_margins = *self.editor_margins.lock();
26741        let gutter_dimensions = editor_margins.gutter;
26742        h_flex()
26743            .key_context("Editor")
26744            .bg(cx.theme().colors().editor_background)
26745            .border_y_1()
26746            .border_color(cx.theme().status().info_border)
26747            .size_full()
26748            .py(window.line_height() / 2.5)
26749            .on_action(cx.listener(Self::confirm))
26750            .on_action(cx.listener(Self::cancel))
26751            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26752            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26753    }
26754}
26755
26756impl Focusable for BreakpointPromptEditor {
26757    fn focus_handle(&self, cx: &App) -> FocusHandle {
26758        self.prompt.focus_handle(cx)
26759    }
26760}
26761
26762fn all_edits_insertions_or_deletions(
26763    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26764    snapshot: &MultiBufferSnapshot,
26765) -> bool {
26766    let mut all_insertions = true;
26767    let mut all_deletions = true;
26768
26769    for (range, new_text) in edits.iter() {
26770        let range_is_empty = range.to_offset(snapshot).is_empty();
26771        let text_is_empty = new_text.is_empty();
26772
26773        if range_is_empty != text_is_empty {
26774            if range_is_empty {
26775                all_deletions = false;
26776            } else {
26777                all_insertions = false;
26778            }
26779        } else {
26780            return false;
26781        }
26782
26783        if !all_insertions && !all_deletions {
26784            return false;
26785        }
26786    }
26787    all_insertions || all_deletions
26788}
26789
26790struct MissingEditPredictionKeybindingTooltip;
26791
26792impl Render for MissingEditPredictionKeybindingTooltip {
26793    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26794        ui::tooltip_container(cx, |container, cx| {
26795            container
26796                .flex_shrink_0()
26797                .max_w_80()
26798                .min_h(rems_from_px(124.))
26799                .justify_between()
26800                .child(
26801                    v_flex()
26802                        .flex_1()
26803                        .text_ui_sm(cx)
26804                        .child(Label::new("Conflict with Accept Keybinding"))
26805                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26806                )
26807                .child(
26808                    h_flex()
26809                        .pb_1()
26810                        .gap_1()
26811                        .items_end()
26812                        .w_full()
26813                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26814                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26815                        }))
26816                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26817                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26818                        })),
26819                )
26820        })
26821    }
26822}
26823
26824#[derive(Debug, Clone, Copy, PartialEq)]
26825pub struct LineHighlight {
26826    pub background: Background,
26827    pub border: Option<gpui::Hsla>,
26828    pub include_gutter: bool,
26829    pub type_id: Option<TypeId>,
26830}
26831
26832struct LineManipulationResult {
26833    pub new_text: String,
26834    pub line_count_before: usize,
26835    pub line_count_after: usize,
26836}
26837
26838fn render_diff_hunk_controls(
26839    row: u32,
26840    status: &DiffHunkStatus,
26841    hunk_range: Range<Anchor>,
26842    is_created_file: bool,
26843    line_height: Pixels,
26844    editor: &Entity<Editor>,
26845    _window: &mut Window,
26846    cx: &mut App,
26847) -> AnyElement {
26848    h_flex()
26849        .h(line_height)
26850        .mr_1()
26851        .gap_1()
26852        .px_0p5()
26853        .pb_1()
26854        .border_x_1()
26855        .border_b_1()
26856        .border_color(cx.theme().colors().border_variant)
26857        .rounded_b_lg()
26858        .bg(cx.theme().colors().editor_background)
26859        .gap_1()
26860        .block_mouse_except_scroll()
26861        .shadow_md()
26862        .child(if status.has_secondary_hunk() {
26863            Button::new(("stage", row as u64), "Stage")
26864                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26865                .tooltip({
26866                    let focus_handle = editor.focus_handle(cx);
26867                    move |_window, cx| {
26868                        Tooltip::for_action_in(
26869                            "Stage Hunk",
26870                            &::git::ToggleStaged,
26871                            &focus_handle,
26872                            cx,
26873                        )
26874                    }
26875                })
26876                .on_click({
26877                    let editor = editor.clone();
26878                    move |_event, _window, cx| {
26879                        editor.update(cx, |editor, cx| {
26880                            editor.stage_or_unstage_diff_hunks(
26881                                true,
26882                                vec![hunk_range.start..hunk_range.start],
26883                                cx,
26884                            );
26885                        });
26886                    }
26887                })
26888        } else {
26889            Button::new(("unstage", row as u64), "Unstage")
26890                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26891                .tooltip({
26892                    let focus_handle = editor.focus_handle(cx);
26893                    move |_window, cx| {
26894                        Tooltip::for_action_in(
26895                            "Unstage Hunk",
26896                            &::git::ToggleStaged,
26897                            &focus_handle,
26898                            cx,
26899                        )
26900                    }
26901                })
26902                .on_click({
26903                    let editor = editor.clone();
26904                    move |_event, _window, cx| {
26905                        editor.update(cx, |editor, cx| {
26906                            editor.stage_or_unstage_diff_hunks(
26907                                false,
26908                                vec![hunk_range.start..hunk_range.start],
26909                                cx,
26910                            );
26911                        });
26912                    }
26913                })
26914        })
26915        .child(
26916            Button::new(("restore", row as u64), "Restore")
26917                .tooltip({
26918                    let focus_handle = editor.focus_handle(cx);
26919                    move |_window, cx| {
26920                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26921                    }
26922                })
26923                .on_click({
26924                    let editor = editor.clone();
26925                    move |_event, window, cx| {
26926                        editor.update(cx, |editor, cx| {
26927                            let snapshot = editor.snapshot(window, cx);
26928                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26929                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26930                        });
26931                    }
26932                })
26933                .disabled(is_created_file),
26934        )
26935        .when(
26936            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26937            |el| {
26938                el.child(
26939                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26940                        .shape(IconButtonShape::Square)
26941                        .icon_size(IconSize::Small)
26942                        // .disabled(!has_multiple_hunks)
26943                        .tooltip({
26944                            let focus_handle = editor.focus_handle(cx);
26945                            move |_window, cx| {
26946                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26947                            }
26948                        })
26949                        .on_click({
26950                            let editor = editor.clone();
26951                            move |_event, window, cx| {
26952                                editor.update(cx, |editor, cx| {
26953                                    let snapshot = editor.snapshot(window, cx);
26954                                    let position =
26955                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26956                                    editor.go_to_hunk_before_or_after_position(
26957                                        &snapshot,
26958                                        position,
26959                                        Direction::Next,
26960                                        window,
26961                                        cx,
26962                                    );
26963                                    editor.expand_selected_diff_hunks(cx);
26964                                });
26965                            }
26966                        }),
26967                )
26968                .child(
26969                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26970                        .shape(IconButtonShape::Square)
26971                        .icon_size(IconSize::Small)
26972                        // .disabled(!has_multiple_hunks)
26973                        .tooltip({
26974                            let focus_handle = editor.focus_handle(cx);
26975                            move |_window, cx| {
26976                                Tooltip::for_action_in(
26977                                    "Previous Hunk",
26978                                    &GoToPreviousHunk,
26979                                    &focus_handle,
26980                                    cx,
26981                                )
26982                            }
26983                        })
26984                        .on_click({
26985                            let editor = editor.clone();
26986                            move |_event, window, cx| {
26987                                editor.update(cx, |editor, cx| {
26988                                    let snapshot = editor.snapshot(window, cx);
26989                                    let point =
26990                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26991                                    editor.go_to_hunk_before_or_after_position(
26992                                        &snapshot,
26993                                        point,
26994                                        Direction::Prev,
26995                                        window,
26996                                        cx,
26997                                    );
26998                                    editor.expand_selected_diff_hunks(cx);
26999                                });
27000                            }
27001                        }),
27002                )
27003            },
27004        )
27005        .into_any_element()
27006}
27007
27008pub fn multibuffer_context_lines(cx: &App) -> u32 {
27009    EditorSettings::try_get(cx)
27010        .map(|settings| settings.excerpt_context_lines)
27011        .unwrap_or(2)
27012        .min(32)
27013}