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/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1025///
 1026/// See the [module level documentation](self) for more information.
 1027pub struct Editor {
 1028    focus_handle: FocusHandle,
 1029    last_focused_descendant: Option<WeakFocusHandle>,
 1030    /// The text buffer being edited
 1031    buffer: Entity<MultiBuffer>,
 1032    /// Map of how text in the buffer should be displayed.
 1033    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1034    pub display_map: Entity<DisplayMap>,
 1035    placeholder_display_map: Option<Entity<DisplayMap>>,
 1036    pub selections: SelectionsCollection,
 1037    pub scroll_manager: ScrollManager,
 1038    /// When inline assist editors are linked, they all render cursors because
 1039    /// typing enters text into each of them, even the ones that aren't focused.
 1040    pub(crate) show_cursor_when_unfocused: bool,
 1041    columnar_selection_state: Option<ColumnarSelectionState>,
 1042    add_selections_state: Option<AddSelectionsState>,
 1043    select_next_state: Option<SelectNextState>,
 1044    select_prev_state: Option<SelectNextState>,
 1045    selection_history: SelectionHistory,
 1046    defer_selection_effects: bool,
 1047    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1048    autoclose_regions: Vec<AutocloseRegion>,
 1049    snippet_stack: InvalidationStack<SnippetState>,
 1050    select_syntax_node_history: SelectSyntaxNodeHistory,
 1051    ime_transaction: Option<TransactionId>,
 1052    pub diagnostics_max_severity: DiagnosticSeverity,
 1053    active_diagnostics: ActiveDiagnostic,
 1054    show_inline_diagnostics: bool,
 1055    inline_diagnostics_update: Task<()>,
 1056    inline_diagnostics_enabled: bool,
 1057    diagnostics_enabled: bool,
 1058    word_completions_enabled: bool,
 1059    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1060    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1061    hard_wrap: Option<usize>,
 1062    project: Option<Entity<Project>>,
 1063    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1064    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1065    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1066    blink_manager: Entity<BlinkManager>,
 1067    show_cursor_names: bool,
 1068    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1069    pub show_local_selections: bool,
 1070    mode: EditorMode,
 1071    show_breadcrumbs: bool,
 1072    show_gutter: bool,
 1073    show_scrollbars: ScrollbarAxes,
 1074    minimap_visibility: MinimapVisibility,
 1075    offset_content: bool,
 1076    disable_expand_excerpt_buttons: bool,
 1077    delegate_expand_excerpts: bool,
 1078    show_line_numbers: Option<bool>,
 1079    use_relative_line_numbers: Option<bool>,
 1080    show_git_diff_gutter: Option<bool>,
 1081    show_code_actions: Option<bool>,
 1082    show_runnables: Option<bool>,
 1083    show_breakpoints: Option<bool>,
 1084    show_wrap_guides: Option<bool>,
 1085    show_indent_guides: Option<bool>,
 1086    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1087    highlight_order: usize,
 1088    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1089    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1090    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1091    scrollbar_marker_state: ScrollbarMarkerState,
 1092    active_indent_guides_state: ActiveIndentGuidesState,
 1093    nav_history: Option<ItemNavHistory>,
 1094    context_menu: RefCell<Option<CodeContextMenu>>,
 1095    context_menu_options: Option<ContextMenuOptions>,
 1096    mouse_context_menu: Option<MouseContextMenu>,
 1097    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1098    inline_blame_popover: Option<InlineBlamePopover>,
 1099    inline_blame_popover_show_task: Option<Task<()>>,
 1100    signature_help_state: SignatureHelpState,
 1101    auto_signature_help: Option<bool>,
 1102    find_all_references_task_sources: Vec<Anchor>,
 1103    next_completion_id: CompletionId,
 1104    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1105    code_actions_task: Option<Task<Result<()>>>,
 1106    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1107    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1108    document_highlights_task: Option<Task<()>>,
 1109    linked_editing_range_task: Option<Task<Option<()>>>,
 1110    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1111    pending_rename: Option<RenameState>,
 1112    searchable: bool,
 1113    cursor_shape: CursorShape,
 1114    /// Whether the cursor is offset one character to the left when something is
 1115    /// selected (needed for vim visual mode)
 1116    cursor_offset_on_selection: bool,
 1117    current_line_highlight: Option<CurrentLineHighlight>,
 1118    pub collapse_matches: bool,
 1119    autoindent_mode: Option<AutoindentMode>,
 1120    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1121    input_enabled: bool,
 1122    use_modal_editing: bool,
 1123    read_only: bool,
 1124    leader_id: Option<CollaboratorId>,
 1125    remote_id: Option<ViewId>,
 1126    pub hover_state: HoverState,
 1127    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1128    prev_pressure_stage: Option<PressureStage>,
 1129    gutter_hovered: bool,
 1130    hovered_link_state: Option<HoveredLinkState>,
 1131    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1132    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1133    active_edit_prediction: Option<EditPredictionState>,
 1134    /// Used to prevent flickering as the user types while the menu is open
 1135    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1136    edit_prediction_settings: EditPredictionSettings,
 1137    edit_predictions_hidden_for_vim_mode: bool,
 1138    show_edit_predictions_override: Option<bool>,
 1139    show_completions_on_input_override: Option<bool>,
 1140    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1141    edit_prediction_preview: EditPredictionPreview,
 1142    edit_prediction_indent_conflict: bool,
 1143    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1144    next_inlay_id: usize,
 1145    next_color_inlay_id: usize,
 1146    _subscriptions: Vec<Subscription>,
 1147    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1148    gutter_dimensions: GutterDimensions,
 1149    style: Option<EditorStyle>,
 1150    text_style_refinement: Option<TextStyleRefinement>,
 1151    next_editor_action_id: EditorActionId,
 1152    editor_actions: Rc<
 1153        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1154    >,
 1155    use_autoclose: bool,
 1156    use_auto_surround: bool,
 1157    auto_replace_emoji_shortcode: bool,
 1158    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1159    show_git_blame_gutter: bool,
 1160    show_git_blame_inline: bool,
 1161    show_git_blame_inline_delay_task: Option<Task<()>>,
 1162    git_blame_inline_enabled: bool,
 1163    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1164    buffer_serialization: Option<BufferSerialization>,
 1165    show_selection_menu: Option<bool>,
 1166    blame: Option<Entity<GitBlame>>,
 1167    blame_subscription: Option<Subscription>,
 1168    custom_context_menu: Option<
 1169        Box<
 1170            dyn 'static
 1171                + Fn(
 1172                    &mut Self,
 1173                    DisplayPoint,
 1174                    &mut Window,
 1175                    &mut Context<Self>,
 1176                ) -> Option<Entity<ui::ContextMenu>>,
 1177        >,
 1178    >,
 1179    last_bounds: Option<Bounds<Pixels>>,
 1180    last_position_map: Option<Rc<PositionMap>>,
 1181    expect_bounds_change: Option<Bounds<Pixels>>,
 1182    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1183    tasks_update_task: Option<Task<()>>,
 1184    breakpoint_store: Option<Entity<BreakpointStore>>,
 1185    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1186    hovered_diff_hunk_row: Option<DisplayRow>,
 1187    pull_diagnostics_task: Task<()>,
 1188    pull_diagnostics_background_task: Task<()>,
 1189    in_project_search: bool,
 1190    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1191    breadcrumb_header: Option<String>,
 1192    focused_block: Option<FocusedBlock>,
 1193    next_scroll_position: NextScrollCursorCenterTopBottom,
 1194    addons: HashMap<TypeId, Box<dyn Addon>>,
 1195    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1196    load_diff_task: Option<Shared<Task<()>>>,
 1197    /// Whether we are temporarily displaying a diff other than git's
 1198    temporary_diff_override: bool,
 1199    selection_mark_mode: bool,
 1200    toggle_fold_multiple_buffers: Task<()>,
 1201    _scroll_cursor_center_top_bottom_task: Task<()>,
 1202    serialize_selections: Task<()>,
 1203    serialize_folds: Task<()>,
 1204    mouse_cursor_hidden: bool,
 1205    minimap: Option<Entity<Self>>,
 1206    hide_mouse_mode: HideMouseMode,
 1207    pub change_list: ChangeList,
 1208    inline_value_cache: InlineValueCache,
 1209    number_deleted_lines: bool,
 1210
 1211    selection_drag_state: SelectionDragState,
 1212    colors: Option<LspColorData>,
 1213    post_scroll_update: Task<()>,
 1214    refresh_colors_task: Task<()>,
 1215    inlay_hints: Option<LspInlayHintData>,
 1216    folding_newlines: Task<()>,
 1217    select_next_is_case_sensitive: Option<bool>,
 1218    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1219    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1220    accent_data: Option<AccentData>,
 1221    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1222}
 1223
 1224#[derive(Debug, PartialEq)]
 1225struct AccentData {
 1226    colors: AccentColors,
 1227    overrides: Vec<SharedString>,
 1228}
 1229
 1230fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1231    if debounce_ms > 0 {
 1232        Some(Duration::from_millis(debounce_ms))
 1233    } else {
 1234        None
 1235    }
 1236}
 1237
 1238#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1239enum NextScrollCursorCenterTopBottom {
 1240    #[default]
 1241    Center,
 1242    Top,
 1243    Bottom,
 1244}
 1245
 1246impl NextScrollCursorCenterTopBottom {
 1247    fn next(&self) -> Self {
 1248        match self {
 1249            Self::Center => Self::Top,
 1250            Self::Top => Self::Bottom,
 1251            Self::Bottom => Self::Center,
 1252        }
 1253    }
 1254}
 1255
 1256#[derive(Clone)]
 1257pub struct EditorSnapshot {
 1258    pub mode: EditorMode,
 1259    show_gutter: bool,
 1260    offset_content: bool,
 1261    show_line_numbers: Option<bool>,
 1262    number_deleted_lines: bool,
 1263    show_git_diff_gutter: Option<bool>,
 1264    show_code_actions: Option<bool>,
 1265    show_runnables: Option<bool>,
 1266    show_breakpoints: Option<bool>,
 1267    git_blame_gutter_max_author_length: Option<usize>,
 1268    pub display_snapshot: DisplaySnapshot,
 1269    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1270    is_focused: bool,
 1271    scroll_anchor: ScrollAnchor,
 1272    ongoing_scroll: OngoingScroll,
 1273    current_line_highlight: CurrentLineHighlight,
 1274    gutter_hovered: bool,
 1275}
 1276
 1277#[derive(Default, Debug, Clone, Copy)]
 1278pub struct GutterDimensions {
 1279    pub left_padding: Pixels,
 1280    pub right_padding: Pixels,
 1281    pub width: Pixels,
 1282    pub margin: Pixels,
 1283    pub git_blame_entries_width: Option<Pixels>,
 1284}
 1285
 1286impl GutterDimensions {
 1287    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1288        Self {
 1289            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1290            ..Default::default()
 1291        }
 1292    }
 1293
 1294    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1295        -cx.text_system().descent(font_id, font_size)
 1296    }
 1297    /// The full width of the space taken up by the gutter.
 1298    pub fn full_width(&self) -> Pixels {
 1299        self.margin + self.width
 1300    }
 1301
 1302    /// The width of the space reserved for the fold indicators,
 1303    /// use alongside 'justify_end' and `gutter_width` to
 1304    /// right align content with the line numbers
 1305    pub fn fold_area_width(&self) -> Pixels {
 1306        self.margin + self.right_padding
 1307    }
 1308}
 1309
 1310struct CharacterDimensions {
 1311    em_width: Pixels,
 1312    em_advance: Pixels,
 1313    line_height: Pixels,
 1314}
 1315
 1316#[derive(Debug)]
 1317pub struct RemoteSelection {
 1318    pub replica_id: ReplicaId,
 1319    pub selection: Selection<Anchor>,
 1320    pub cursor_shape: CursorShape,
 1321    pub collaborator_id: CollaboratorId,
 1322    pub line_mode: bool,
 1323    pub user_name: Option<SharedString>,
 1324    pub color: PlayerColor,
 1325}
 1326
 1327#[derive(Clone, Debug)]
 1328struct SelectionHistoryEntry {
 1329    selections: Arc<[Selection<Anchor>]>,
 1330    select_next_state: Option<SelectNextState>,
 1331    select_prev_state: Option<SelectNextState>,
 1332    add_selections_state: Option<AddSelectionsState>,
 1333}
 1334
 1335#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1336enum SelectionHistoryMode {
 1337    #[default]
 1338    Normal,
 1339    Undoing,
 1340    Redoing,
 1341    Skipping,
 1342}
 1343
 1344#[derive(Clone, PartialEq, Eq, Hash)]
 1345struct HoveredCursor {
 1346    replica_id: ReplicaId,
 1347    selection_id: usize,
 1348}
 1349
 1350#[derive(Debug)]
 1351/// SelectionEffects controls the side-effects of updating the selection.
 1352///
 1353/// The default behaviour does "what you mostly want":
 1354/// - it pushes to the nav history if the cursor moved by >10 lines
 1355/// - it re-triggers completion requests
 1356/// - it scrolls to fit
 1357///
 1358/// You might want to modify these behaviours. For example when doing a "jump"
 1359/// like go to definition, we always want to add to nav history; but when scrolling
 1360/// in vim mode we never do.
 1361///
 1362/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1363/// move.
 1364#[derive(Clone)]
 1365pub struct SelectionEffects {
 1366    nav_history: Option<bool>,
 1367    completions: bool,
 1368    scroll: Option<Autoscroll>,
 1369}
 1370
 1371impl Default for SelectionEffects {
 1372    fn default() -> Self {
 1373        Self {
 1374            nav_history: None,
 1375            completions: true,
 1376            scroll: Some(Autoscroll::fit()),
 1377        }
 1378    }
 1379}
 1380impl SelectionEffects {
 1381    pub fn scroll(scroll: Autoscroll) -> Self {
 1382        Self {
 1383            scroll: Some(scroll),
 1384            ..Default::default()
 1385        }
 1386    }
 1387
 1388    pub fn no_scroll() -> Self {
 1389        Self {
 1390            scroll: None,
 1391            ..Default::default()
 1392        }
 1393    }
 1394
 1395    pub fn completions(self, completions: bool) -> Self {
 1396        Self {
 1397            completions,
 1398            ..self
 1399        }
 1400    }
 1401
 1402    pub fn nav_history(self, nav_history: bool) -> Self {
 1403        Self {
 1404            nav_history: Some(nav_history),
 1405            ..self
 1406        }
 1407    }
 1408}
 1409
 1410struct DeferredSelectionEffectsState {
 1411    changed: bool,
 1412    effects: SelectionEffects,
 1413    old_cursor_position: Anchor,
 1414    history_entry: SelectionHistoryEntry,
 1415}
 1416
 1417#[derive(Default)]
 1418struct SelectionHistory {
 1419    #[allow(clippy::type_complexity)]
 1420    selections_by_transaction:
 1421        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1422    mode: SelectionHistoryMode,
 1423    undo_stack: VecDeque<SelectionHistoryEntry>,
 1424    redo_stack: VecDeque<SelectionHistoryEntry>,
 1425}
 1426
 1427impl SelectionHistory {
 1428    #[track_caller]
 1429    fn insert_transaction(
 1430        &mut self,
 1431        transaction_id: TransactionId,
 1432        selections: Arc<[Selection<Anchor>]>,
 1433    ) {
 1434        if selections.is_empty() {
 1435            log::error!(
 1436                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1437                std::panic::Location::caller()
 1438            );
 1439            return;
 1440        }
 1441        self.selections_by_transaction
 1442            .insert(transaction_id, (selections, None));
 1443    }
 1444
 1445    #[allow(clippy::type_complexity)]
 1446    fn transaction(
 1447        &self,
 1448        transaction_id: TransactionId,
 1449    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1450        self.selections_by_transaction.get(&transaction_id)
 1451    }
 1452
 1453    #[allow(clippy::type_complexity)]
 1454    fn transaction_mut(
 1455        &mut self,
 1456        transaction_id: TransactionId,
 1457    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1458        self.selections_by_transaction.get_mut(&transaction_id)
 1459    }
 1460
 1461    fn push(&mut self, entry: SelectionHistoryEntry) {
 1462        if !entry.selections.is_empty() {
 1463            match self.mode {
 1464                SelectionHistoryMode::Normal => {
 1465                    self.push_undo(entry);
 1466                    self.redo_stack.clear();
 1467                }
 1468                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1469                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1470                SelectionHistoryMode::Skipping => {}
 1471            }
 1472        }
 1473    }
 1474
 1475    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1476        if self
 1477            .undo_stack
 1478            .back()
 1479            .is_none_or(|e| e.selections != entry.selections)
 1480        {
 1481            self.undo_stack.push_back(entry);
 1482            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1483                self.undo_stack.pop_front();
 1484            }
 1485        }
 1486    }
 1487
 1488    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1489        if self
 1490            .redo_stack
 1491            .back()
 1492            .is_none_or(|e| e.selections != entry.selections)
 1493        {
 1494            self.redo_stack.push_back(entry);
 1495            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1496                self.redo_stack.pop_front();
 1497            }
 1498        }
 1499    }
 1500}
 1501
 1502#[derive(Clone, Copy)]
 1503pub struct RowHighlightOptions {
 1504    pub autoscroll: bool,
 1505    pub include_gutter: bool,
 1506}
 1507
 1508impl Default for RowHighlightOptions {
 1509    fn default() -> Self {
 1510        Self {
 1511            autoscroll: Default::default(),
 1512            include_gutter: true,
 1513        }
 1514    }
 1515}
 1516
 1517struct RowHighlight {
 1518    index: usize,
 1519    range: Range<Anchor>,
 1520    color: Hsla,
 1521    options: RowHighlightOptions,
 1522    type_id: TypeId,
 1523}
 1524
 1525#[derive(Clone, Debug)]
 1526struct AddSelectionsState {
 1527    groups: Vec<AddSelectionsGroup>,
 1528}
 1529
 1530#[derive(Clone, Debug)]
 1531struct AddSelectionsGroup {
 1532    above: bool,
 1533    stack: Vec<usize>,
 1534}
 1535
 1536#[derive(Clone)]
 1537struct SelectNextState {
 1538    query: AhoCorasick,
 1539    wordwise: bool,
 1540    done: bool,
 1541}
 1542
 1543impl std::fmt::Debug for SelectNextState {
 1544    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1545        f.debug_struct(std::any::type_name::<Self>())
 1546            .field("wordwise", &self.wordwise)
 1547            .field("done", &self.done)
 1548            .finish()
 1549    }
 1550}
 1551
 1552#[derive(Debug)]
 1553struct AutocloseRegion {
 1554    selection_id: usize,
 1555    range: Range<Anchor>,
 1556    pair: BracketPair,
 1557}
 1558
 1559#[derive(Debug)]
 1560struct SnippetState {
 1561    ranges: Vec<Vec<Range<Anchor>>>,
 1562    active_index: usize,
 1563    choices: Vec<Option<Vec<String>>>,
 1564}
 1565
 1566#[doc(hidden)]
 1567pub struct RenameState {
 1568    pub range: Range<Anchor>,
 1569    pub old_name: Arc<str>,
 1570    pub editor: Entity<Editor>,
 1571    block_id: CustomBlockId,
 1572}
 1573
 1574struct InvalidationStack<T>(Vec<T>);
 1575
 1576struct RegisteredEditPredictionDelegate {
 1577    provider: Arc<dyn EditPredictionDelegateHandle>,
 1578    _subscription: Subscription,
 1579}
 1580
 1581#[derive(Debug, PartialEq, Eq)]
 1582pub struct ActiveDiagnosticGroup {
 1583    pub active_range: Range<Anchor>,
 1584    pub active_message: String,
 1585    pub group_id: usize,
 1586    pub blocks: HashSet<CustomBlockId>,
 1587}
 1588
 1589#[derive(Debug, PartialEq, Eq)]
 1590
 1591pub(crate) enum ActiveDiagnostic {
 1592    None,
 1593    All,
 1594    Group(ActiveDiagnosticGroup),
 1595}
 1596
 1597#[derive(Serialize, Deserialize, Clone, Debug)]
 1598pub struct ClipboardSelection {
 1599    /// The number of bytes in this selection.
 1600    pub len: usize,
 1601    /// Whether this was a full-line selection.
 1602    pub is_entire_line: bool,
 1603    /// The indentation of the first line when this content was originally copied.
 1604    pub first_line_indent: u32,
 1605    #[serde(default)]
 1606    pub file_path: Option<PathBuf>,
 1607    #[serde(default)]
 1608    pub line_range: Option<RangeInclusive<u32>>,
 1609}
 1610
 1611impl ClipboardSelection {
 1612    pub fn for_buffer(
 1613        len: usize,
 1614        is_entire_line: bool,
 1615        range: Range<Point>,
 1616        buffer: &MultiBufferSnapshot,
 1617        project: Option<&Entity<Project>>,
 1618        cx: &App,
 1619    ) -> Self {
 1620        let first_line_indent = buffer
 1621            .indent_size_for_line(MultiBufferRow(range.start.row))
 1622            .len;
 1623
 1624        let file_path = util::maybe!({
 1625            let project = project?.read(cx);
 1626            let file = buffer.file_at(range.start)?;
 1627            let project_path = ProjectPath {
 1628                worktree_id: file.worktree_id(cx),
 1629                path: file.path().clone(),
 1630            };
 1631            project.absolute_path(&project_path, cx)
 1632        });
 1633
 1634        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1635
 1636        Self {
 1637            len,
 1638            is_entire_line,
 1639            first_line_indent,
 1640            file_path,
 1641            line_range,
 1642        }
 1643    }
 1644}
 1645
 1646// selections, scroll behavior, was newest selection reversed
 1647type SelectSyntaxNodeHistoryState = (
 1648    Box<[Selection<MultiBufferOffset>]>,
 1649    SelectSyntaxNodeScrollBehavior,
 1650    bool,
 1651);
 1652
 1653#[derive(Default)]
 1654struct SelectSyntaxNodeHistory {
 1655    stack: Vec<SelectSyntaxNodeHistoryState>,
 1656    // disable temporarily to allow changing selections without losing the stack
 1657    pub disable_clearing: bool,
 1658}
 1659
 1660impl SelectSyntaxNodeHistory {
 1661    pub fn try_clear(&mut self) {
 1662        if !self.disable_clearing {
 1663            self.stack.clear();
 1664        }
 1665    }
 1666
 1667    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1668        self.stack.push(selection);
 1669    }
 1670
 1671    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1672        self.stack.pop()
 1673    }
 1674}
 1675
 1676enum SelectSyntaxNodeScrollBehavior {
 1677    CursorTop,
 1678    FitSelection,
 1679    CursorBottom,
 1680}
 1681
 1682#[derive(Debug)]
 1683pub(crate) struct NavigationData {
 1684    cursor_anchor: Anchor,
 1685    cursor_position: Point,
 1686    scroll_anchor: ScrollAnchor,
 1687    scroll_top_row: u32,
 1688}
 1689
 1690#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1691pub enum GotoDefinitionKind {
 1692    Symbol,
 1693    Declaration,
 1694    Type,
 1695    Implementation,
 1696}
 1697
 1698pub enum FormatTarget {
 1699    Buffers(HashSet<Entity<Buffer>>),
 1700    Ranges(Vec<Range<MultiBufferPoint>>),
 1701}
 1702
 1703pub(crate) struct FocusedBlock {
 1704    id: BlockId,
 1705    focus_handle: WeakFocusHandle,
 1706}
 1707
 1708#[derive(Clone, Debug)]
 1709enum JumpData {
 1710    MultiBufferRow {
 1711        row: MultiBufferRow,
 1712        line_offset_from_top: u32,
 1713    },
 1714    MultiBufferPoint {
 1715        excerpt_id: ExcerptId,
 1716        position: Point,
 1717        anchor: text::Anchor,
 1718        line_offset_from_top: u32,
 1719    },
 1720}
 1721
 1722pub enum MultibufferSelectionMode {
 1723    First,
 1724    All,
 1725}
 1726
 1727#[derive(Clone, Copy, Debug, Default)]
 1728pub struct RewrapOptions {
 1729    pub override_language_settings: bool,
 1730    pub preserve_existing_whitespace: bool,
 1731}
 1732
 1733impl Editor {
 1734    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1735        let buffer = cx.new(|cx| Buffer::local("", cx));
 1736        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1737        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1738    }
 1739
 1740    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let buffer = cx.new(|cx| Buffer::local("", cx));
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, None, window, cx)
 1744    }
 1745
 1746    pub fn auto_height(
 1747        min_lines: usize,
 1748        max_lines: usize,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        let buffer = cx.new(|cx| Buffer::local("", cx));
 1753        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1754        Self::new(
 1755            EditorMode::AutoHeight {
 1756                min_lines,
 1757                max_lines: Some(max_lines),
 1758            },
 1759            buffer,
 1760            None,
 1761            window,
 1762            cx,
 1763        )
 1764    }
 1765
 1766    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1767    /// The editor grows as tall as needed to fit its content.
 1768    pub fn auto_height_unbounded(
 1769        min_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: None,
 1779            },
 1780            buffer,
 1781            None,
 1782            window,
 1783            cx,
 1784        )
 1785    }
 1786
 1787    pub fn for_buffer(
 1788        buffer: Entity<Buffer>,
 1789        project: Option<Entity<Project>>,
 1790        window: &mut Window,
 1791        cx: &mut Context<Self>,
 1792    ) -> Self {
 1793        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1794        Self::new(EditorMode::full(), buffer, project, window, cx)
 1795    }
 1796
 1797    pub fn for_multibuffer(
 1798        buffer: Entity<MultiBuffer>,
 1799        project: Option<Entity<Project>>,
 1800        window: &mut Window,
 1801        cx: &mut Context<Self>,
 1802    ) -> Self {
 1803        Self::new(EditorMode::full(), buffer, project, window, cx)
 1804    }
 1805
 1806    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1807        let mut clone = Self::new(
 1808            self.mode.clone(),
 1809            self.buffer.clone(),
 1810            self.project.clone(),
 1811            window,
 1812            cx,
 1813        );
 1814        self.display_map.update(cx, |display_map, cx| {
 1815            let snapshot = display_map.snapshot(cx);
 1816            clone.display_map.update(cx, |display_map, cx| {
 1817                display_map.set_state(&snapshot, cx);
 1818            });
 1819        });
 1820        clone.folds_did_change(cx);
 1821        clone.selections.clone_state(&self.selections);
 1822        clone.scroll_manager.clone_state(&self.scroll_manager);
 1823        clone.searchable = self.searchable;
 1824        clone.read_only = self.read_only;
 1825        clone
 1826    }
 1827
 1828    pub fn new(
 1829        mode: EditorMode,
 1830        buffer: Entity<MultiBuffer>,
 1831        project: Option<Entity<Project>>,
 1832        window: &mut Window,
 1833        cx: &mut Context<Self>,
 1834    ) -> Self {
 1835        Editor::new_internal(mode, buffer, project, None, window, cx)
 1836    }
 1837
 1838    pub fn sticky_headers(
 1839        &self,
 1840        style: &EditorStyle,
 1841        cx: &App,
 1842    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1843        let multi_buffer = self.buffer().read(cx);
 1844        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1845        let multi_buffer_visible_start = self
 1846            .scroll_manager
 1847            .anchor()
 1848            .anchor
 1849            .to_point(&multi_buffer_snapshot);
 1850        let max_row = multi_buffer_snapshot.max_point().row;
 1851
 1852        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1853        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1854
 1855        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1856            let outline_items = buffer
 1857                .outline_items_containing(
 1858                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1859                    true,
 1860                    Some(style.syntax.as_ref()),
 1861                )
 1862                .into_iter()
 1863                .map(|outline_item| OutlineItem {
 1864                    depth: outline_item.depth,
 1865                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1866                    source_range_for_text: Anchor::range_in_buffer(
 1867                        *excerpt_id,
 1868                        outline_item.source_range_for_text,
 1869                    ),
 1870                    text: outline_item.text,
 1871                    highlight_ranges: outline_item.highlight_ranges,
 1872                    name_ranges: outline_item.name_ranges,
 1873                    body_range: outline_item
 1874                        .body_range
 1875                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1876                    annotation_range: outline_item
 1877                        .annotation_range
 1878                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1879                });
 1880            return Some(outline_items.collect());
 1881        }
 1882
 1883        None
 1884    }
 1885
 1886    fn new_internal(
 1887        mode: EditorMode,
 1888        multi_buffer: Entity<MultiBuffer>,
 1889        project: Option<Entity<Project>>,
 1890        display_map: Option<Entity<DisplayMap>>,
 1891        window: &mut Window,
 1892        cx: &mut Context<Self>,
 1893    ) -> Self {
 1894        debug_assert!(
 1895            display_map.is_none() || mode.is_minimap(),
 1896            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1897        );
 1898
 1899        let full_mode = mode.is_full();
 1900        let is_minimap = mode.is_minimap();
 1901        let diagnostics_max_severity = if full_mode {
 1902            EditorSettings::get_global(cx)
 1903                .diagnostics_max_severity
 1904                .unwrap_or(DiagnosticSeverity::Hint)
 1905        } else {
 1906            DiagnosticSeverity::Off
 1907        };
 1908        let style = window.text_style();
 1909        let font_size = style.font_size.to_pixels(window.rem_size());
 1910        let editor = cx.entity().downgrade();
 1911        let fold_placeholder = FoldPlaceholder {
 1912            constrain_width: false,
 1913            render: Arc::new(move |fold_id, fold_range, cx| {
 1914                let editor = editor.clone();
 1915                div()
 1916                    .id(fold_id)
 1917                    .bg(cx.theme().colors().ghost_element_background)
 1918                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1919                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1920                    .rounded_xs()
 1921                    .size_full()
 1922                    .cursor_pointer()
 1923                    .child("")
 1924                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1925                    .on_click(move |_, _window, cx| {
 1926                        editor
 1927                            .update(cx, |editor, cx| {
 1928                                editor.unfold_ranges(
 1929                                    &[fold_range.start..fold_range.end],
 1930                                    true,
 1931                                    false,
 1932                                    cx,
 1933                                );
 1934                                cx.stop_propagation();
 1935                            })
 1936                            .ok();
 1937                    })
 1938                    .into_any()
 1939            }),
 1940            merge_adjacent: true,
 1941            ..FoldPlaceholder::default()
 1942        };
 1943        let display_map = display_map.unwrap_or_else(|| {
 1944            cx.new(|cx| {
 1945                DisplayMap::new(
 1946                    multi_buffer.clone(),
 1947                    style.font(),
 1948                    font_size,
 1949                    None,
 1950                    FILE_HEADER_HEIGHT,
 1951                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1952                    fold_placeholder,
 1953                    diagnostics_max_severity,
 1954                    cx,
 1955                )
 1956            })
 1957        });
 1958
 1959        let selections = SelectionsCollection::new();
 1960
 1961        let blink_manager = cx.new(|cx| {
 1962            let mut blink_manager = BlinkManager::new(
 1963                CURSOR_BLINK_INTERVAL,
 1964                |cx| EditorSettings::get_global(cx).cursor_blink,
 1965                cx,
 1966            );
 1967            if is_minimap {
 1968                blink_manager.disable(cx);
 1969            }
 1970            blink_manager
 1971        });
 1972
 1973        let soft_wrap_mode_override =
 1974            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1975
 1976        let mut project_subscriptions = Vec::new();
 1977        if full_mode && let Some(project) = project.as_ref() {
 1978            project_subscriptions.push(cx.subscribe_in(
 1979                project,
 1980                window,
 1981                |editor, _, event, window, cx| match event {
 1982                    project::Event::RefreshCodeLens => {
 1983                        // we always query lens with actions, without storing them, always refreshing them
 1984                    }
 1985                    project::Event::RefreshInlayHints {
 1986                        server_id,
 1987                        request_id,
 1988                    } => {
 1989                        editor.refresh_inlay_hints(
 1990                            InlayHintRefreshReason::RefreshRequested {
 1991                                server_id: *server_id,
 1992                                request_id: *request_id,
 1993                            },
 1994                            cx,
 1995                        );
 1996                    }
 1997                    project::Event::LanguageServerRemoved(..) => {
 1998                        if editor.tasks_update_task.is_none() {
 1999                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2000                        }
 2001                        editor.registered_buffers.clear();
 2002                        editor.register_visible_buffers(cx);
 2003                    }
 2004                    project::Event::LanguageServerAdded(..) => {
 2005                        if editor.tasks_update_task.is_none() {
 2006                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2007                        }
 2008                    }
 2009                    project::Event::SnippetEdit(id, snippet_edits) => {
 2010                        // todo(lw): Non singletons
 2011                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2012                            let snapshot = buffer.read(cx).snapshot();
 2013                            let focus_handle = editor.focus_handle(cx);
 2014                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2015                                for (range, snippet) in snippet_edits {
 2016                                    let buffer_range =
 2017                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2018                                    editor
 2019                                        .insert_snippet(
 2020                                            &[MultiBufferOffset(buffer_range.start)
 2021                                                ..MultiBufferOffset(buffer_range.end)],
 2022                                            snippet.clone(),
 2023                                            window,
 2024                                            cx,
 2025                                        )
 2026                                        .ok();
 2027                                }
 2028                            }
 2029                        }
 2030                    }
 2031                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2032                        let buffer_id = *buffer_id;
 2033                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2034                            editor.register_buffer(buffer_id, cx);
 2035                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2036                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2037                            refresh_linked_ranges(editor, window, cx);
 2038                            editor.refresh_code_actions(window, cx);
 2039                            editor.refresh_document_highlights(cx);
 2040                        }
 2041                    }
 2042
 2043                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2044                        let Some(workspace) = editor.workspace() else {
 2045                            return;
 2046                        };
 2047                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2048                        else {
 2049                            return;
 2050                        };
 2051
 2052                        if active_editor.entity_id() == cx.entity_id() {
 2053                            let entity_id = cx.entity_id();
 2054                            workspace.update(cx, |this, cx| {
 2055                                this.panes_mut()
 2056                                    .iter_mut()
 2057                                    .filter(|pane| pane.entity_id() != entity_id)
 2058                                    .for_each(|p| {
 2059                                        p.update(cx, |pane, _| {
 2060                                            pane.nav_history_mut().rename_item(
 2061                                                entity_id,
 2062                                                project_path.clone(),
 2063                                                abs_path.clone().into(),
 2064                                            );
 2065                                        })
 2066                                    });
 2067                            });
 2068
 2069                            Self::open_transaction_for_hidden_buffers(
 2070                                workspace,
 2071                                transaction.clone(),
 2072                                "Rename".to_string(),
 2073                                window,
 2074                                cx,
 2075                            );
 2076                        }
 2077                    }
 2078
 2079                    project::Event::WorkspaceEditApplied(transaction) => {
 2080                        let Some(workspace) = editor.workspace() else {
 2081                            return;
 2082                        };
 2083                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2084                        else {
 2085                            return;
 2086                        };
 2087
 2088                        if active_editor.entity_id() == cx.entity_id() {
 2089                            Self::open_transaction_for_hidden_buffers(
 2090                                workspace,
 2091                                transaction.clone(),
 2092                                "LSP Edit".to_string(),
 2093                                window,
 2094                                cx,
 2095                            );
 2096                        }
 2097                    }
 2098
 2099                    _ => {}
 2100                },
 2101            ));
 2102            if let Some(task_inventory) = project
 2103                .read(cx)
 2104                .task_store()
 2105                .read(cx)
 2106                .task_inventory()
 2107                .cloned()
 2108            {
 2109                project_subscriptions.push(cx.observe_in(
 2110                    &task_inventory,
 2111                    window,
 2112                    |editor, _, window, cx| {
 2113                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2114                    },
 2115                ));
 2116            };
 2117
 2118            project_subscriptions.push(cx.subscribe_in(
 2119                &project.read(cx).breakpoint_store(),
 2120                window,
 2121                |editor, _, event, window, cx| match event {
 2122                    BreakpointStoreEvent::ClearDebugLines => {
 2123                        editor.clear_row_highlights::<ActiveDebugLine>();
 2124                        editor.refresh_inline_values(cx);
 2125                    }
 2126                    BreakpointStoreEvent::SetDebugLine => {
 2127                        if editor.go_to_active_debug_line(window, cx) {
 2128                            cx.stop_propagation();
 2129                        }
 2130
 2131                        editor.refresh_inline_values(cx);
 2132                    }
 2133                    _ => {}
 2134                },
 2135            ));
 2136            let git_store = project.read(cx).git_store().clone();
 2137            let project = project.clone();
 2138            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2139                if let GitStoreEvent::RepositoryAdded = event {
 2140                    this.load_diff_task = Some(
 2141                        update_uncommitted_diff_for_buffer(
 2142                            cx.entity(),
 2143                            &project,
 2144                            this.buffer.read(cx).all_buffers(),
 2145                            this.buffer.clone(),
 2146                            cx,
 2147                        )
 2148                        .shared(),
 2149                    );
 2150                }
 2151            }));
 2152        }
 2153
 2154        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2155
 2156        let inlay_hint_settings =
 2157            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2158        let focus_handle = cx.focus_handle();
 2159        if !is_minimap {
 2160            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2161                .detach();
 2162            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2163                .detach();
 2164            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2165                .detach();
 2166            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2167                .detach();
 2168            cx.observe_pending_input(window, Self::observe_pending_input)
 2169                .detach();
 2170        }
 2171
 2172        let show_indent_guides =
 2173            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2174                Some(false)
 2175            } else {
 2176                None
 2177            };
 2178
 2179        let breakpoint_store = match (&mode, project.as_ref()) {
 2180            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2181            _ => None,
 2182        };
 2183
 2184        let mut code_action_providers = Vec::new();
 2185        let mut load_uncommitted_diff = None;
 2186        if let Some(project) = project.clone() {
 2187            load_uncommitted_diff = Some(
 2188                update_uncommitted_diff_for_buffer(
 2189                    cx.entity(),
 2190                    &project,
 2191                    multi_buffer.read(cx).all_buffers(),
 2192                    multi_buffer.clone(),
 2193                    cx,
 2194                )
 2195                .shared(),
 2196            );
 2197            code_action_providers.push(Rc::new(project) as Rc<_>);
 2198        }
 2199
 2200        let mut editor = Self {
 2201            focus_handle,
 2202            show_cursor_when_unfocused: false,
 2203            last_focused_descendant: None,
 2204            buffer: multi_buffer.clone(),
 2205            display_map: display_map.clone(),
 2206            placeholder_display_map: None,
 2207            selections,
 2208            scroll_manager: ScrollManager::new(cx),
 2209            columnar_selection_state: None,
 2210            add_selections_state: None,
 2211            select_next_state: None,
 2212            select_prev_state: None,
 2213            selection_history: SelectionHistory::default(),
 2214            defer_selection_effects: false,
 2215            deferred_selection_effects_state: None,
 2216            autoclose_regions: Vec::new(),
 2217            snippet_stack: InvalidationStack::default(),
 2218            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2219            ime_transaction: None,
 2220            active_diagnostics: ActiveDiagnostic::None,
 2221            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2222            inline_diagnostics_update: Task::ready(()),
 2223            inline_diagnostics: Vec::new(),
 2224            soft_wrap_mode_override,
 2225            diagnostics_max_severity,
 2226            hard_wrap: None,
 2227            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2228            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2229            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2230            project,
 2231            blink_manager: blink_manager.clone(),
 2232            show_local_selections: true,
 2233            show_scrollbars: ScrollbarAxes {
 2234                horizontal: full_mode,
 2235                vertical: full_mode,
 2236            },
 2237            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2238            offset_content: !matches!(mode, EditorMode::SingleLine),
 2239            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2240            show_gutter: full_mode,
 2241            show_line_numbers: (!full_mode).then_some(false),
 2242            use_relative_line_numbers: None,
 2243            disable_expand_excerpt_buttons: !full_mode,
 2244            delegate_expand_excerpts: false,
 2245            show_git_diff_gutter: None,
 2246            show_code_actions: None,
 2247            show_runnables: None,
 2248            show_breakpoints: None,
 2249            show_wrap_guides: None,
 2250            show_indent_guides,
 2251            buffers_with_disabled_indent_guides: HashSet::default(),
 2252            highlight_order: 0,
 2253            highlighted_rows: HashMap::default(),
 2254            background_highlights: HashMap::default(),
 2255            gutter_highlights: HashMap::default(),
 2256            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2257            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2258            nav_history: None,
 2259            context_menu: RefCell::new(None),
 2260            context_menu_options: None,
 2261            mouse_context_menu: None,
 2262            completion_tasks: Vec::new(),
 2263            inline_blame_popover: None,
 2264            inline_blame_popover_show_task: None,
 2265            signature_help_state: SignatureHelpState::default(),
 2266            auto_signature_help: None,
 2267            find_all_references_task_sources: Vec::new(),
 2268            next_completion_id: 0,
 2269            next_inlay_id: 0,
 2270            code_action_providers,
 2271            available_code_actions: None,
 2272            code_actions_task: None,
 2273            quick_selection_highlight_task: None,
 2274            debounced_selection_highlight_task: None,
 2275            document_highlights_task: None,
 2276            linked_editing_range_task: None,
 2277            pending_rename: None,
 2278            searchable: !is_minimap,
 2279            cursor_shape: EditorSettings::get_global(cx)
 2280                .cursor_shape
 2281                .unwrap_or_default(),
 2282            cursor_offset_on_selection: false,
 2283            current_line_highlight: None,
 2284            autoindent_mode: Some(AutoindentMode::EachLine),
 2285            collapse_matches: false,
 2286            workspace: None,
 2287            input_enabled: !is_minimap,
 2288            use_modal_editing: full_mode,
 2289            read_only: is_minimap,
 2290            use_autoclose: true,
 2291            use_auto_surround: true,
 2292            auto_replace_emoji_shortcode: false,
 2293            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2294            leader_id: None,
 2295            remote_id: None,
 2296            hover_state: HoverState::default(),
 2297            pending_mouse_down: None,
 2298            prev_pressure_stage: None,
 2299            hovered_link_state: None,
 2300            edit_prediction_provider: None,
 2301            active_edit_prediction: None,
 2302            stale_edit_prediction_in_menu: None,
 2303            edit_prediction_preview: EditPredictionPreview::Inactive {
 2304                released_too_fast: false,
 2305            },
 2306            inline_diagnostics_enabled: full_mode,
 2307            diagnostics_enabled: full_mode,
 2308            word_completions_enabled: full_mode,
 2309            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2310            gutter_hovered: false,
 2311            pixel_position_of_newest_cursor: None,
 2312            last_bounds: None,
 2313            last_position_map: None,
 2314            expect_bounds_change: None,
 2315            gutter_dimensions: GutterDimensions::default(),
 2316            style: None,
 2317            show_cursor_names: false,
 2318            hovered_cursors: HashMap::default(),
 2319            next_editor_action_id: EditorActionId::default(),
 2320            editor_actions: Rc::default(),
 2321            edit_predictions_hidden_for_vim_mode: false,
 2322            show_edit_predictions_override: None,
 2323            show_completions_on_input_override: None,
 2324            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2325            edit_prediction_settings: EditPredictionSettings::Disabled,
 2326            edit_prediction_indent_conflict: false,
 2327            edit_prediction_requires_modifier_in_indent_conflict: true,
 2328            custom_context_menu: None,
 2329            show_git_blame_gutter: false,
 2330            show_git_blame_inline: false,
 2331            show_selection_menu: None,
 2332            show_git_blame_inline_delay_task: None,
 2333            git_blame_inline_enabled: full_mode
 2334                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2335            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2336            buffer_serialization: is_minimap.not().then(|| {
 2337                BufferSerialization::new(
 2338                    ProjectSettings::get_global(cx)
 2339                        .session
 2340                        .restore_unsaved_buffers,
 2341                )
 2342            }),
 2343            blame: None,
 2344            blame_subscription: None,
 2345            tasks: BTreeMap::default(),
 2346
 2347            breakpoint_store,
 2348            gutter_breakpoint_indicator: (None, None),
 2349            hovered_diff_hunk_row: None,
 2350            _subscriptions: (!is_minimap)
 2351                .then(|| {
 2352                    vec![
 2353                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2354                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2355                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2356                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2357                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2358                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2359                        cx.observe_window_activation(window, |editor, window, cx| {
 2360                            let active = window.is_window_active();
 2361                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2362                                if active {
 2363                                    blink_manager.enable(cx);
 2364                                } else {
 2365                                    blink_manager.disable(cx);
 2366                                }
 2367                            });
 2368                            if active {
 2369                                editor.show_mouse_cursor(cx);
 2370                            }
 2371                        }),
 2372                    ]
 2373                })
 2374                .unwrap_or_default(),
 2375            tasks_update_task: None,
 2376            pull_diagnostics_task: Task::ready(()),
 2377            pull_diagnostics_background_task: Task::ready(()),
 2378            colors: None,
 2379            refresh_colors_task: Task::ready(()),
 2380            inlay_hints: None,
 2381            next_color_inlay_id: 0,
 2382            post_scroll_update: Task::ready(()),
 2383            linked_edit_ranges: Default::default(),
 2384            in_project_search: false,
 2385            previous_search_ranges: None,
 2386            breadcrumb_header: None,
 2387            focused_block: None,
 2388            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2389            addons: HashMap::default(),
 2390            registered_buffers: HashMap::default(),
 2391            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2392            selection_mark_mode: false,
 2393            toggle_fold_multiple_buffers: Task::ready(()),
 2394            serialize_selections: Task::ready(()),
 2395            serialize_folds: Task::ready(()),
 2396            text_style_refinement: None,
 2397            load_diff_task: load_uncommitted_diff,
 2398            temporary_diff_override: false,
 2399            mouse_cursor_hidden: false,
 2400            minimap: None,
 2401            hide_mouse_mode: EditorSettings::get_global(cx)
 2402                .hide_mouse
 2403                .unwrap_or_default(),
 2404            change_list: ChangeList::new(),
 2405            mode,
 2406            selection_drag_state: SelectionDragState::None,
 2407            folding_newlines: Task::ready(()),
 2408            lookup_key: None,
 2409            select_next_is_case_sensitive: None,
 2410            applicable_language_settings: HashMap::default(),
 2411            accent_data: None,
 2412            fetched_tree_sitter_chunks: HashMap::default(),
 2413            number_deleted_lines: false,
 2414        };
 2415
 2416        if is_minimap {
 2417            return editor;
 2418        }
 2419
 2420        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2421        editor.accent_data = editor.fetch_accent_data(cx);
 2422
 2423        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2424            editor
 2425                ._subscriptions
 2426                .push(cx.observe(breakpoints, |_, _, cx| {
 2427                    cx.notify();
 2428                }));
 2429        }
 2430        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2431        editor._subscriptions.extend(project_subscriptions);
 2432
 2433        editor._subscriptions.push(cx.subscribe_in(
 2434            &cx.entity(),
 2435            window,
 2436            |editor, _, e: &EditorEvent, window, cx| match e {
 2437                EditorEvent::ScrollPositionChanged { local, .. } => {
 2438                    if *local {
 2439                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2440                        editor.inline_blame_popover.take();
 2441                        let new_anchor = editor.scroll_manager.anchor();
 2442                        let snapshot = editor.snapshot(window, cx);
 2443                        editor.update_restoration_data(cx, move |data| {
 2444                            data.scroll_position = (
 2445                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2446                                new_anchor.offset,
 2447                            );
 2448                        });
 2449
 2450                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2451                            cx.background_executor()
 2452                                .timer(Duration::from_millis(50))
 2453                                .await;
 2454                            editor
 2455                                .update_in(cx, |editor, window, cx| {
 2456                                    editor.register_visible_buffers(cx);
 2457                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2458                                    editor.refresh_inlay_hints(
 2459                                        InlayHintRefreshReason::NewLinesShown,
 2460                                        cx,
 2461                                    );
 2462                                    editor.colorize_brackets(false, cx);
 2463                                })
 2464                                .ok();
 2465                        });
 2466                    }
 2467                }
 2468                EditorEvent::Edited { .. } => {
 2469                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2470                        .map(|vim_mode| vim_mode.0)
 2471                        .unwrap_or(false);
 2472                    if !vim_mode {
 2473                        let display_map = editor.display_snapshot(cx);
 2474                        let selections = editor.selections.all_adjusted_display(&display_map);
 2475                        let pop_state = editor
 2476                            .change_list
 2477                            .last()
 2478                            .map(|previous| {
 2479                                previous.len() == selections.len()
 2480                                    && previous.iter().enumerate().all(|(ix, p)| {
 2481                                        p.to_display_point(&display_map).row()
 2482                                            == selections[ix].head().row()
 2483                                    })
 2484                            })
 2485                            .unwrap_or(false);
 2486                        let new_positions = selections
 2487                            .into_iter()
 2488                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2489                            .collect();
 2490                        editor
 2491                            .change_list
 2492                            .push_to_change_list(pop_state, new_positions);
 2493                    }
 2494                }
 2495                _ => (),
 2496            },
 2497        ));
 2498
 2499        if let Some(dap_store) = editor
 2500            .project
 2501            .as_ref()
 2502            .map(|project| project.read(cx).dap_store())
 2503        {
 2504            let weak_editor = cx.weak_entity();
 2505
 2506            editor
 2507                ._subscriptions
 2508                .push(
 2509                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2510                        let session_entity = cx.entity();
 2511                        weak_editor
 2512                            .update(cx, |editor, cx| {
 2513                                editor._subscriptions.push(
 2514                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2515                                );
 2516                            })
 2517                            .ok();
 2518                    }),
 2519                );
 2520
 2521            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2522                editor
 2523                    ._subscriptions
 2524                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2525            }
 2526        }
 2527
 2528        // skip adding the initial selection to selection history
 2529        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2530        editor.end_selection(window, cx);
 2531        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2532
 2533        editor.scroll_manager.show_scrollbars(window, cx);
 2534        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2535
 2536        if full_mode {
 2537            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2538            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2539
 2540            if editor.git_blame_inline_enabled {
 2541                editor.start_git_blame_inline(false, window, cx);
 2542            }
 2543
 2544            editor.go_to_active_debug_line(window, cx);
 2545
 2546            editor.minimap =
 2547                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2548            editor.colors = Some(LspColorData::new(cx));
 2549            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2550
 2551            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2552                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2553            }
 2554            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2555        }
 2556
 2557        editor
 2558    }
 2559
 2560    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2561        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2562    }
 2563
 2564    pub fn deploy_mouse_context_menu(
 2565        &mut self,
 2566        position: gpui::Point<Pixels>,
 2567        context_menu: Entity<ContextMenu>,
 2568        window: &mut Window,
 2569        cx: &mut Context<Self>,
 2570    ) {
 2571        self.mouse_context_menu = Some(MouseContextMenu::new(
 2572            self,
 2573            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2574            context_menu,
 2575            window,
 2576            cx,
 2577        ));
 2578    }
 2579
 2580    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2581        self.mouse_context_menu
 2582            .as_ref()
 2583            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2584    }
 2585
 2586    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2587        if self
 2588            .selections
 2589            .pending_anchor()
 2590            .is_some_and(|pending_selection| {
 2591                let snapshot = self.buffer().read(cx).snapshot(cx);
 2592                pending_selection.range().includes(range, &snapshot)
 2593            })
 2594        {
 2595            return true;
 2596        }
 2597
 2598        self.selections
 2599            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2600            .into_iter()
 2601            .any(|selection| {
 2602                // This is needed to cover a corner case, if we just check for an existing
 2603                // selection in the fold range, having a cursor at the start of the fold
 2604                // marks it as selected. Non-empty selections don't cause this.
 2605                let length = selection.end - selection.start;
 2606                length > 0
 2607            })
 2608    }
 2609
 2610    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2611        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2612    }
 2613
 2614    fn key_context_internal(
 2615        &self,
 2616        has_active_edit_prediction: bool,
 2617        window: &mut Window,
 2618        cx: &mut App,
 2619    ) -> KeyContext {
 2620        let mut key_context = KeyContext::new_with_defaults();
 2621        key_context.add("Editor");
 2622        let mode = match self.mode {
 2623            EditorMode::SingleLine => "single_line",
 2624            EditorMode::AutoHeight { .. } => "auto_height",
 2625            EditorMode::Minimap { .. } => "minimap",
 2626            EditorMode::Full { .. } => "full",
 2627        };
 2628
 2629        if EditorSettings::jupyter_enabled(cx) {
 2630            key_context.add("jupyter");
 2631        }
 2632
 2633        key_context.set("mode", mode);
 2634        if self.pending_rename.is_some() {
 2635            key_context.add("renaming");
 2636        }
 2637
 2638        if let Some(snippet_stack) = self.snippet_stack.last() {
 2639            key_context.add("in_snippet");
 2640
 2641            if snippet_stack.active_index > 0 {
 2642                key_context.add("has_previous_tabstop");
 2643            }
 2644
 2645            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2646                key_context.add("has_next_tabstop");
 2647            }
 2648        }
 2649
 2650        match self.context_menu.borrow().as_ref() {
 2651            Some(CodeContextMenu::Completions(menu)) => {
 2652                if menu.visible() {
 2653                    key_context.add("menu");
 2654                    key_context.add("showing_completions");
 2655                }
 2656            }
 2657            Some(CodeContextMenu::CodeActions(menu)) => {
 2658                if menu.visible() {
 2659                    key_context.add("menu");
 2660                    key_context.add("showing_code_actions")
 2661                }
 2662            }
 2663            None => {}
 2664        }
 2665
 2666        if self.signature_help_state.has_multiple_signatures() {
 2667            key_context.add("showing_signature_help");
 2668        }
 2669
 2670        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2671        if !self.focus_handle(cx).contains_focused(window, cx)
 2672            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2673        {
 2674            for addon in self.addons.values() {
 2675                addon.extend_key_context(&mut key_context, cx)
 2676            }
 2677        }
 2678
 2679        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2680            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2681                Some(
 2682                    file.full_path(cx)
 2683                        .extension()?
 2684                        .to_string_lossy()
 2685                        .to_lowercase(),
 2686                )
 2687            }) {
 2688                key_context.set("extension", extension);
 2689            }
 2690        } else {
 2691            key_context.add("multibuffer");
 2692        }
 2693
 2694        if has_active_edit_prediction {
 2695            if self.edit_prediction_in_conflict() {
 2696                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2697            } else {
 2698                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2699                key_context.add("copilot_suggestion");
 2700            }
 2701        }
 2702
 2703        if self.selection_mark_mode {
 2704            key_context.add("selection_mode");
 2705        }
 2706
 2707        let disjoint = self.selections.disjoint_anchors();
 2708        let snapshot = self.snapshot(window, cx);
 2709        let snapshot = snapshot.buffer_snapshot();
 2710        if self.mode == EditorMode::SingleLine
 2711            && let [selection] = disjoint
 2712            && selection.start == selection.end
 2713            && selection.end.to_offset(snapshot) == snapshot.len()
 2714        {
 2715            key_context.add("end_of_input");
 2716        }
 2717
 2718        if self.has_any_expanded_diff_hunks(cx) {
 2719            key_context.add("diffs_expanded");
 2720        }
 2721
 2722        key_context
 2723    }
 2724
 2725    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2726        self.last_bounds.as_ref()
 2727    }
 2728
 2729    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2730        if self.mouse_cursor_hidden {
 2731            self.mouse_cursor_hidden = false;
 2732            cx.notify();
 2733        }
 2734    }
 2735
 2736    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2737        let hide_mouse_cursor = match origin {
 2738            HideMouseCursorOrigin::TypingAction => {
 2739                matches!(
 2740                    self.hide_mouse_mode,
 2741                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2742                )
 2743            }
 2744            HideMouseCursorOrigin::MovementAction => {
 2745                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2746            }
 2747        };
 2748        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2749            self.mouse_cursor_hidden = hide_mouse_cursor;
 2750            cx.notify();
 2751        }
 2752    }
 2753
 2754    pub fn edit_prediction_in_conflict(&self) -> bool {
 2755        if !self.show_edit_predictions_in_menu() {
 2756            return false;
 2757        }
 2758
 2759        let showing_completions = self
 2760            .context_menu
 2761            .borrow()
 2762            .as_ref()
 2763            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2764
 2765        showing_completions
 2766            || self.edit_prediction_requires_modifier()
 2767            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2768            // bindings to insert tab characters.
 2769            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2770    }
 2771
 2772    pub fn accept_edit_prediction_keybind(
 2773        &self,
 2774        granularity: EditPredictionGranularity,
 2775        window: &mut Window,
 2776        cx: &mut App,
 2777    ) -> AcceptEditPredictionBinding {
 2778        let key_context = self.key_context_internal(true, window, cx);
 2779        let in_conflict = self.edit_prediction_in_conflict();
 2780
 2781        let bindings =
 2782            match granularity {
 2783                EditPredictionGranularity::Word => window
 2784                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2785                EditPredictionGranularity::Line => window
 2786                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2787                EditPredictionGranularity::Full => {
 2788                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2789                }
 2790            };
 2791
 2792        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2793            !in_conflict
 2794                || binding
 2795                    .keystrokes()
 2796                    .first()
 2797                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2798        }))
 2799    }
 2800
 2801    pub fn new_file(
 2802        workspace: &mut Workspace,
 2803        _: &workspace::NewFile,
 2804        window: &mut Window,
 2805        cx: &mut Context<Workspace>,
 2806    ) {
 2807        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2808            "Failed to create buffer",
 2809            window,
 2810            cx,
 2811            |e, _, _| match e.error_code() {
 2812                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2813                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2814                e.error_tag("required").unwrap_or("the latest version")
 2815            )),
 2816                _ => None,
 2817            },
 2818        );
 2819    }
 2820
 2821    pub fn new_in_workspace(
 2822        workspace: &mut Workspace,
 2823        window: &mut Window,
 2824        cx: &mut Context<Workspace>,
 2825    ) -> Task<Result<Entity<Editor>>> {
 2826        let project = workspace.project().clone();
 2827        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2828
 2829        cx.spawn_in(window, async move |workspace, cx| {
 2830            let buffer = create.await?;
 2831            workspace.update_in(cx, |workspace, window, cx| {
 2832                let editor =
 2833                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2834                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2835                editor
 2836            })
 2837        })
 2838    }
 2839
 2840    fn new_file_vertical(
 2841        workspace: &mut Workspace,
 2842        _: &workspace::NewFileSplitVertical,
 2843        window: &mut Window,
 2844        cx: &mut Context<Workspace>,
 2845    ) {
 2846        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2847    }
 2848
 2849    fn new_file_horizontal(
 2850        workspace: &mut Workspace,
 2851        _: &workspace::NewFileSplitHorizontal,
 2852        window: &mut Window,
 2853        cx: &mut Context<Workspace>,
 2854    ) {
 2855        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2856    }
 2857
 2858    fn new_file_split(
 2859        workspace: &mut Workspace,
 2860        action: &workspace::NewFileSplit,
 2861        window: &mut Window,
 2862        cx: &mut Context<Workspace>,
 2863    ) {
 2864        Self::new_file_in_direction(workspace, action.0, window, cx)
 2865    }
 2866
 2867    fn new_file_in_direction(
 2868        workspace: &mut Workspace,
 2869        direction: SplitDirection,
 2870        window: &mut Window,
 2871        cx: &mut Context<Workspace>,
 2872    ) {
 2873        let project = workspace.project().clone();
 2874        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2875
 2876        cx.spawn_in(window, async move |workspace, cx| {
 2877            let buffer = create.await?;
 2878            workspace.update_in(cx, move |workspace, window, cx| {
 2879                workspace.split_item(
 2880                    direction,
 2881                    Box::new(
 2882                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2883                    ),
 2884                    window,
 2885                    cx,
 2886                )
 2887            })?;
 2888            anyhow::Ok(())
 2889        })
 2890        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2891            match e.error_code() {
 2892                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2893                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2894                e.error_tag("required").unwrap_or("the latest version")
 2895            )),
 2896                _ => None,
 2897            }
 2898        });
 2899    }
 2900
 2901    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2902        self.leader_id
 2903    }
 2904
 2905    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2906        &self.buffer
 2907    }
 2908
 2909    pub fn project(&self) -> Option<&Entity<Project>> {
 2910        self.project.as_ref()
 2911    }
 2912
 2913    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2914        self.workspace.as_ref()?.0.upgrade()
 2915    }
 2916
 2917    /// Returns the workspace serialization ID if this editor should be serialized.
 2918    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2919        self.workspace
 2920            .as_ref()
 2921            .filter(|_| self.should_serialize_buffer())
 2922            .and_then(|workspace| workspace.1)
 2923    }
 2924
 2925    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2926        self.buffer().read(cx).title(cx)
 2927    }
 2928
 2929    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2930        let git_blame_gutter_max_author_length = self
 2931            .render_git_blame_gutter(cx)
 2932            .then(|| {
 2933                if let Some(blame) = self.blame.as_ref() {
 2934                    let max_author_length =
 2935                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2936                    Some(max_author_length)
 2937                } else {
 2938                    None
 2939                }
 2940            })
 2941            .flatten();
 2942
 2943        EditorSnapshot {
 2944            mode: self.mode.clone(),
 2945            show_gutter: self.show_gutter,
 2946            offset_content: self.offset_content,
 2947            show_line_numbers: self.show_line_numbers,
 2948            number_deleted_lines: self.number_deleted_lines,
 2949            show_git_diff_gutter: self.show_git_diff_gutter,
 2950            show_code_actions: self.show_code_actions,
 2951            show_runnables: self.show_runnables,
 2952            show_breakpoints: self.show_breakpoints,
 2953            git_blame_gutter_max_author_length,
 2954            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2955            placeholder_display_snapshot: self
 2956                .placeholder_display_map
 2957                .as_ref()
 2958                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2959            scroll_anchor: self.scroll_manager.anchor(),
 2960            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2961            is_focused: self.focus_handle.is_focused(window),
 2962            current_line_highlight: self
 2963                .current_line_highlight
 2964                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2965            gutter_hovered: self.gutter_hovered,
 2966        }
 2967    }
 2968
 2969    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2970        self.buffer.read(cx).language_at(point, cx)
 2971    }
 2972
 2973    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2974        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2975    }
 2976
 2977    pub fn active_excerpt(
 2978        &self,
 2979        cx: &App,
 2980    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2981        self.buffer
 2982            .read(cx)
 2983            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2984    }
 2985
 2986    pub fn mode(&self) -> &EditorMode {
 2987        &self.mode
 2988    }
 2989
 2990    pub fn set_mode(&mut self, mode: EditorMode) {
 2991        self.mode = mode;
 2992    }
 2993
 2994    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2995        self.collaboration_hub.as_deref()
 2996    }
 2997
 2998    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2999        self.collaboration_hub = Some(hub);
 3000    }
 3001
 3002    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3003        self.in_project_search = in_project_search;
 3004    }
 3005
 3006    pub fn set_custom_context_menu(
 3007        &mut self,
 3008        f: impl 'static
 3009        + Fn(
 3010            &mut Self,
 3011            DisplayPoint,
 3012            &mut Window,
 3013            &mut Context<Self>,
 3014        ) -> Option<Entity<ui::ContextMenu>>,
 3015    ) {
 3016        self.custom_context_menu = Some(Box::new(f))
 3017    }
 3018
 3019    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3020        self.completion_provider = provider;
 3021    }
 3022
 3023    #[cfg(any(test, feature = "test-support"))]
 3024    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3025        self.completion_provider.clone()
 3026    }
 3027
 3028    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3029        self.semantics_provider.clone()
 3030    }
 3031
 3032    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3033        self.semantics_provider = provider;
 3034    }
 3035
 3036    pub fn set_edit_prediction_provider<T>(
 3037        &mut self,
 3038        provider: Option<Entity<T>>,
 3039        window: &mut Window,
 3040        cx: &mut Context<Self>,
 3041    ) where
 3042        T: EditPredictionDelegate,
 3043    {
 3044        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3045            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3046                if this.focus_handle.is_focused(window) {
 3047                    this.update_visible_edit_prediction(window, cx);
 3048                }
 3049            }),
 3050            provider: Arc::new(provider),
 3051        });
 3052        self.update_edit_prediction_settings(cx);
 3053        self.refresh_edit_prediction(false, false, window, cx);
 3054    }
 3055
 3056    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3057        self.placeholder_display_map
 3058            .as_ref()
 3059            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3060    }
 3061
 3062    pub fn set_placeholder_text(
 3063        &mut self,
 3064        placeholder_text: &str,
 3065        window: &mut Window,
 3066        cx: &mut Context<Self>,
 3067    ) {
 3068        let multibuffer = cx
 3069            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3070
 3071        let style = window.text_style();
 3072
 3073        self.placeholder_display_map = Some(cx.new(|cx| {
 3074            DisplayMap::new(
 3075                multibuffer,
 3076                style.font(),
 3077                style.font_size.to_pixels(window.rem_size()),
 3078                None,
 3079                FILE_HEADER_HEIGHT,
 3080                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3081                Default::default(),
 3082                DiagnosticSeverity::Off,
 3083                cx,
 3084            )
 3085        }));
 3086        cx.notify();
 3087    }
 3088
 3089    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3090        self.cursor_shape = cursor_shape;
 3091
 3092        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3093        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3094
 3095        cx.notify();
 3096    }
 3097
 3098    pub fn cursor_shape(&self) -> CursorShape {
 3099        self.cursor_shape
 3100    }
 3101
 3102    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3103        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3104    }
 3105
 3106    pub fn set_current_line_highlight(
 3107        &mut self,
 3108        current_line_highlight: Option<CurrentLineHighlight>,
 3109    ) {
 3110        self.current_line_highlight = current_line_highlight;
 3111    }
 3112
 3113    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3114        self.collapse_matches = collapse_matches;
 3115    }
 3116
 3117    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3118        if self.collapse_matches {
 3119            return range.start..range.start;
 3120        }
 3121        range.clone()
 3122    }
 3123
 3124    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3125        self.display_map.read(cx).clip_at_line_ends
 3126    }
 3127
 3128    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3129        if self.display_map.read(cx).clip_at_line_ends != clip {
 3130            self.display_map
 3131                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3132        }
 3133    }
 3134
 3135    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3136        self.input_enabled = input_enabled;
 3137    }
 3138
 3139    pub fn set_edit_predictions_hidden_for_vim_mode(
 3140        &mut self,
 3141        hidden: bool,
 3142        window: &mut Window,
 3143        cx: &mut Context<Self>,
 3144    ) {
 3145        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3146            self.edit_predictions_hidden_for_vim_mode = hidden;
 3147            if hidden {
 3148                self.update_visible_edit_prediction(window, cx);
 3149            } else {
 3150                self.refresh_edit_prediction(true, false, window, cx);
 3151            }
 3152        }
 3153    }
 3154
 3155    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3156        self.menu_edit_predictions_policy = value;
 3157    }
 3158
 3159    pub fn set_autoindent(&mut self, autoindent: bool) {
 3160        if autoindent {
 3161            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3162        } else {
 3163            self.autoindent_mode = None;
 3164        }
 3165    }
 3166
 3167    pub fn capability(&self, cx: &App) -> Capability {
 3168        if self.read_only {
 3169            Capability::ReadOnly
 3170        } else {
 3171            self.buffer.read(cx).capability()
 3172        }
 3173    }
 3174
 3175    pub fn read_only(&self, cx: &App) -> bool {
 3176        self.read_only || self.buffer.read(cx).read_only()
 3177    }
 3178
 3179    pub fn set_read_only(&mut self, read_only: bool) {
 3180        self.read_only = read_only;
 3181    }
 3182
 3183    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3184        self.use_autoclose = autoclose;
 3185    }
 3186
 3187    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3188        self.use_auto_surround = auto_surround;
 3189    }
 3190
 3191    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3192        self.auto_replace_emoji_shortcode = auto_replace;
 3193    }
 3194
 3195    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3196        self.buffer_serialization = should_serialize.then(|| {
 3197            BufferSerialization::new(
 3198                ProjectSettings::get_global(cx)
 3199                    .session
 3200                    .restore_unsaved_buffers,
 3201            )
 3202        })
 3203    }
 3204
 3205    fn should_serialize_buffer(&self) -> bool {
 3206        self.buffer_serialization.is_some()
 3207    }
 3208
 3209    pub fn toggle_edit_predictions(
 3210        &mut self,
 3211        _: &ToggleEditPrediction,
 3212        window: &mut Window,
 3213        cx: &mut Context<Self>,
 3214    ) {
 3215        if self.show_edit_predictions_override.is_some() {
 3216            self.set_show_edit_predictions(None, window, cx);
 3217        } else {
 3218            let show_edit_predictions = !self.edit_predictions_enabled();
 3219            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3220        }
 3221    }
 3222
 3223    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3224        self.show_completions_on_input_override = show_completions_on_input;
 3225    }
 3226
 3227    pub fn set_show_edit_predictions(
 3228        &mut self,
 3229        show_edit_predictions: Option<bool>,
 3230        window: &mut Window,
 3231        cx: &mut Context<Self>,
 3232    ) {
 3233        self.show_edit_predictions_override = show_edit_predictions;
 3234        self.update_edit_prediction_settings(cx);
 3235
 3236        if let Some(false) = show_edit_predictions {
 3237            self.discard_edit_prediction(false, cx);
 3238        } else {
 3239            self.refresh_edit_prediction(false, true, window, cx);
 3240        }
 3241    }
 3242
 3243    fn edit_predictions_disabled_in_scope(
 3244        &self,
 3245        buffer: &Entity<Buffer>,
 3246        buffer_position: language::Anchor,
 3247        cx: &App,
 3248    ) -> bool {
 3249        let snapshot = buffer.read(cx).snapshot();
 3250        let settings = snapshot.settings_at(buffer_position, cx);
 3251
 3252        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3253            return false;
 3254        };
 3255
 3256        scope.override_name().is_some_and(|scope_name| {
 3257            settings
 3258                .edit_predictions_disabled_in
 3259                .iter()
 3260                .any(|s| s == scope_name)
 3261        })
 3262    }
 3263
 3264    pub fn set_use_modal_editing(&mut self, to: bool) {
 3265        self.use_modal_editing = to;
 3266    }
 3267
 3268    pub fn use_modal_editing(&self) -> bool {
 3269        self.use_modal_editing
 3270    }
 3271
 3272    fn selections_did_change(
 3273        &mut self,
 3274        local: bool,
 3275        old_cursor_position: &Anchor,
 3276        effects: SelectionEffects,
 3277        window: &mut Window,
 3278        cx: &mut Context<Self>,
 3279    ) {
 3280        window.invalidate_character_coordinates();
 3281
 3282        // Copy selections to primary selection buffer
 3283        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3284        if local {
 3285            let selections = self
 3286                .selections
 3287                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3288            let buffer_handle = self.buffer.read(cx).read(cx);
 3289
 3290            let mut text = String::new();
 3291            for (index, selection) in selections.iter().enumerate() {
 3292                let text_for_selection = buffer_handle
 3293                    .text_for_range(selection.start..selection.end)
 3294                    .collect::<String>();
 3295
 3296                text.push_str(&text_for_selection);
 3297                if index != selections.len() - 1 {
 3298                    text.push('\n');
 3299                }
 3300            }
 3301
 3302            if !text.is_empty() {
 3303                cx.write_to_primary(ClipboardItem::new_string(text));
 3304            }
 3305        }
 3306
 3307        let selection_anchors = self.selections.disjoint_anchors_arc();
 3308
 3309        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3310            self.buffer.update(cx, |buffer, cx| {
 3311                buffer.set_active_selections(
 3312                    &selection_anchors,
 3313                    self.selections.line_mode(),
 3314                    self.cursor_shape,
 3315                    cx,
 3316                )
 3317            });
 3318        }
 3319        let display_map = self
 3320            .display_map
 3321            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3322        let buffer = display_map.buffer_snapshot();
 3323        if self.selections.count() == 1 {
 3324            self.add_selections_state = None;
 3325        }
 3326        self.select_next_state = None;
 3327        self.select_prev_state = None;
 3328        self.select_syntax_node_history.try_clear();
 3329        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3330        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3331        self.take_rename(false, window, cx);
 3332
 3333        let newest_selection = self.selections.newest_anchor();
 3334        let new_cursor_position = newest_selection.head();
 3335        let selection_start = newest_selection.start;
 3336
 3337        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3338            self.push_to_nav_history(
 3339                *old_cursor_position,
 3340                Some(new_cursor_position.to_point(buffer)),
 3341                false,
 3342                effects.nav_history == Some(true),
 3343                cx,
 3344            );
 3345        }
 3346
 3347        if local {
 3348            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3349                self.register_buffer(buffer_id, cx);
 3350            }
 3351
 3352            let mut context_menu = self.context_menu.borrow_mut();
 3353            let completion_menu = match context_menu.as_ref() {
 3354                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3355                Some(CodeContextMenu::CodeActions(_)) => {
 3356                    *context_menu = None;
 3357                    None
 3358                }
 3359                None => None,
 3360            };
 3361            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3362            drop(context_menu);
 3363
 3364            if effects.completions
 3365                && let Some(completion_position) = completion_position
 3366            {
 3367                let start_offset = selection_start.to_offset(buffer);
 3368                let position_matches = start_offset == completion_position.to_offset(buffer);
 3369                let continue_showing = if let Some((snap, ..)) =
 3370                    buffer.point_to_buffer_offset(completion_position)
 3371                    && !snap.capability.editable()
 3372                {
 3373                    false
 3374                } else if position_matches {
 3375                    if self.snippet_stack.is_empty() {
 3376                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3377                            == Some(CharKind::Word)
 3378                    } else {
 3379                        // Snippet choices can be shown even when the cursor is in whitespace.
 3380                        // Dismissing the menu with actions like backspace is handled by
 3381                        // invalidation regions.
 3382                        true
 3383                    }
 3384                } else {
 3385                    false
 3386                };
 3387
 3388                if continue_showing {
 3389                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3390                } else {
 3391                    self.hide_context_menu(window, cx);
 3392                }
 3393            }
 3394
 3395            hide_hover(self, cx);
 3396
 3397            if old_cursor_position.to_display_point(&display_map).row()
 3398                != new_cursor_position.to_display_point(&display_map).row()
 3399            {
 3400                self.available_code_actions.take();
 3401            }
 3402            self.refresh_code_actions(window, cx);
 3403            self.refresh_document_highlights(cx);
 3404            refresh_linked_ranges(self, window, cx);
 3405
 3406            self.refresh_selected_text_highlights(false, window, cx);
 3407            self.refresh_matching_bracket_highlights(window, cx);
 3408            self.update_visible_edit_prediction(window, cx);
 3409            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3410            self.inline_blame_popover.take();
 3411            if self.git_blame_inline_enabled {
 3412                self.start_inline_blame_timer(window, cx);
 3413            }
 3414        }
 3415
 3416        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3417        cx.emit(EditorEvent::SelectionsChanged { local });
 3418
 3419        let selections = &self.selections.disjoint_anchors_arc();
 3420        if selections.len() == 1 {
 3421            cx.emit(SearchEvent::ActiveMatchChanged)
 3422        }
 3423        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3424            let inmemory_selections = selections
 3425                .iter()
 3426                .map(|s| {
 3427                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3428                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3429                })
 3430                .collect();
 3431            self.update_restoration_data(cx, |data| {
 3432                data.selections = inmemory_selections;
 3433            });
 3434
 3435            if WorkspaceSettings::get(None, cx).restore_on_startup
 3436                != RestoreOnStartupBehavior::EmptyTab
 3437                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3438            {
 3439                let snapshot = self.buffer().read(cx).snapshot(cx);
 3440                let selections = selections.clone();
 3441                let background_executor = cx.background_executor().clone();
 3442                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3443                self.serialize_selections = cx.background_spawn(async move {
 3444                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3445                    let db_selections = selections
 3446                        .iter()
 3447                        .map(|selection| {
 3448                            (
 3449                                selection.start.to_offset(&snapshot).0,
 3450                                selection.end.to_offset(&snapshot).0,
 3451                            )
 3452                        })
 3453                        .collect();
 3454
 3455                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3456                        .await
 3457                        .with_context(|| {
 3458                            format!(
 3459                                "persisting editor selections for editor {editor_id}, \
 3460                                workspace {workspace_id:?}"
 3461                            )
 3462                        })
 3463                        .log_err();
 3464                });
 3465            }
 3466        }
 3467
 3468        cx.notify();
 3469    }
 3470
 3471    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3472        use text::ToOffset as _;
 3473        use text::ToPoint as _;
 3474
 3475        if self.mode.is_minimap()
 3476            || WorkspaceSettings::get(None, cx).restore_on_startup
 3477                == RestoreOnStartupBehavior::EmptyTab
 3478        {
 3479            return;
 3480        }
 3481
 3482        if !self.buffer().read(cx).is_singleton() {
 3483            return;
 3484        }
 3485
 3486        let display_snapshot = self
 3487            .display_map
 3488            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3489        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3490            return;
 3491        };
 3492        let inmemory_folds = display_snapshot
 3493            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3494            .map(|fold| {
 3495                fold.range.start.text_anchor.to_point(&snapshot)
 3496                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3497            })
 3498            .collect();
 3499        self.update_restoration_data(cx, |data| {
 3500            data.folds = inmemory_folds;
 3501        });
 3502
 3503        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3504            return;
 3505        };
 3506        let background_executor = cx.background_executor().clone();
 3507        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3508        let db_folds = display_snapshot
 3509            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3510            .map(|fold| {
 3511                (
 3512                    fold.range.start.text_anchor.to_offset(&snapshot),
 3513                    fold.range.end.text_anchor.to_offset(&snapshot),
 3514                )
 3515            })
 3516            .collect();
 3517        self.serialize_folds = cx.background_spawn(async move {
 3518            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3519            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3520                .await
 3521                .with_context(|| {
 3522                    format!(
 3523                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3524                    )
 3525                })
 3526                .log_err();
 3527        });
 3528    }
 3529
 3530    pub fn sync_selections(
 3531        &mut self,
 3532        other: Entity<Editor>,
 3533        cx: &mut Context<Self>,
 3534    ) -> gpui::Subscription {
 3535        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3536        if !other_selections.is_empty() {
 3537            self.selections
 3538                .change_with(&self.display_snapshot(cx), |selections| {
 3539                    selections.select_anchors(other_selections);
 3540                });
 3541        }
 3542
 3543        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3544            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3545                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3546                if other_selections.is_empty() {
 3547                    return;
 3548                }
 3549                let snapshot = this.display_snapshot(cx);
 3550                this.selections.change_with(&snapshot, |selections| {
 3551                    selections.select_anchors(other_selections);
 3552                });
 3553            }
 3554        });
 3555
 3556        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3557            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3558                let these_selections = this.selections.disjoint_anchors().to_vec();
 3559                if these_selections.is_empty() {
 3560                    return;
 3561                }
 3562                other.update(cx, |other_editor, cx| {
 3563                    let snapshot = other_editor.display_snapshot(cx);
 3564                    other_editor
 3565                        .selections
 3566                        .change_with(&snapshot, |selections| {
 3567                            selections.select_anchors(these_selections);
 3568                        })
 3569                });
 3570            }
 3571        });
 3572
 3573        Subscription::join(other_subscription, this_subscription)
 3574    }
 3575
 3576    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3577        if self.buffer().read(cx).is_singleton() {
 3578            return;
 3579        }
 3580        let snapshot = self.buffer.read(cx).snapshot(cx);
 3581        let buffer_ids: HashSet<BufferId> = self
 3582            .selections
 3583            .disjoint_anchor_ranges()
 3584            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3585            .collect();
 3586        for buffer_id in buffer_ids {
 3587            self.unfold_buffer(buffer_id, cx);
 3588        }
 3589    }
 3590
 3591    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3592    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3593    /// effects of selection change occur at the end of the transaction.
 3594    pub fn change_selections<R>(
 3595        &mut self,
 3596        effects: SelectionEffects,
 3597        window: &mut Window,
 3598        cx: &mut Context<Self>,
 3599        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3600    ) -> R {
 3601        let snapshot = self.display_snapshot(cx);
 3602        if let Some(state) = &mut self.deferred_selection_effects_state {
 3603            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3604            state.effects.completions = effects.completions;
 3605            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3606            let (changed, result) = self.selections.change_with(&snapshot, change);
 3607            state.changed |= changed;
 3608            return result;
 3609        }
 3610        let mut state = DeferredSelectionEffectsState {
 3611            changed: false,
 3612            effects,
 3613            old_cursor_position: self.selections.newest_anchor().head(),
 3614            history_entry: SelectionHistoryEntry {
 3615                selections: self.selections.disjoint_anchors_arc(),
 3616                select_next_state: self.select_next_state.clone(),
 3617                select_prev_state: self.select_prev_state.clone(),
 3618                add_selections_state: self.add_selections_state.clone(),
 3619            },
 3620        };
 3621        let (changed, result) = self.selections.change_with(&snapshot, change);
 3622        state.changed = state.changed || changed;
 3623        if self.defer_selection_effects {
 3624            self.deferred_selection_effects_state = Some(state);
 3625        } else {
 3626            self.apply_selection_effects(state, window, cx);
 3627        }
 3628        result
 3629    }
 3630
 3631    /// Defers the effects of selection change, so that the effects of multiple calls to
 3632    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3633    /// to selection history and the state of popovers based on selection position aren't
 3634    /// erroneously updated.
 3635    pub fn with_selection_effects_deferred<R>(
 3636        &mut self,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3640    ) -> R {
 3641        let already_deferred = self.defer_selection_effects;
 3642        self.defer_selection_effects = true;
 3643        let result = update(self, window, cx);
 3644        if !already_deferred {
 3645            self.defer_selection_effects = false;
 3646            if let Some(state) = self.deferred_selection_effects_state.take() {
 3647                self.apply_selection_effects(state, window, cx);
 3648            }
 3649        }
 3650        result
 3651    }
 3652
 3653    fn apply_selection_effects(
 3654        &mut self,
 3655        state: DeferredSelectionEffectsState,
 3656        window: &mut Window,
 3657        cx: &mut Context<Self>,
 3658    ) {
 3659        if state.changed {
 3660            self.selection_history.push(state.history_entry);
 3661
 3662            if let Some(autoscroll) = state.effects.scroll {
 3663                self.request_autoscroll(autoscroll, cx);
 3664            }
 3665
 3666            let old_cursor_position = &state.old_cursor_position;
 3667
 3668            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3669
 3670            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3671                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3672            }
 3673        }
 3674    }
 3675
 3676    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3677    where
 3678        I: IntoIterator<Item = (Range<S>, T)>,
 3679        S: ToOffset,
 3680        T: Into<Arc<str>>,
 3681    {
 3682        if self.read_only(cx) {
 3683            return;
 3684        }
 3685
 3686        self.buffer
 3687            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3688    }
 3689
 3690    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3691    where
 3692        I: IntoIterator<Item = (Range<S>, T)>,
 3693        S: ToOffset,
 3694        T: Into<Arc<str>>,
 3695    {
 3696        if self.read_only(cx) {
 3697            return;
 3698        }
 3699
 3700        self.buffer.update(cx, |buffer, cx| {
 3701            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3702        });
 3703    }
 3704
 3705    pub fn edit_with_block_indent<I, S, T>(
 3706        &mut self,
 3707        edits: I,
 3708        original_indent_columns: Vec<Option<u32>>,
 3709        cx: &mut Context<Self>,
 3710    ) where
 3711        I: IntoIterator<Item = (Range<S>, T)>,
 3712        S: ToOffset,
 3713        T: Into<Arc<str>>,
 3714    {
 3715        if self.read_only(cx) {
 3716            return;
 3717        }
 3718
 3719        self.buffer.update(cx, |buffer, cx| {
 3720            buffer.edit(
 3721                edits,
 3722                Some(AutoindentMode::Block {
 3723                    original_indent_columns,
 3724                }),
 3725                cx,
 3726            )
 3727        });
 3728    }
 3729
 3730    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3731        self.hide_context_menu(window, cx);
 3732
 3733        match phase {
 3734            SelectPhase::Begin {
 3735                position,
 3736                add,
 3737                click_count,
 3738            } => self.begin_selection(position, add, click_count, window, cx),
 3739            SelectPhase::BeginColumnar {
 3740                position,
 3741                goal_column,
 3742                reset,
 3743                mode,
 3744            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3745            SelectPhase::Extend {
 3746                position,
 3747                click_count,
 3748            } => self.extend_selection(position, click_count, window, cx),
 3749            SelectPhase::Update {
 3750                position,
 3751                goal_column,
 3752                scroll_delta,
 3753            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3754            SelectPhase::End => self.end_selection(window, cx),
 3755        }
 3756    }
 3757
 3758    fn extend_selection(
 3759        &mut self,
 3760        position: DisplayPoint,
 3761        click_count: usize,
 3762        window: &mut Window,
 3763        cx: &mut Context<Self>,
 3764    ) {
 3765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3766        let tail = self
 3767            .selections
 3768            .newest::<MultiBufferOffset>(&display_map)
 3769            .tail();
 3770        let click_count = click_count.max(match self.selections.select_mode() {
 3771            SelectMode::Character => 1,
 3772            SelectMode::Word(_) => 2,
 3773            SelectMode::Line(_) => 3,
 3774            SelectMode::All => 4,
 3775        });
 3776        self.begin_selection(position, false, click_count, window, cx);
 3777
 3778        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3779
 3780        let current_selection = match self.selections.select_mode() {
 3781            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3782            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3783        };
 3784
 3785        let mut pending_selection = self
 3786            .selections
 3787            .pending_anchor()
 3788            .cloned()
 3789            .expect("extend_selection not called with pending selection");
 3790
 3791        if pending_selection
 3792            .start
 3793            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3794            == Ordering::Greater
 3795        {
 3796            pending_selection.start = current_selection.start;
 3797        }
 3798        if pending_selection
 3799            .end
 3800            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3801            == Ordering::Less
 3802        {
 3803            pending_selection.end = current_selection.end;
 3804            pending_selection.reversed = true;
 3805        }
 3806
 3807        let mut pending_mode = self.selections.pending_mode().unwrap();
 3808        match &mut pending_mode {
 3809            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3810            _ => {}
 3811        }
 3812
 3813        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3814            SelectionEffects::scroll(Autoscroll::fit())
 3815        } else {
 3816            SelectionEffects::no_scroll()
 3817        };
 3818
 3819        self.change_selections(effects, window, cx, |s| {
 3820            s.set_pending(pending_selection.clone(), pending_mode);
 3821            s.set_is_extending(true);
 3822        });
 3823    }
 3824
 3825    fn begin_selection(
 3826        &mut self,
 3827        position: DisplayPoint,
 3828        add: bool,
 3829        click_count: usize,
 3830        window: &mut Window,
 3831        cx: &mut Context<Self>,
 3832    ) {
 3833        if !self.focus_handle.is_focused(window) {
 3834            self.last_focused_descendant = None;
 3835            window.focus(&self.focus_handle, cx);
 3836        }
 3837
 3838        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3839        let buffer = display_map.buffer_snapshot();
 3840        let position = display_map.clip_point(position, Bias::Left);
 3841
 3842        let start;
 3843        let end;
 3844        let mode;
 3845        let mut auto_scroll;
 3846        match click_count {
 3847            1 => {
 3848                start = buffer.anchor_before(position.to_point(&display_map));
 3849                end = start;
 3850                mode = SelectMode::Character;
 3851                auto_scroll = true;
 3852            }
 3853            2 => {
 3854                let position = display_map
 3855                    .clip_point(position, Bias::Left)
 3856                    .to_offset(&display_map, Bias::Left);
 3857                let (range, _) = buffer.surrounding_word(position, None);
 3858                start = buffer.anchor_before(range.start);
 3859                end = buffer.anchor_before(range.end);
 3860                mode = SelectMode::Word(start..end);
 3861                auto_scroll = true;
 3862            }
 3863            3 => {
 3864                let position = display_map
 3865                    .clip_point(position, Bias::Left)
 3866                    .to_point(&display_map);
 3867                let line_start = display_map.prev_line_boundary(position).0;
 3868                let next_line_start = buffer.clip_point(
 3869                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3870                    Bias::Left,
 3871                );
 3872                start = buffer.anchor_before(line_start);
 3873                end = buffer.anchor_before(next_line_start);
 3874                mode = SelectMode::Line(start..end);
 3875                auto_scroll = true;
 3876            }
 3877            _ => {
 3878                start = buffer.anchor_before(MultiBufferOffset(0));
 3879                end = buffer.anchor_before(buffer.len());
 3880                mode = SelectMode::All;
 3881                auto_scroll = false;
 3882            }
 3883        }
 3884        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3885
 3886        let point_to_delete: Option<usize> = {
 3887            let selected_points: Vec<Selection<Point>> =
 3888                self.selections.disjoint_in_range(start..end, &display_map);
 3889
 3890            if !add || click_count > 1 {
 3891                None
 3892            } else if !selected_points.is_empty() {
 3893                Some(selected_points[0].id)
 3894            } else {
 3895                let clicked_point_already_selected =
 3896                    self.selections.disjoint_anchors().iter().find(|selection| {
 3897                        selection.start.to_point(buffer) == start.to_point(buffer)
 3898                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3899                    });
 3900
 3901                clicked_point_already_selected.map(|selection| selection.id)
 3902            }
 3903        };
 3904
 3905        let selections_count = self.selections.count();
 3906        let effects = if auto_scroll {
 3907            SelectionEffects::default()
 3908        } else {
 3909            SelectionEffects::no_scroll()
 3910        };
 3911
 3912        self.change_selections(effects, window, cx, |s| {
 3913            if let Some(point_to_delete) = point_to_delete {
 3914                s.delete(point_to_delete);
 3915
 3916                if selections_count == 1 {
 3917                    s.set_pending_anchor_range(start..end, mode);
 3918                }
 3919            } else {
 3920                if !add {
 3921                    s.clear_disjoint();
 3922                }
 3923
 3924                s.set_pending_anchor_range(start..end, mode);
 3925            }
 3926        });
 3927    }
 3928
 3929    fn begin_columnar_selection(
 3930        &mut self,
 3931        position: DisplayPoint,
 3932        goal_column: u32,
 3933        reset: bool,
 3934        mode: ColumnarMode,
 3935        window: &mut Window,
 3936        cx: &mut Context<Self>,
 3937    ) {
 3938        if !self.focus_handle.is_focused(window) {
 3939            self.last_focused_descendant = None;
 3940            window.focus(&self.focus_handle, cx);
 3941        }
 3942
 3943        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3944
 3945        if reset {
 3946            let pointer_position = display_map
 3947                .buffer_snapshot()
 3948                .anchor_before(position.to_point(&display_map));
 3949
 3950            self.change_selections(
 3951                SelectionEffects::scroll(Autoscroll::newest()),
 3952                window,
 3953                cx,
 3954                |s| {
 3955                    s.clear_disjoint();
 3956                    s.set_pending_anchor_range(
 3957                        pointer_position..pointer_position,
 3958                        SelectMode::Character,
 3959                    );
 3960                },
 3961            );
 3962        };
 3963
 3964        let tail = self.selections.newest::<Point>(&display_map).tail();
 3965        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3966        self.columnar_selection_state = match mode {
 3967            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3968                selection_tail: selection_anchor,
 3969                display_point: if reset {
 3970                    if position.column() != goal_column {
 3971                        Some(DisplayPoint::new(position.row(), goal_column))
 3972                    } else {
 3973                        None
 3974                    }
 3975                } else {
 3976                    None
 3977                },
 3978            }),
 3979            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3980                selection_tail: selection_anchor,
 3981            }),
 3982        };
 3983
 3984        if !reset {
 3985            self.select_columns(position, goal_column, &display_map, window, cx);
 3986        }
 3987    }
 3988
 3989    fn update_selection(
 3990        &mut self,
 3991        position: DisplayPoint,
 3992        goal_column: u32,
 3993        scroll_delta: gpui::Point<f32>,
 3994        window: &mut Window,
 3995        cx: &mut Context<Self>,
 3996    ) {
 3997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3998
 3999        if self.columnar_selection_state.is_some() {
 4000            self.select_columns(position, goal_column, &display_map, window, cx);
 4001        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4002            let buffer = display_map.buffer_snapshot();
 4003            let head;
 4004            let tail;
 4005            let mode = self.selections.pending_mode().unwrap();
 4006            match &mode {
 4007                SelectMode::Character => {
 4008                    head = position.to_point(&display_map);
 4009                    tail = pending.tail().to_point(buffer);
 4010                }
 4011                SelectMode::Word(original_range) => {
 4012                    let offset = display_map
 4013                        .clip_point(position, Bias::Left)
 4014                        .to_offset(&display_map, Bias::Left);
 4015                    let original_range = original_range.to_offset(buffer);
 4016
 4017                    let head_offset = if buffer.is_inside_word(offset, None)
 4018                        || original_range.contains(&offset)
 4019                    {
 4020                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4021                        if word_range.start < original_range.start {
 4022                            word_range.start
 4023                        } else {
 4024                            word_range.end
 4025                        }
 4026                    } else {
 4027                        offset
 4028                    };
 4029
 4030                    head = head_offset.to_point(buffer);
 4031                    if head_offset <= original_range.start {
 4032                        tail = original_range.end.to_point(buffer);
 4033                    } else {
 4034                        tail = original_range.start.to_point(buffer);
 4035                    }
 4036                }
 4037                SelectMode::Line(original_range) => {
 4038                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4039
 4040                    let position = display_map
 4041                        .clip_point(position, Bias::Left)
 4042                        .to_point(&display_map);
 4043                    let line_start = display_map.prev_line_boundary(position).0;
 4044                    let next_line_start = buffer.clip_point(
 4045                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4046                        Bias::Left,
 4047                    );
 4048
 4049                    if line_start < original_range.start {
 4050                        head = line_start
 4051                    } else {
 4052                        head = next_line_start
 4053                    }
 4054
 4055                    if head <= original_range.start {
 4056                        tail = original_range.end;
 4057                    } else {
 4058                        tail = original_range.start;
 4059                    }
 4060                }
 4061                SelectMode::All => {
 4062                    return;
 4063                }
 4064            };
 4065
 4066            if head < tail {
 4067                pending.start = buffer.anchor_before(head);
 4068                pending.end = buffer.anchor_before(tail);
 4069                pending.reversed = true;
 4070            } else {
 4071                pending.start = buffer.anchor_before(tail);
 4072                pending.end = buffer.anchor_before(head);
 4073                pending.reversed = false;
 4074            }
 4075
 4076            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4077                s.set_pending(pending.clone(), mode);
 4078            });
 4079        } else {
 4080            log::error!("update_selection dispatched with no pending selection");
 4081            return;
 4082        }
 4083
 4084        self.apply_scroll_delta(scroll_delta, window, cx);
 4085        cx.notify();
 4086    }
 4087
 4088    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4089        self.columnar_selection_state.take();
 4090        if let Some(pending_mode) = self.selections.pending_mode() {
 4091            let selections = self
 4092                .selections
 4093                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4094            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4095                s.select(selections);
 4096                s.clear_pending();
 4097                if s.is_extending() {
 4098                    s.set_is_extending(false);
 4099                } else {
 4100                    s.set_select_mode(pending_mode);
 4101                }
 4102            });
 4103        }
 4104    }
 4105
 4106    fn select_columns(
 4107        &mut self,
 4108        head: DisplayPoint,
 4109        goal_column: u32,
 4110        display_map: &DisplaySnapshot,
 4111        window: &mut Window,
 4112        cx: &mut Context<Self>,
 4113    ) {
 4114        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4115            return;
 4116        };
 4117
 4118        let tail = match columnar_state {
 4119            ColumnarSelectionState::FromMouse {
 4120                selection_tail,
 4121                display_point,
 4122            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4123            ColumnarSelectionState::FromSelection { selection_tail } => {
 4124                selection_tail.to_display_point(display_map)
 4125            }
 4126        };
 4127
 4128        let start_row = cmp::min(tail.row(), head.row());
 4129        let end_row = cmp::max(tail.row(), head.row());
 4130        let start_column = cmp::min(tail.column(), goal_column);
 4131        let end_column = cmp::max(tail.column(), goal_column);
 4132        let reversed = start_column < tail.column();
 4133
 4134        let selection_ranges = (start_row.0..=end_row.0)
 4135            .map(DisplayRow)
 4136            .filter_map(|row| {
 4137                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4138                    || start_column <= display_map.line_len(row))
 4139                    && !display_map.is_block_line(row)
 4140                {
 4141                    let start = display_map
 4142                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4143                        .to_point(display_map);
 4144                    let end = display_map
 4145                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4146                        .to_point(display_map);
 4147                    if reversed {
 4148                        Some(end..start)
 4149                    } else {
 4150                        Some(start..end)
 4151                    }
 4152                } else {
 4153                    None
 4154                }
 4155            })
 4156            .collect::<Vec<_>>();
 4157        if selection_ranges.is_empty() {
 4158            return;
 4159        }
 4160
 4161        let ranges = match columnar_state {
 4162            ColumnarSelectionState::FromMouse { .. } => {
 4163                let mut non_empty_ranges = selection_ranges
 4164                    .iter()
 4165                    .filter(|selection_range| selection_range.start != selection_range.end)
 4166                    .peekable();
 4167                if non_empty_ranges.peek().is_some() {
 4168                    non_empty_ranges.cloned().collect()
 4169                } else {
 4170                    selection_ranges
 4171                }
 4172            }
 4173            _ => selection_ranges,
 4174        };
 4175
 4176        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4177            s.select_ranges(ranges);
 4178        });
 4179        cx.notify();
 4180    }
 4181
 4182    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4183        self.selections
 4184            .all_adjusted(snapshot)
 4185            .iter()
 4186            .any(|selection| !selection.is_empty())
 4187    }
 4188
 4189    pub fn has_pending_nonempty_selection(&self) -> bool {
 4190        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4191            Some(Selection { start, end, .. }) => start != end,
 4192            None => false,
 4193        };
 4194
 4195        pending_nonempty_selection
 4196            || (self.columnar_selection_state.is_some()
 4197                && self.selections.disjoint_anchors().len() > 1)
 4198    }
 4199
 4200    pub fn has_pending_selection(&self) -> bool {
 4201        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4202    }
 4203
 4204    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4205        self.selection_mark_mode = false;
 4206        self.selection_drag_state = SelectionDragState::None;
 4207
 4208        if self.dismiss_menus_and_popups(true, window, cx) {
 4209            cx.notify();
 4210            return;
 4211        }
 4212        if self.clear_expanded_diff_hunks(cx) {
 4213            cx.notify();
 4214            return;
 4215        }
 4216        if self.show_git_blame_gutter {
 4217            self.show_git_blame_gutter = false;
 4218            cx.notify();
 4219            return;
 4220        }
 4221
 4222        if self.mode.is_full()
 4223            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4224        {
 4225            cx.notify();
 4226            return;
 4227        }
 4228
 4229        cx.propagate();
 4230    }
 4231
 4232    pub fn dismiss_menus_and_popups(
 4233        &mut self,
 4234        is_user_requested: bool,
 4235        window: &mut Window,
 4236        cx: &mut Context<Self>,
 4237    ) -> bool {
 4238        let mut dismissed = false;
 4239
 4240        dismissed |= self.take_rename(false, window, cx).is_some();
 4241        dismissed |= self.hide_blame_popover(true, cx);
 4242        dismissed |= hide_hover(self, cx);
 4243        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4244        dismissed |= self.hide_context_menu(window, cx).is_some();
 4245        dismissed |= self.mouse_context_menu.take().is_some();
 4246        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4247        dismissed |= self.snippet_stack.pop().is_some();
 4248
 4249        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4250            self.dismiss_diagnostics(cx);
 4251            dismissed = true;
 4252        }
 4253
 4254        dismissed
 4255    }
 4256
 4257    fn linked_editing_ranges_for(
 4258        &self,
 4259        selection: Range<text::Anchor>,
 4260        cx: &App,
 4261    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4262        if self.linked_edit_ranges.is_empty() {
 4263            return None;
 4264        }
 4265        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4266            selection.end.buffer_id.and_then(|end_buffer_id| {
 4267                if selection.start.buffer_id != Some(end_buffer_id) {
 4268                    return None;
 4269                }
 4270                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4271                let snapshot = buffer.read(cx).snapshot();
 4272                self.linked_edit_ranges
 4273                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4274                    .map(|ranges| (ranges, snapshot, buffer))
 4275            })?;
 4276        use text::ToOffset as TO;
 4277        // find offset from the start of current range to current cursor position
 4278        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4279
 4280        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4281        let start_difference = start_offset - start_byte_offset;
 4282        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4283        let end_difference = end_offset - start_byte_offset;
 4284        // Current range has associated linked ranges.
 4285        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4286        for range in linked_ranges.iter() {
 4287            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4288            let end_offset = start_offset + end_difference;
 4289            let start_offset = start_offset + start_difference;
 4290            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4291                continue;
 4292            }
 4293            if self.selections.disjoint_anchor_ranges().any(|s| {
 4294                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4295                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4296                {
 4297                    return false;
 4298                }
 4299                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4300                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4301            }) {
 4302                continue;
 4303            }
 4304            let start = buffer_snapshot.anchor_after(start_offset);
 4305            let end = buffer_snapshot.anchor_after(end_offset);
 4306            linked_edits
 4307                .entry(buffer.clone())
 4308                .or_default()
 4309                .push(start..end);
 4310        }
 4311        Some(linked_edits)
 4312    }
 4313
 4314    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4315        let text: Arc<str> = text.into();
 4316
 4317        if self.read_only(cx) {
 4318            return;
 4319        }
 4320
 4321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4322
 4323        self.unfold_buffers_with_selections(cx);
 4324
 4325        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4326        let mut bracket_inserted = false;
 4327        let mut edits = Vec::new();
 4328        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4329        let mut new_selections = Vec::with_capacity(selections.len());
 4330        let mut new_autoclose_regions = Vec::new();
 4331        let snapshot = self.buffer.read(cx).read(cx);
 4332        let mut clear_linked_edit_ranges = false;
 4333        let mut all_selections_read_only = true;
 4334        let mut has_adjacent_edits = false;
 4335        let mut in_adjacent_group = false;
 4336
 4337        let mut regions = self
 4338            .selections_with_autoclose_regions(selections, &snapshot)
 4339            .peekable();
 4340
 4341        while let Some((selection, autoclose_region)) = regions.next() {
 4342            if snapshot
 4343                .point_to_buffer_point(selection.head())
 4344                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4345            {
 4346                continue;
 4347            }
 4348            if snapshot
 4349                .point_to_buffer_point(selection.tail())
 4350                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4351            {
 4352                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4353                continue;
 4354            }
 4355            all_selections_read_only = false;
 4356
 4357            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4358                // Determine if the inserted text matches the opening or closing
 4359                // bracket of any of this language's bracket pairs.
 4360                let mut bracket_pair = None;
 4361                let mut is_bracket_pair_start = false;
 4362                let mut is_bracket_pair_end = false;
 4363                if !text.is_empty() {
 4364                    let mut bracket_pair_matching_end = None;
 4365                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4366                    //  and they are removing the character that triggered IME popup.
 4367                    for (pair, enabled) in scope.brackets() {
 4368                        if !pair.close && !pair.surround {
 4369                            continue;
 4370                        }
 4371
 4372                        if enabled && pair.start.ends_with(text.as_ref()) {
 4373                            let prefix_len = pair.start.len() - text.len();
 4374                            let preceding_text_matches_prefix = prefix_len == 0
 4375                                || (selection.start.column >= (prefix_len as u32)
 4376                                    && snapshot.contains_str_at(
 4377                                        Point::new(
 4378                                            selection.start.row,
 4379                                            selection.start.column - (prefix_len as u32),
 4380                                        ),
 4381                                        &pair.start[..prefix_len],
 4382                                    ));
 4383                            if preceding_text_matches_prefix {
 4384                                bracket_pair = Some(pair.clone());
 4385                                is_bracket_pair_start = true;
 4386                                break;
 4387                            }
 4388                        }
 4389                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4390                        {
 4391                            // take first bracket pair matching end, but don't break in case a later bracket
 4392                            // pair matches start
 4393                            bracket_pair_matching_end = Some(pair.clone());
 4394                        }
 4395                    }
 4396                    if let Some(end) = bracket_pair_matching_end
 4397                        && bracket_pair.is_none()
 4398                    {
 4399                        bracket_pair = Some(end);
 4400                        is_bracket_pair_end = true;
 4401                    }
 4402                }
 4403
 4404                if let Some(bracket_pair) = bracket_pair {
 4405                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4406                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4407                    let auto_surround =
 4408                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4409                    if selection.is_empty() {
 4410                        if is_bracket_pair_start {
 4411                            // If the inserted text is a suffix of an opening bracket and the
 4412                            // selection is preceded by the rest of the opening bracket, then
 4413                            // insert the closing bracket.
 4414                            let following_text_allows_autoclose = snapshot
 4415                                .chars_at(selection.start)
 4416                                .next()
 4417                                .is_none_or(|c| scope.should_autoclose_before(c));
 4418
 4419                            let preceding_text_allows_autoclose = selection.start.column == 0
 4420                                || snapshot
 4421                                    .reversed_chars_at(selection.start)
 4422                                    .next()
 4423                                    .is_none_or(|c| {
 4424                                        bracket_pair.start != bracket_pair.end
 4425                                            || !snapshot
 4426                                                .char_classifier_at(selection.start)
 4427                                                .is_word(c)
 4428                                    });
 4429
 4430                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4431                                && bracket_pair.start.len() == 1
 4432                            {
 4433                                let target = bracket_pair.start.chars().next().unwrap();
 4434                                let mut byte_offset = 0u32;
 4435                                let current_line_count = snapshot
 4436                                    .reversed_chars_at(selection.start)
 4437                                    .take_while(|&c| c != '\n')
 4438                                    .filter(|c| {
 4439                                        byte_offset += c.len_utf8() as u32;
 4440                                        if *c != target {
 4441                                            return false;
 4442                                        }
 4443
 4444                                        let point = Point::new(
 4445                                            selection.start.row,
 4446                                            selection.start.column.saturating_sub(byte_offset),
 4447                                        );
 4448
 4449                                        let is_enabled = snapshot
 4450                                            .language_scope_at(point)
 4451                                            .and_then(|scope| {
 4452                                                scope
 4453                                                    .brackets()
 4454                                                    .find(|(pair, _)| {
 4455                                                        pair.start == bracket_pair.start
 4456                                                    })
 4457                                                    .map(|(_, enabled)| enabled)
 4458                                            })
 4459                                            .unwrap_or(true);
 4460
 4461                                        let is_delimiter = snapshot
 4462                                            .language_scope_at(Point::new(
 4463                                                point.row,
 4464                                                point.column + 1,
 4465                                            ))
 4466                                            .and_then(|scope| {
 4467                                                scope
 4468                                                    .brackets()
 4469                                                    .find(|(pair, _)| {
 4470                                                        pair.start == bracket_pair.start
 4471                                                    })
 4472                                                    .map(|(_, enabled)| !enabled)
 4473                                            })
 4474                                            .unwrap_or(false);
 4475
 4476                                        is_enabled && !is_delimiter
 4477                                    })
 4478                                    .count();
 4479                                current_line_count % 2 == 1
 4480                            } else {
 4481                                false
 4482                            };
 4483
 4484                            if autoclose
 4485                                && bracket_pair.close
 4486                                && following_text_allows_autoclose
 4487                                && preceding_text_allows_autoclose
 4488                                && !is_closing_quote
 4489                            {
 4490                                let anchor = snapshot.anchor_before(selection.end);
 4491                                new_selections.push((selection.map(|_| anchor), text.len()));
 4492                                new_autoclose_regions.push((
 4493                                    anchor,
 4494                                    text.len(),
 4495                                    selection.id,
 4496                                    bracket_pair.clone(),
 4497                                ));
 4498                                edits.push((
 4499                                    selection.range(),
 4500                                    format!("{}{}", text, bracket_pair.end).into(),
 4501                                ));
 4502                                bracket_inserted = true;
 4503                                continue;
 4504                            }
 4505                        }
 4506
 4507                        if let Some(region) = autoclose_region {
 4508                            // If the selection is followed by an auto-inserted closing bracket,
 4509                            // then don't insert that closing bracket again; just move the selection
 4510                            // past the closing bracket.
 4511                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4512                                && text.as_ref() == region.pair.end.as_str()
 4513                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4514                            if should_skip {
 4515                                let anchor = snapshot.anchor_after(selection.end);
 4516                                new_selections
 4517                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4518                                continue;
 4519                            }
 4520                        }
 4521
 4522                        let always_treat_brackets_as_autoclosed = snapshot
 4523                            .language_settings_at(selection.start, cx)
 4524                            .always_treat_brackets_as_autoclosed;
 4525                        if always_treat_brackets_as_autoclosed
 4526                            && is_bracket_pair_end
 4527                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4528                        {
 4529                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4530                            // and the inserted text is a closing bracket and the selection is followed
 4531                            // by the closing bracket then move the selection past the closing bracket.
 4532                            let anchor = snapshot.anchor_after(selection.end);
 4533                            new_selections.push((selection.map(|_| anchor), text.len()));
 4534                            continue;
 4535                        }
 4536                    }
 4537                    // If an opening bracket is 1 character long and is typed while
 4538                    // text is selected, then surround that text with the bracket pair.
 4539                    else if auto_surround
 4540                        && bracket_pair.surround
 4541                        && is_bracket_pair_start
 4542                        && bracket_pair.start.chars().count() == 1
 4543                    {
 4544                        edits.push((selection.start..selection.start, text.clone()));
 4545                        edits.push((
 4546                            selection.end..selection.end,
 4547                            bracket_pair.end.as_str().into(),
 4548                        ));
 4549                        bracket_inserted = true;
 4550                        new_selections.push((
 4551                            Selection {
 4552                                id: selection.id,
 4553                                start: snapshot.anchor_after(selection.start),
 4554                                end: snapshot.anchor_before(selection.end),
 4555                                reversed: selection.reversed,
 4556                                goal: selection.goal,
 4557                            },
 4558                            0,
 4559                        ));
 4560                        continue;
 4561                    }
 4562                }
 4563            }
 4564
 4565            if self.auto_replace_emoji_shortcode
 4566                && selection.is_empty()
 4567                && text.as_ref().ends_with(':')
 4568                && let Some(possible_emoji_short_code) =
 4569                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4570                && !possible_emoji_short_code.is_empty()
 4571                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4572            {
 4573                let emoji_shortcode_start = Point::new(
 4574                    selection.start.row,
 4575                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4576                );
 4577
 4578                // Remove shortcode from buffer
 4579                edits.push((
 4580                    emoji_shortcode_start..selection.start,
 4581                    "".to_string().into(),
 4582                ));
 4583                new_selections.push((
 4584                    Selection {
 4585                        id: selection.id,
 4586                        start: snapshot.anchor_after(emoji_shortcode_start),
 4587                        end: snapshot.anchor_before(selection.start),
 4588                        reversed: selection.reversed,
 4589                        goal: selection.goal,
 4590                    },
 4591                    0,
 4592                ));
 4593
 4594                // Insert emoji
 4595                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4596                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4597                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4598
 4599                continue;
 4600            }
 4601
 4602            let next_is_adjacent = regions
 4603                .peek()
 4604                .is_some_and(|(next, _)| selection.end == next.start);
 4605
 4606            // If not handling any auto-close operation, then just replace the selected
 4607            // text with the given input and move the selection to the end of the
 4608            // newly inserted text.
 4609            let anchor = if in_adjacent_group || next_is_adjacent {
 4610                // After edits the right bias would shift those anchor to the next visible fragment
 4611                // but we want to resolve to the previous one
 4612                snapshot.anchor_before(selection.end)
 4613            } else {
 4614                snapshot.anchor_after(selection.end)
 4615            };
 4616
 4617            if !self.linked_edit_ranges.is_empty() {
 4618                let start_anchor = snapshot.anchor_before(selection.start);
 4619
 4620                let is_word_char = text.chars().next().is_none_or(|char| {
 4621                    let classifier = snapshot
 4622                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4623                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4624                    classifier.is_word(char)
 4625                });
 4626
 4627                if is_word_char {
 4628                    if let Some(ranges) = self
 4629                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4630                    {
 4631                        for (buffer, edits) in ranges {
 4632                            linked_edits
 4633                                .entry(buffer.clone())
 4634                                .or_default()
 4635                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4636                        }
 4637                    }
 4638                } else {
 4639                    clear_linked_edit_ranges = true;
 4640                }
 4641            }
 4642
 4643            new_selections.push((selection.map(|_| anchor), 0));
 4644            edits.push((selection.start..selection.end, text.clone()));
 4645
 4646            has_adjacent_edits |= next_is_adjacent;
 4647            in_adjacent_group = next_is_adjacent;
 4648        }
 4649
 4650        if all_selections_read_only {
 4651            return;
 4652        }
 4653
 4654        drop(regions);
 4655        drop(snapshot);
 4656
 4657        self.transact(window, cx, |this, window, cx| {
 4658            if clear_linked_edit_ranges {
 4659                this.linked_edit_ranges.clear();
 4660            }
 4661            let initial_buffer_versions =
 4662                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4663
 4664            this.buffer.update(cx, |buffer, cx| {
 4665                if has_adjacent_edits {
 4666                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4667                } else {
 4668                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4669                }
 4670            });
 4671            for (buffer, edits) in linked_edits {
 4672                buffer.update(cx, |buffer, cx| {
 4673                    let snapshot = buffer.snapshot();
 4674                    let edits = edits
 4675                        .into_iter()
 4676                        .map(|(range, text)| {
 4677                            use text::ToPoint as TP;
 4678                            let end_point = TP::to_point(&range.end, &snapshot);
 4679                            let start_point = TP::to_point(&range.start, &snapshot);
 4680                            (start_point..end_point, text)
 4681                        })
 4682                        .sorted_by_key(|(range, _)| range.start);
 4683                    buffer.edit(edits, None, cx);
 4684                })
 4685            }
 4686            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4687            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4688            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4689            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4690                new_anchor_selections,
 4691                &map,
 4692            )
 4693            .zip(new_selection_deltas)
 4694            .map(|(selection, delta)| Selection {
 4695                id: selection.id,
 4696                start: selection.start + delta,
 4697                end: selection.end + delta,
 4698                reversed: selection.reversed,
 4699                goal: SelectionGoal::None,
 4700            })
 4701            .collect::<Vec<_>>();
 4702
 4703            let mut i = 0;
 4704            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4705                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4706                let start = map.buffer_snapshot().anchor_before(position);
 4707                let end = map.buffer_snapshot().anchor_after(position);
 4708                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4709                    match existing_state
 4710                        .range
 4711                        .start
 4712                        .cmp(&start, map.buffer_snapshot())
 4713                    {
 4714                        Ordering::Less => i += 1,
 4715                        Ordering::Greater => break,
 4716                        Ordering::Equal => {
 4717                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4718                                Ordering::Less => i += 1,
 4719                                Ordering::Equal => break,
 4720                                Ordering::Greater => break,
 4721                            }
 4722                        }
 4723                    }
 4724                }
 4725                this.autoclose_regions.insert(
 4726                    i,
 4727                    AutocloseRegion {
 4728                        selection_id,
 4729                        range: start..end,
 4730                        pair,
 4731                    },
 4732                );
 4733            }
 4734
 4735            let had_active_edit_prediction = this.has_active_edit_prediction();
 4736            this.change_selections(
 4737                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4738                window,
 4739                cx,
 4740                |s| s.select(new_selections),
 4741            );
 4742
 4743            if !bracket_inserted
 4744                && let Some(on_type_format_task) =
 4745                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4746            {
 4747                on_type_format_task.detach_and_log_err(cx);
 4748            }
 4749
 4750            let editor_settings = EditorSettings::get_global(cx);
 4751            if bracket_inserted
 4752                && (editor_settings.auto_signature_help
 4753                    || editor_settings.show_signature_help_after_edits)
 4754            {
 4755                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4756            }
 4757
 4758            let trigger_in_words =
 4759                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4760            if this.hard_wrap.is_some() {
 4761                let latest: Range<Point> = this.selections.newest(&map).range();
 4762                if latest.is_empty()
 4763                    && this
 4764                        .buffer()
 4765                        .read(cx)
 4766                        .snapshot(cx)
 4767                        .line_len(MultiBufferRow(latest.start.row))
 4768                        == latest.start.column
 4769                {
 4770                    this.rewrap_impl(
 4771                        RewrapOptions {
 4772                            override_language_settings: true,
 4773                            preserve_existing_whitespace: true,
 4774                        },
 4775                        cx,
 4776                    )
 4777                }
 4778            }
 4779            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4780            refresh_linked_ranges(this, window, cx);
 4781            this.refresh_edit_prediction(true, false, window, cx);
 4782            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4783        });
 4784    }
 4785
 4786    fn find_possible_emoji_shortcode_at_position(
 4787        snapshot: &MultiBufferSnapshot,
 4788        position: Point,
 4789    ) -> Option<String> {
 4790        let mut chars = Vec::new();
 4791        let mut found_colon = false;
 4792        for char in snapshot.reversed_chars_at(position).take(100) {
 4793            // Found a possible emoji shortcode in the middle of the buffer
 4794            if found_colon {
 4795                if char.is_whitespace() {
 4796                    chars.reverse();
 4797                    return Some(chars.iter().collect());
 4798                }
 4799                // If the previous character is not a whitespace, we are in the middle of a word
 4800                // and we only want to complete the shortcode if the word is made up of other emojis
 4801                let mut containing_word = String::new();
 4802                for ch in snapshot
 4803                    .reversed_chars_at(position)
 4804                    .skip(chars.len() + 1)
 4805                    .take(100)
 4806                {
 4807                    if ch.is_whitespace() {
 4808                        break;
 4809                    }
 4810                    containing_word.push(ch);
 4811                }
 4812                let containing_word = containing_word.chars().rev().collect::<String>();
 4813                if util::word_consists_of_emojis(containing_word.as_str()) {
 4814                    chars.reverse();
 4815                    return Some(chars.iter().collect());
 4816                }
 4817            }
 4818
 4819            if char.is_whitespace() || !char.is_ascii() {
 4820                return None;
 4821            }
 4822            if char == ':' {
 4823                found_colon = true;
 4824            } else {
 4825                chars.push(char);
 4826            }
 4827        }
 4828        // Found a possible emoji shortcode at the beginning of the buffer
 4829        chars.reverse();
 4830        Some(chars.iter().collect())
 4831    }
 4832
 4833    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4835        self.transact(window, cx, |this, window, cx| {
 4836            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4837                let selections = this
 4838                    .selections
 4839                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4840                let multi_buffer = this.buffer.read(cx);
 4841                let buffer = multi_buffer.snapshot(cx);
 4842                selections
 4843                    .iter()
 4844                    .map(|selection| {
 4845                        let start_point = selection.start.to_point(&buffer);
 4846                        let mut existing_indent =
 4847                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4848                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4849                        let start = selection.start;
 4850                        let end = selection.end;
 4851                        let selection_is_empty = start == end;
 4852                        let language_scope = buffer.language_scope_at(start);
 4853                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4854                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4855                                &buffer,
 4856                                start..end,
 4857                                language,
 4858                            )
 4859                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4860                                    &buffer,
 4861                                    start..end,
 4862                                );
 4863
 4864                            let mut newline_config = NewlineConfig::Newline {
 4865                                additional_indent: IndentSize::spaces(0),
 4866                                extra_line_additional_indent: if needs_extra_newline {
 4867                                    Some(IndentSize::spaces(0))
 4868                                } else {
 4869                                    None
 4870                                },
 4871                                prevent_auto_indent: false,
 4872                            };
 4873
 4874                            let comment_delimiter = maybe!({
 4875                                if !selection_is_empty {
 4876                                    return None;
 4877                                }
 4878
 4879                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4880                                    return None;
 4881                                }
 4882
 4883                                return comment_delimiter_for_newline(
 4884                                    &start_point,
 4885                                    &buffer,
 4886                                    language,
 4887                                );
 4888                            });
 4889
 4890                            let doc_delimiter = maybe!({
 4891                                if !selection_is_empty {
 4892                                    return None;
 4893                                }
 4894
 4895                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4896                                    return None;
 4897                                }
 4898
 4899                                return documentation_delimiter_for_newline(
 4900                                    &start_point,
 4901                                    &buffer,
 4902                                    language,
 4903                                    &mut newline_config,
 4904                                );
 4905                            });
 4906
 4907                            let list_delimiter = maybe!({
 4908                                if !selection_is_empty {
 4909                                    return None;
 4910                                }
 4911
 4912                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4913                                    return None;
 4914                                }
 4915
 4916                                return list_delimiter_for_newline(
 4917                                    &start_point,
 4918                                    &buffer,
 4919                                    language,
 4920                                    &mut newline_config,
 4921                                );
 4922                            });
 4923
 4924                            (
 4925                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4926                                newline_config,
 4927                            )
 4928                        } else {
 4929                            (
 4930                                None,
 4931                                NewlineConfig::Newline {
 4932                                    additional_indent: IndentSize::spaces(0),
 4933                                    extra_line_additional_indent: None,
 4934                                    prevent_auto_indent: false,
 4935                                },
 4936                            )
 4937                        };
 4938
 4939                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4940                            NewlineConfig::ClearCurrentLine => {
 4941                                let row_start =
 4942                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4943                                (row_start, String::new(), false)
 4944                            }
 4945                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4946                                let row_start =
 4947                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4948                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4949                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4950                                let reduced_indent =
 4951                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4952                                let mut new_text = String::new();
 4953                                new_text.extend(reduced_indent.chars());
 4954                                new_text.push_str(continuation);
 4955                                (row_start, new_text, true)
 4956                            }
 4957                            NewlineConfig::Newline {
 4958                                additional_indent,
 4959                                extra_line_additional_indent,
 4960                                prevent_auto_indent,
 4961                            } => {
 4962                                let capacity_for_delimiter =
 4963                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4964                                let extra_line_len = extra_line_additional_indent
 4965                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4966                                    .unwrap_or(0);
 4967                                let mut new_text = String::with_capacity(
 4968                                    1 + capacity_for_delimiter
 4969                                        + existing_indent.len as usize
 4970                                        + additional_indent.len as usize
 4971                                        + extra_line_len,
 4972                                );
 4973                                new_text.push('\n');
 4974                                new_text.extend(existing_indent.chars());
 4975                                new_text.extend(additional_indent.chars());
 4976                                if let Some(delimiter) = &delimiter {
 4977                                    new_text.push_str(delimiter);
 4978                                }
 4979                                if let Some(extra_indent) = extra_line_additional_indent {
 4980                                    new_text.push('\n');
 4981                                    new_text.extend(existing_indent.chars());
 4982                                    new_text.extend(extra_indent.chars());
 4983                                }
 4984                                (start, new_text, *prevent_auto_indent)
 4985                            }
 4986                        };
 4987
 4988                        let anchor = buffer.anchor_after(end);
 4989                        let new_selection = selection.map(|_| anchor);
 4990                        (
 4991                            ((edit_start..end, new_text), prevent_auto_indent),
 4992                            (newline_config.has_extra_line(), new_selection),
 4993                        )
 4994                    })
 4995                    .unzip()
 4996            };
 4997
 4998            let mut auto_indent_edits = Vec::new();
 4999            let mut edits = Vec::new();
 5000            for (edit, prevent_auto_indent) in edits_with_flags {
 5001                if prevent_auto_indent {
 5002                    edits.push(edit);
 5003                } else {
 5004                    auto_indent_edits.push(edit);
 5005                }
 5006            }
 5007            if !edits.is_empty() {
 5008                this.edit(edits, cx);
 5009            }
 5010            if !auto_indent_edits.is_empty() {
 5011                this.edit_with_autoindent(auto_indent_edits, cx);
 5012            }
 5013
 5014            let buffer = this.buffer.read(cx).snapshot(cx);
 5015            let new_selections = selection_info
 5016                .into_iter()
 5017                .map(|(extra_newline_inserted, new_selection)| {
 5018                    let mut cursor = new_selection.end.to_point(&buffer);
 5019                    if extra_newline_inserted {
 5020                        cursor.row -= 1;
 5021                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5022                    }
 5023                    new_selection.map(|_| cursor)
 5024                })
 5025                .collect();
 5026
 5027            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5028            this.refresh_edit_prediction(true, false, window, cx);
 5029            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5030                task.detach_and_log_err(cx);
 5031            }
 5032        });
 5033    }
 5034
 5035    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5037
 5038        let buffer = self.buffer.read(cx);
 5039        let snapshot = buffer.snapshot(cx);
 5040
 5041        let mut edits = Vec::new();
 5042        let mut rows = Vec::new();
 5043
 5044        for (rows_inserted, selection) in self
 5045            .selections
 5046            .all_adjusted(&self.display_snapshot(cx))
 5047            .into_iter()
 5048            .enumerate()
 5049        {
 5050            let cursor = selection.head();
 5051            let row = cursor.row;
 5052
 5053            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5054
 5055            let newline = "\n".to_string();
 5056            edits.push((start_of_line..start_of_line, newline));
 5057
 5058            rows.push(row + rows_inserted as u32);
 5059        }
 5060
 5061        self.transact(window, cx, |editor, window, cx| {
 5062            editor.edit(edits, cx);
 5063
 5064            editor.change_selections(Default::default(), window, cx, |s| {
 5065                let mut index = 0;
 5066                s.move_cursors_with(|map, _, _| {
 5067                    let row = rows[index];
 5068                    index += 1;
 5069
 5070                    let point = Point::new(row, 0);
 5071                    let boundary = map.next_line_boundary(point).1;
 5072                    let clipped = map.clip_point(boundary, Bias::Left);
 5073
 5074                    (clipped, SelectionGoal::None)
 5075                });
 5076            });
 5077
 5078            let mut indent_edits = Vec::new();
 5079            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5080            for row in rows {
 5081                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5082                for (row, indent) in indents {
 5083                    if indent.len == 0 {
 5084                        continue;
 5085                    }
 5086
 5087                    let text = match indent.kind {
 5088                        IndentKind::Space => " ".repeat(indent.len as usize),
 5089                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5090                    };
 5091                    let point = Point::new(row.0, 0);
 5092                    indent_edits.push((point..point, text));
 5093                }
 5094            }
 5095            editor.edit(indent_edits, cx);
 5096            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5097                format.detach_and_log_err(cx);
 5098            }
 5099        });
 5100    }
 5101
 5102    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5104
 5105        let buffer = self.buffer.read(cx);
 5106        let snapshot = buffer.snapshot(cx);
 5107
 5108        let mut edits = Vec::new();
 5109        let mut rows = Vec::new();
 5110        let mut rows_inserted = 0;
 5111
 5112        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5113            let cursor = selection.head();
 5114            let row = cursor.row;
 5115
 5116            let point = Point::new(row + 1, 0);
 5117            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5118
 5119            let newline = "\n".to_string();
 5120            edits.push((start_of_line..start_of_line, newline));
 5121
 5122            rows_inserted += 1;
 5123            rows.push(row + rows_inserted);
 5124        }
 5125
 5126        self.transact(window, cx, |editor, window, cx| {
 5127            editor.edit(edits, cx);
 5128
 5129            editor.change_selections(Default::default(), window, cx, |s| {
 5130                let mut index = 0;
 5131                s.move_cursors_with(|map, _, _| {
 5132                    let row = rows[index];
 5133                    index += 1;
 5134
 5135                    let point = Point::new(row, 0);
 5136                    let boundary = map.next_line_boundary(point).1;
 5137                    let clipped = map.clip_point(boundary, Bias::Left);
 5138
 5139                    (clipped, SelectionGoal::None)
 5140                });
 5141            });
 5142
 5143            let mut indent_edits = Vec::new();
 5144            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5145            for row in rows {
 5146                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5147                for (row, indent) in indents {
 5148                    if indent.len == 0 {
 5149                        continue;
 5150                    }
 5151
 5152                    let text = match indent.kind {
 5153                        IndentKind::Space => " ".repeat(indent.len as usize),
 5154                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5155                    };
 5156                    let point = Point::new(row.0, 0);
 5157                    indent_edits.push((point..point, text));
 5158                }
 5159            }
 5160            editor.edit(indent_edits, cx);
 5161            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5162                format.detach_and_log_err(cx);
 5163            }
 5164        });
 5165    }
 5166
 5167    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5168        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5169            original_indent_columns: Vec::new(),
 5170        });
 5171        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5172    }
 5173
 5174    fn insert_with_autoindent_mode(
 5175        &mut self,
 5176        text: &str,
 5177        autoindent_mode: Option<AutoindentMode>,
 5178        window: &mut Window,
 5179        cx: &mut Context<Self>,
 5180    ) {
 5181        if self.read_only(cx) {
 5182            return;
 5183        }
 5184
 5185        let text: Arc<str> = text.into();
 5186        self.transact(window, cx, |this, window, cx| {
 5187            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5188            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5189                let anchors = {
 5190                    let snapshot = buffer.read(cx);
 5191                    old_selections
 5192                        .iter()
 5193                        .map(|s| {
 5194                            let anchor = snapshot.anchor_after(s.head());
 5195                            s.map(|_| anchor)
 5196                        })
 5197                        .collect::<Vec<_>>()
 5198                };
 5199                buffer.edit(
 5200                    old_selections
 5201                        .iter()
 5202                        .map(|s| (s.start..s.end, text.clone())),
 5203                    autoindent_mode,
 5204                    cx,
 5205                );
 5206                anchors
 5207            });
 5208
 5209            this.change_selections(Default::default(), window, cx, |s| {
 5210                s.select_anchors(selection_anchors);
 5211            });
 5212
 5213            cx.notify();
 5214        });
 5215    }
 5216
 5217    fn trigger_completion_on_input(
 5218        &mut self,
 5219        text: &str,
 5220        trigger_in_words: bool,
 5221        window: &mut Window,
 5222        cx: &mut Context<Self>,
 5223    ) {
 5224        let completions_source = self
 5225            .context_menu
 5226            .borrow()
 5227            .as_ref()
 5228            .and_then(|menu| match menu {
 5229                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5230                CodeContextMenu::CodeActions(_) => None,
 5231            });
 5232
 5233        match completions_source {
 5234            Some(CompletionsMenuSource::Words { .. }) => {
 5235                self.open_or_update_completions_menu(
 5236                    Some(CompletionsMenuSource::Words {
 5237                        ignore_threshold: false,
 5238                    }),
 5239                    None,
 5240                    trigger_in_words,
 5241                    window,
 5242                    cx,
 5243                );
 5244            }
 5245            _ => self.open_or_update_completions_menu(
 5246                None,
 5247                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5248                true,
 5249                window,
 5250                cx,
 5251            ),
 5252        }
 5253    }
 5254
 5255    /// If any empty selections is touching the start of its innermost containing autoclose
 5256    /// region, expand it to select the brackets.
 5257    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5258        let selections = self
 5259            .selections
 5260            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5261        let buffer = self.buffer.read(cx).read(cx);
 5262        let new_selections = self
 5263            .selections_with_autoclose_regions(selections, &buffer)
 5264            .map(|(mut selection, region)| {
 5265                if !selection.is_empty() {
 5266                    return selection;
 5267                }
 5268
 5269                if let Some(region) = region {
 5270                    let mut range = region.range.to_offset(&buffer);
 5271                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5272                        range.start -= region.pair.start.len();
 5273                        if buffer.contains_str_at(range.start, &region.pair.start)
 5274                            && buffer.contains_str_at(range.end, &region.pair.end)
 5275                        {
 5276                            range.end += region.pair.end.len();
 5277                            selection.start = range.start;
 5278                            selection.end = range.end;
 5279
 5280                            return selection;
 5281                        }
 5282                    }
 5283                }
 5284
 5285                let always_treat_brackets_as_autoclosed = buffer
 5286                    .language_settings_at(selection.start, cx)
 5287                    .always_treat_brackets_as_autoclosed;
 5288
 5289                if !always_treat_brackets_as_autoclosed {
 5290                    return selection;
 5291                }
 5292
 5293                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5294                    for (pair, enabled) in scope.brackets() {
 5295                        if !enabled || !pair.close {
 5296                            continue;
 5297                        }
 5298
 5299                        if buffer.contains_str_at(selection.start, &pair.end) {
 5300                            let pair_start_len = pair.start.len();
 5301                            if buffer.contains_str_at(
 5302                                selection.start.saturating_sub_usize(pair_start_len),
 5303                                &pair.start,
 5304                            ) {
 5305                                selection.start -= pair_start_len;
 5306                                selection.end += pair.end.len();
 5307
 5308                                return selection;
 5309                            }
 5310                        }
 5311                    }
 5312                }
 5313
 5314                selection
 5315            })
 5316            .collect();
 5317
 5318        drop(buffer);
 5319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5320            selections.select(new_selections)
 5321        });
 5322    }
 5323
 5324    /// Iterate the given selections, and for each one, find the smallest surrounding
 5325    /// autoclose region. This uses the ordering of the selections and the autoclose
 5326    /// regions to avoid repeated comparisons.
 5327    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5328        &'a self,
 5329        selections: impl IntoIterator<Item = Selection<D>>,
 5330        buffer: &'a MultiBufferSnapshot,
 5331    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5332        let mut i = 0;
 5333        let mut regions = self.autoclose_regions.as_slice();
 5334        selections.into_iter().map(move |selection| {
 5335            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5336
 5337            let mut enclosing = None;
 5338            while let Some(pair_state) = regions.get(i) {
 5339                if pair_state.range.end.to_offset(buffer) < range.start {
 5340                    regions = &regions[i + 1..];
 5341                    i = 0;
 5342                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5343                    break;
 5344                } else {
 5345                    if pair_state.selection_id == selection.id {
 5346                        enclosing = Some(pair_state);
 5347                    }
 5348                    i += 1;
 5349                }
 5350            }
 5351
 5352            (selection, enclosing)
 5353        })
 5354    }
 5355
 5356    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5357    fn invalidate_autoclose_regions(
 5358        &mut self,
 5359        mut selections: &[Selection<Anchor>],
 5360        buffer: &MultiBufferSnapshot,
 5361    ) {
 5362        self.autoclose_regions.retain(|state| {
 5363            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5364                return false;
 5365            }
 5366
 5367            let mut i = 0;
 5368            while let Some(selection) = selections.get(i) {
 5369                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5370                    selections = &selections[1..];
 5371                    continue;
 5372                }
 5373                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5374                    break;
 5375                }
 5376                if selection.id == state.selection_id {
 5377                    return true;
 5378                } else {
 5379                    i += 1;
 5380                }
 5381            }
 5382            false
 5383        });
 5384    }
 5385
 5386    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5387        let offset = position.to_offset(buffer);
 5388        let (word_range, kind) =
 5389            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5390        if offset > word_range.start && kind == Some(CharKind::Word) {
 5391            Some(
 5392                buffer
 5393                    .text_for_range(word_range.start..offset)
 5394                    .collect::<String>(),
 5395            )
 5396        } else {
 5397            None
 5398        }
 5399    }
 5400
 5401    pub fn visible_excerpts(
 5402        &self,
 5403        lsp_related_only: bool,
 5404        cx: &mut Context<Editor>,
 5405    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5406        let project = self.project().cloned();
 5407        let multi_buffer = self.buffer().read(cx);
 5408        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5409        let multi_buffer_visible_start = self
 5410            .scroll_manager
 5411            .anchor()
 5412            .anchor
 5413            .to_point(&multi_buffer_snapshot);
 5414        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5415            multi_buffer_visible_start
 5416                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5417            Bias::Left,
 5418        );
 5419        multi_buffer_snapshot
 5420            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5421            .into_iter()
 5422            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5423            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5424                if !lsp_related_only {
 5425                    return Some((
 5426                        excerpt_id,
 5427                        (
 5428                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5429                            buffer.version().clone(),
 5430                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5431                        ),
 5432                    ));
 5433                }
 5434
 5435                let project = project.as_ref()?.read(cx);
 5436                let buffer_file = project::File::from_dyn(buffer.file())?;
 5437                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5438                let worktree_entry = buffer_worktree
 5439                    .read(cx)
 5440                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5441                if worktree_entry.is_ignored {
 5442                    None
 5443                } else {
 5444                    Some((
 5445                        excerpt_id,
 5446                        (
 5447                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5448                            buffer.version().clone(),
 5449                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5450                        ),
 5451                    ))
 5452                }
 5453            })
 5454            .collect()
 5455    }
 5456
 5457    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5458        TextLayoutDetails {
 5459            text_system: window.text_system().clone(),
 5460            editor_style: self.style.clone().unwrap(),
 5461            rem_size: window.rem_size(),
 5462            scroll_anchor: self.scroll_manager.anchor(),
 5463            visible_rows: self.visible_line_count(),
 5464            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5465        }
 5466    }
 5467
 5468    fn trigger_on_type_formatting(
 5469        &self,
 5470        input: String,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) -> Option<Task<Result<()>>> {
 5474        if input.chars().count() != 1 {
 5475            return None;
 5476        }
 5477
 5478        let project = self.project()?;
 5479        let position = self.selections.newest_anchor().head();
 5480        let (buffer, buffer_position) = self
 5481            .buffer
 5482            .read(cx)
 5483            .text_anchor_for_position(position, cx)?;
 5484
 5485        let settings = language_settings::language_settings(
 5486            buffer
 5487                .read(cx)
 5488                .language_at(buffer_position)
 5489                .map(|l| l.name()),
 5490            buffer.read(cx).file(),
 5491            cx,
 5492        );
 5493        if !settings.use_on_type_format {
 5494            return None;
 5495        }
 5496
 5497        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5498        // hence we do LSP request & edit on host side only — add formats to host's history.
 5499        let push_to_lsp_host_history = true;
 5500        // If this is not the host, append its history with new edits.
 5501        let push_to_client_history = project.read(cx).is_via_collab();
 5502
 5503        let on_type_formatting = project.update(cx, |project, cx| {
 5504            project.on_type_format(
 5505                buffer.clone(),
 5506                buffer_position,
 5507                input,
 5508                push_to_lsp_host_history,
 5509                cx,
 5510            )
 5511        });
 5512        Some(cx.spawn_in(window, async move |editor, cx| {
 5513            if let Some(transaction) = on_type_formatting.await? {
 5514                if push_to_client_history {
 5515                    buffer
 5516                        .update(cx, |buffer, _| {
 5517                            buffer.push_transaction(transaction, Instant::now());
 5518                            buffer.finalize_last_transaction();
 5519                        })
 5520                        .ok();
 5521                }
 5522                editor.update(cx, |editor, cx| {
 5523                    editor.refresh_document_highlights(cx);
 5524                })?;
 5525            }
 5526            Ok(())
 5527        }))
 5528    }
 5529
 5530    pub fn show_word_completions(
 5531        &mut self,
 5532        _: &ShowWordCompletions,
 5533        window: &mut Window,
 5534        cx: &mut Context<Self>,
 5535    ) {
 5536        self.open_or_update_completions_menu(
 5537            Some(CompletionsMenuSource::Words {
 5538                ignore_threshold: true,
 5539            }),
 5540            None,
 5541            false,
 5542            window,
 5543            cx,
 5544        );
 5545    }
 5546
 5547    pub fn show_completions(
 5548        &mut self,
 5549        _: &ShowCompletions,
 5550        window: &mut Window,
 5551        cx: &mut Context<Self>,
 5552    ) {
 5553        self.open_or_update_completions_menu(None, None, false, window, cx);
 5554    }
 5555
 5556    fn open_or_update_completions_menu(
 5557        &mut self,
 5558        requested_source: Option<CompletionsMenuSource>,
 5559        trigger: Option<String>,
 5560        trigger_in_words: bool,
 5561        window: &mut Window,
 5562        cx: &mut Context<Self>,
 5563    ) {
 5564        if self.pending_rename.is_some() {
 5565            return;
 5566        }
 5567
 5568        let completions_source = self
 5569            .context_menu
 5570            .borrow()
 5571            .as_ref()
 5572            .and_then(|menu| match menu {
 5573                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5574                CodeContextMenu::CodeActions(_) => None,
 5575            });
 5576
 5577        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5578
 5579        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5580        // inserted and selected. To handle that case, the start of the selection is used so that
 5581        // the menu starts with all choices.
 5582        let position = self
 5583            .selections
 5584            .newest_anchor()
 5585            .start
 5586            .bias_right(&multibuffer_snapshot);
 5587        if position.diff_base_anchor.is_some() {
 5588            return;
 5589        }
 5590        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5591        let Some(buffer) = buffer_position
 5592            .text_anchor
 5593            .buffer_id
 5594            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5595        else {
 5596            return;
 5597        };
 5598        let buffer_snapshot = buffer.read(cx).snapshot();
 5599
 5600        let menu_is_open = matches!(
 5601            self.context_menu.borrow().as_ref(),
 5602            Some(CodeContextMenu::Completions(_))
 5603        );
 5604
 5605        let language = buffer_snapshot
 5606            .language_at(buffer_position.text_anchor)
 5607            .map(|language| language.name());
 5608
 5609        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5610        let completion_settings = language_settings.completions.clone();
 5611
 5612        let show_completions_on_input = self
 5613            .show_completions_on_input_override
 5614            .unwrap_or(language_settings.show_completions_on_input);
 5615        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5616            return;
 5617        }
 5618
 5619        let query: Option<Arc<String>> =
 5620            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5621                .map(|query| query.into());
 5622
 5623        drop(multibuffer_snapshot);
 5624
 5625        // Hide the current completions menu when query is empty. Without this, cached
 5626        // completions from before the trigger char may be reused (#32774).
 5627        if query.is_none() && menu_is_open {
 5628            self.hide_context_menu(window, cx);
 5629        }
 5630
 5631        let mut ignore_word_threshold = false;
 5632        let provider = match requested_source {
 5633            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5634            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5635                ignore_word_threshold = ignore_threshold;
 5636                None
 5637            }
 5638            Some(CompletionsMenuSource::SnippetChoices)
 5639            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5640                log::error!("bug: SnippetChoices requested_source is not handled");
 5641                None
 5642            }
 5643        };
 5644
 5645        let sort_completions = provider
 5646            .as_ref()
 5647            .is_some_and(|provider| provider.sort_completions());
 5648
 5649        let filter_completions = provider
 5650            .as_ref()
 5651            .is_none_or(|provider| provider.filter_completions());
 5652
 5653        let was_snippets_only = matches!(
 5654            completions_source,
 5655            Some(CompletionsMenuSource::SnippetsOnly)
 5656        );
 5657
 5658        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5659            if filter_completions {
 5660                menu.filter(
 5661                    query.clone().unwrap_or_default(),
 5662                    buffer_position.text_anchor,
 5663                    &buffer,
 5664                    provider.clone(),
 5665                    window,
 5666                    cx,
 5667                );
 5668            }
 5669            // When `is_incomplete` is false, no need to re-query completions when the current query
 5670            // is a suffix of the initial query.
 5671            let was_complete = !menu.is_incomplete;
 5672            if was_complete && !was_snippets_only {
 5673                // If the new query is a suffix of the old query (typing more characters) and
 5674                // the previous result was complete, the existing completions can be filtered.
 5675                //
 5676                // Note that snippet completions are always complete.
 5677                let query_matches = match (&menu.initial_query, &query) {
 5678                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5679                    (None, _) => true,
 5680                    _ => false,
 5681                };
 5682                if query_matches {
 5683                    let position_matches = if menu.initial_position == position {
 5684                        true
 5685                    } else {
 5686                        let snapshot = self.buffer.read(cx).read(cx);
 5687                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5688                    };
 5689                    if position_matches {
 5690                        return;
 5691                    }
 5692                }
 5693            }
 5694        };
 5695
 5696        let Anchor {
 5697            excerpt_id: buffer_excerpt_id,
 5698            text_anchor: buffer_position,
 5699            ..
 5700        } = buffer_position;
 5701
 5702        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5703            buffer_snapshot.surrounding_word(buffer_position, None)
 5704        {
 5705            let word_to_exclude = buffer_snapshot
 5706                .text_for_range(word_range.clone())
 5707                .collect::<String>();
 5708            (
 5709                buffer_snapshot.anchor_before(word_range.start)
 5710                    ..buffer_snapshot.anchor_after(buffer_position),
 5711                Some(word_to_exclude),
 5712            )
 5713        } else {
 5714            (buffer_position..buffer_position, None)
 5715        };
 5716
 5717        let show_completion_documentation = buffer_snapshot
 5718            .settings_at(buffer_position, cx)
 5719            .show_completion_documentation;
 5720
 5721        // The document can be large, so stay in reasonable bounds when searching for words,
 5722        // otherwise completion pop-up might be slow to appear.
 5723        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5724        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5725        let min_word_search = buffer_snapshot.clip_point(
 5726            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5727            Bias::Left,
 5728        );
 5729        let max_word_search = buffer_snapshot.clip_point(
 5730            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5731            Bias::Right,
 5732        );
 5733        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5734            ..buffer_snapshot.point_to_offset(max_word_search);
 5735
 5736        let skip_digits = query
 5737            .as_ref()
 5738            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5739
 5740        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5741            trigger.as_ref().is_none_or(|trigger| {
 5742                provider.is_completion_trigger(
 5743                    &buffer,
 5744                    position.text_anchor,
 5745                    trigger,
 5746                    trigger_in_words,
 5747                    cx,
 5748                )
 5749            })
 5750        });
 5751
 5752        let provider_responses = if let Some(provider) = &provider
 5753            && load_provider_completions
 5754        {
 5755            let trigger_character =
 5756                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5757            let completion_context = CompletionContext {
 5758                trigger_kind: match &trigger_character {
 5759                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5760                    None => CompletionTriggerKind::INVOKED,
 5761                },
 5762                trigger_character,
 5763            };
 5764
 5765            provider.completions(
 5766                buffer_excerpt_id,
 5767                &buffer,
 5768                buffer_position,
 5769                completion_context,
 5770                window,
 5771                cx,
 5772            )
 5773        } else {
 5774            Task::ready(Ok(Vec::new()))
 5775        };
 5776
 5777        let load_word_completions = if !self.word_completions_enabled {
 5778            false
 5779        } else if requested_source
 5780            == Some(CompletionsMenuSource::Words {
 5781                ignore_threshold: true,
 5782            })
 5783        {
 5784            true
 5785        } else {
 5786            load_provider_completions
 5787                && completion_settings.words != WordsCompletionMode::Disabled
 5788                && (ignore_word_threshold || {
 5789                    let words_min_length = completion_settings.words_min_length;
 5790                    // check whether word has at least `words_min_length` characters
 5791                    let query_chars = query.iter().flat_map(|q| q.chars());
 5792                    query_chars.take(words_min_length).count() == words_min_length
 5793                })
 5794        };
 5795
 5796        let mut words = if load_word_completions {
 5797            cx.background_spawn({
 5798                let buffer_snapshot = buffer_snapshot.clone();
 5799                async move {
 5800                    buffer_snapshot.words_in_range(WordsQuery {
 5801                        fuzzy_contents: None,
 5802                        range: word_search_range,
 5803                        skip_digits,
 5804                    })
 5805                }
 5806            })
 5807        } else {
 5808            Task::ready(BTreeMap::default())
 5809        };
 5810
 5811        let snippets = if let Some(provider) = &provider
 5812            && provider.show_snippets()
 5813            && let Some(project) = self.project()
 5814        {
 5815            let char_classifier = buffer_snapshot
 5816                .char_classifier_at(buffer_position)
 5817                .scope_context(Some(CharScopeContext::Completion));
 5818            project.update(cx, |project, cx| {
 5819                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5820            })
 5821        } else {
 5822            Task::ready(Ok(CompletionResponse {
 5823                completions: Vec::new(),
 5824                display_options: Default::default(),
 5825                is_incomplete: false,
 5826            }))
 5827        };
 5828
 5829        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5830
 5831        let id = post_inc(&mut self.next_completion_id);
 5832        let task = cx.spawn_in(window, async move |editor, cx| {
 5833            let Ok(()) = editor.update(cx, |this, _| {
 5834                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5835            }) else {
 5836                return;
 5837            };
 5838
 5839            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5840            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5841            let mut completions = Vec::new();
 5842            let mut is_incomplete = false;
 5843            let mut display_options: Option<CompletionDisplayOptions> = None;
 5844            if let Some(provider_responses) = provider_responses.await.log_err()
 5845                && !provider_responses.is_empty()
 5846            {
 5847                for response in provider_responses {
 5848                    completions.extend(response.completions);
 5849                    is_incomplete = is_incomplete || response.is_incomplete;
 5850                    match display_options.as_mut() {
 5851                        None => {
 5852                            display_options = Some(response.display_options);
 5853                        }
 5854                        Some(options) => options.merge(&response.display_options),
 5855                    }
 5856                }
 5857                if completion_settings.words == WordsCompletionMode::Fallback {
 5858                    words = Task::ready(BTreeMap::default());
 5859                }
 5860            }
 5861            let display_options = display_options.unwrap_or_default();
 5862
 5863            let mut words = words.await;
 5864            if let Some(word_to_exclude) = &word_to_exclude {
 5865                words.remove(word_to_exclude);
 5866            }
 5867            for lsp_completion in &completions {
 5868                words.remove(&lsp_completion.new_text);
 5869            }
 5870            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5871                replace_range: word_replace_range.clone(),
 5872                new_text: word.clone(),
 5873                label: CodeLabel::plain(word, None),
 5874                match_start: None,
 5875                snippet_deduplication_key: None,
 5876                icon_path: None,
 5877                documentation: None,
 5878                source: CompletionSource::BufferWord {
 5879                    word_range,
 5880                    resolved: false,
 5881                },
 5882                insert_text_mode: Some(InsertTextMode::AS_IS),
 5883                confirm: None,
 5884            }));
 5885
 5886            completions.extend(
 5887                snippets
 5888                    .await
 5889                    .into_iter()
 5890                    .flat_map(|response| response.completions),
 5891            );
 5892
 5893            let menu = if completions.is_empty() {
 5894                None
 5895            } else {
 5896                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5897                    let languages = editor
 5898                        .workspace
 5899                        .as_ref()
 5900                        .and_then(|(workspace, _)| workspace.upgrade())
 5901                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5902                    let menu = CompletionsMenu::new(
 5903                        id,
 5904                        requested_source.unwrap_or(if load_provider_completions {
 5905                            CompletionsMenuSource::Normal
 5906                        } else {
 5907                            CompletionsMenuSource::SnippetsOnly
 5908                        }),
 5909                        sort_completions,
 5910                        show_completion_documentation,
 5911                        position,
 5912                        query.clone(),
 5913                        is_incomplete,
 5914                        buffer.clone(),
 5915                        completions.into(),
 5916                        editor
 5917                            .context_menu()
 5918                            .borrow_mut()
 5919                            .as_ref()
 5920                            .map(|menu| menu.primary_scroll_handle()),
 5921                        display_options,
 5922                        snippet_sort_order,
 5923                        languages,
 5924                        language,
 5925                        cx,
 5926                    );
 5927
 5928                    let query = if filter_completions { query } else { None };
 5929                    let matches_task = menu.do_async_filtering(
 5930                        query.unwrap_or_default(),
 5931                        buffer_position,
 5932                        &buffer,
 5933                        cx,
 5934                    );
 5935                    (menu, matches_task)
 5936                }) else {
 5937                    return;
 5938                };
 5939
 5940                let matches = matches_task.await;
 5941
 5942                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5943                    // Newer menu already set, so exit.
 5944                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5945                        editor.context_menu.borrow().as_ref()
 5946                        && prev_menu.id > id
 5947                    {
 5948                        return;
 5949                    };
 5950
 5951                    // Only valid to take prev_menu because either the new menu is immediately set
 5952                    // below, or the menu is hidden.
 5953                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5954                        editor.context_menu.borrow_mut().take()
 5955                    {
 5956                        let position_matches =
 5957                            if prev_menu.initial_position == menu.initial_position {
 5958                                true
 5959                            } else {
 5960                                let snapshot = editor.buffer.read(cx).read(cx);
 5961                                prev_menu.initial_position.to_offset(&snapshot)
 5962                                    == menu.initial_position.to_offset(&snapshot)
 5963                            };
 5964                        if position_matches {
 5965                            // Preserve markdown cache before `set_filter_results` because it will
 5966                            // try to populate the documentation cache.
 5967                            menu.preserve_markdown_cache(prev_menu);
 5968                        }
 5969                    };
 5970
 5971                    menu.set_filter_results(matches, provider, window, cx);
 5972                }) else {
 5973                    return;
 5974                };
 5975
 5976                menu.visible().then_some(menu)
 5977            };
 5978
 5979            editor
 5980                .update_in(cx, |editor, window, cx| {
 5981                    if editor.focus_handle.is_focused(window)
 5982                        && let Some(menu) = menu
 5983                    {
 5984                        *editor.context_menu.borrow_mut() =
 5985                            Some(CodeContextMenu::Completions(menu));
 5986
 5987                        crate::hover_popover::hide_hover(editor, cx);
 5988                        if editor.show_edit_predictions_in_menu() {
 5989                            editor.update_visible_edit_prediction(window, cx);
 5990                        } else {
 5991                            editor.discard_edit_prediction(false, cx);
 5992                        }
 5993
 5994                        cx.notify();
 5995                        return;
 5996                    }
 5997
 5998                    if editor.completion_tasks.len() <= 1 {
 5999                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6000                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6001                        // If it was already hidden and we don't show edit predictions in the menu,
 6002                        // we should also show the edit prediction when available.
 6003                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6004                            editor.update_visible_edit_prediction(window, cx);
 6005                        }
 6006                    }
 6007                })
 6008                .ok();
 6009        });
 6010
 6011        self.completion_tasks.push((id, task));
 6012    }
 6013
 6014    #[cfg(feature = "test-support")]
 6015    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6016        let menu = self.context_menu.borrow();
 6017        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6018            let completions = menu.completions.borrow();
 6019            Some(completions.to_vec())
 6020        } else {
 6021            None
 6022        }
 6023    }
 6024
 6025    pub fn with_completions_menu_matching_id<R>(
 6026        &self,
 6027        id: CompletionId,
 6028        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6029    ) -> R {
 6030        let mut context_menu = self.context_menu.borrow_mut();
 6031        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6032            return f(None);
 6033        };
 6034        if completions_menu.id != id {
 6035            return f(None);
 6036        }
 6037        f(Some(completions_menu))
 6038    }
 6039
 6040    pub fn confirm_completion(
 6041        &mut self,
 6042        action: &ConfirmCompletion,
 6043        window: &mut Window,
 6044        cx: &mut Context<Self>,
 6045    ) -> Option<Task<Result<()>>> {
 6046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6047        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6048    }
 6049
 6050    pub fn confirm_completion_insert(
 6051        &mut self,
 6052        _: &ConfirmCompletionInsert,
 6053        window: &mut Window,
 6054        cx: &mut Context<Self>,
 6055    ) -> Option<Task<Result<()>>> {
 6056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6057        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6058    }
 6059
 6060    pub fn confirm_completion_replace(
 6061        &mut self,
 6062        _: &ConfirmCompletionReplace,
 6063        window: &mut Window,
 6064        cx: &mut Context<Self>,
 6065    ) -> Option<Task<Result<()>>> {
 6066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6067        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6068    }
 6069
 6070    pub fn compose_completion(
 6071        &mut self,
 6072        action: &ComposeCompletion,
 6073        window: &mut Window,
 6074        cx: &mut Context<Self>,
 6075    ) -> Option<Task<Result<()>>> {
 6076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6077        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6078    }
 6079
 6080    fn do_completion(
 6081        &mut self,
 6082        item_ix: Option<usize>,
 6083        intent: CompletionIntent,
 6084        window: &mut Window,
 6085        cx: &mut Context<Editor>,
 6086    ) -> Option<Task<Result<()>>> {
 6087        use language::ToOffset as _;
 6088
 6089        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6090        else {
 6091            return None;
 6092        };
 6093
 6094        let candidate_id = {
 6095            let entries = completions_menu.entries.borrow();
 6096            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6097            if self.show_edit_predictions_in_menu() {
 6098                self.discard_edit_prediction(true, cx);
 6099            }
 6100            mat.candidate_id
 6101        };
 6102
 6103        let completion = completions_menu
 6104            .completions
 6105            .borrow()
 6106            .get(candidate_id)?
 6107            .clone();
 6108        cx.stop_propagation();
 6109
 6110        let buffer_handle = completions_menu.buffer.clone();
 6111
 6112        let CompletionEdit {
 6113            new_text,
 6114            snippet,
 6115            replace_range,
 6116        } = process_completion_for_edit(
 6117            &completion,
 6118            intent,
 6119            &buffer_handle,
 6120            &completions_menu.initial_position.text_anchor,
 6121            cx,
 6122        );
 6123
 6124        let buffer = buffer_handle.read(cx);
 6125        let snapshot = self.buffer.read(cx).snapshot(cx);
 6126        let newest_anchor = self.selections.newest_anchor();
 6127        let replace_range_multibuffer = {
 6128            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6129            excerpt.map_range_from_buffer(replace_range.clone())
 6130        };
 6131        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6132            return None;
 6133        }
 6134
 6135        let old_text = buffer
 6136            .text_for_range(replace_range.clone())
 6137            .collect::<String>();
 6138        let lookbehind = newest_anchor
 6139            .start
 6140            .text_anchor
 6141            .to_offset(buffer)
 6142            .saturating_sub(replace_range.start.0);
 6143        let lookahead = replace_range
 6144            .end
 6145            .0
 6146            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6147        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6148        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6149
 6150        let selections = self
 6151            .selections
 6152            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6153        let mut ranges = Vec::new();
 6154        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6155
 6156        for selection in &selections {
 6157            let range = if selection.id == newest_anchor.id {
 6158                replace_range_multibuffer.clone()
 6159            } else {
 6160                let mut range = selection.range();
 6161
 6162                // if prefix is present, don't duplicate it
 6163                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6164                    range.start = range.start.saturating_sub_usize(lookbehind);
 6165
 6166                    // if suffix is also present, mimic the newest cursor and replace it
 6167                    if selection.id != newest_anchor.id
 6168                        && snapshot.contains_str_at(range.end, suffix)
 6169                    {
 6170                        range.end += lookahead;
 6171                    }
 6172                }
 6173                range
 6174            };
 6175
 6176            ranges.push(range.clone());
 6177
 6178            if !self.linked_edit_ranges.is_empty() {
 6179                let start_anchor = snapshot.anchor_before(range.start);
 6180                let end_anchor = snapshot.anchor_after(range.end);
 6181                if let Some(ranges) = self
 6182                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6183                {
 6184                    for (buffer, edits) in ranges {
 6185                        linked_edits
 6186                            .entry(buffer.clone())
 6187                            .or_default()
 6188                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6189                    }
 6190                }
 6191            }
 6192        }
 6193
 6194        let common_prefix_len = old_text
 6195            .chars()
 6196            .zip(new_text.chars())
 6197            .take_while(|(a, b)| a == b)
 6198            .map(|(a, _)| a.len_utf8())
 6199            .sum::<usize>();
 6200
 6201        cx.emit(EditorEvent::InputHandled {
 6202            utf16_range_to_replace: None,
 6203            text: new_text[common_prefix_len..].into(),
 6204        });
 6205
 6206        self.transact(window, cx, |editor, window, cx| {
 6207            if let Some(mut snippet) = snippet {
 6208                snippet.text = new_text.to_string();
 6209                editor
 6210                    .insert_snippet(&ranges, snippet, window, cx)
 6211                    .log_err();
 6212            } else {
 6213                editor.buffer.update(cx, |multi_buffer, cx| {
 6214                    let auto_indent = match completion.insert_text_mode {
 6215                        Some(InsertTextMode::AS_IS) => None,
 6216                        _ => editor.autoindent_mode.clone(),
 6217                    };
 6218                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6219                    multi_buffer.edit(edits, auto_indent, cx);
 6220                });
 6221            }
 6222            for (buffer, edits) in linked_edits {
 6223                buffer.update(cx, |buffer, cx| {
 6224                    let snapshot = buffer.snapshot();
 6225                    let edits = edits
 6226                        .into_iter()
 6227                        .map(|(range, text)| {
 6228                            use text::ToPoint as TP;
 6229                            let end_point = TP::to_point(&range.end, &snapshot);
 6230                            let start_point = TP::to_point(&range.start, &snapshot);
 6231                            (start_point..end_point, text)
 6232                        })
 6233                        .sorted_by_key(|(range, _)| range.start);
 6234                    buffer.edit(edits, None, cx);
 6235                })
 6236            }
 6237
 6238            editor.refresh_edit_prediction(true, false, window, cx);
 6239        });
 6240        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6241
 6242        let show_new_completions_on_confirm = completion
 6243            .confirm
 6244            .as_ref()
 6245            .is_some_and(|confirm| confirm(intent, window, cx));
 6246        if show_new_completions_on_confirm {
 6247            self.open_or_update_completions_menu(None, None, false, window, cx);
 6248        }
 6249
 6250        let provider = self.completion_provider.as_ref()?;
 6251
 6252        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6253        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6254            let CompletionSource::Lsp {
 6255                lsp_completion,
 6256                server_id,
 6257                ..
 6258            } = &completion.source
 6259            else {
 6260                return None;
 6261            };
 6262            let lsp_command = lsp_completion.command.as_ref()?;
 6263            let available_commands = lsp_store
 6264                .read(cx)
 6265                .lsp_server_capabilities
 6266                .get(server_id)
 6267                .and_then(|server_capabilities| {
 6268                    server_capabilities
 6269                        .execute_command_provider
 6270                        .as_ref()
 6271                        .map(|options| options.commands.as_slice())
 6272                })?;
 6273            if available_commands.contains(&lsp_command.command) {
 6274                Some(CodeAction {
 6275                    server_id: *server_id,
 6276                    range: language::Anchor::MIN..language::Anchor::MIN,
 6277                    lsp_action: LspAction::Command(lsp_command.clone()),
 6278                    resolved: false,
 6279                })
 6280            } else {
 6281                None
 6282            }
 6283        });
 6284
 6285        drop(completion);
 6286        let apply_edits = provider.apply_additional_edits_for_completion(
 6287            buffer_handle.clone(),
 6288            completions_menu.completions.clone(),
 6289            candidate_id,
 6290            true,
 6291            cx,
 6292        );
 6293
 6294        let editor_settings = EditorSettings::get_global(cx);
 6295        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6296            // After the code completion is finished, users often want to know what signatures are needed.
 6297            // so we should automatically call signature_help
 6298            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6299        }
 6300
 6301        Some(cx.spawn_in(window, async move |editor, cx| {
 6302            apply_edits.await?;
 6303
 6304            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6305                let title = command.lsp_action.title().to_owned();
 6306                let project_transaction = lsp_store
 6307                    .update(cx, |lsp_store, cx| {
 6308                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6309                    })?
 6310                    .await
 6311                    .context("applying post-completion command")?;
 6312                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6313                    Self::open_project_transaction(
 6314                        &editor,
 6315                        workspace.downgrade(),
 6316                        project_transaction,
 6317                        title,
 6318                        cx,
 6319                    )
 6320                    .await?;
 6321                }
 6322            }
 6323
 6324            Ok(())
 6325        }))
 6326    }
 6327
 6328    pub fn toggle_code_actions(
 6329        &mut self,
 6330        action: &ToggleCodeActions,
 6331        window: &mut Window,
 6332        cx: &mut Context<Self>,
 6333    ) {
 6334        let quick_launch = action.quick_launch;
 6335        let mut context_menu = self.context_menu.borrow_mut();
 6336        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6337            if code_actions.deployed_from == action.deployed_from {
 6338                // Toggle if we're selecting the same one
 6339                *context_menu = None;
 6340                cx.notify();
 6341                return;
 6342            } else {
 6343                // Otherwise, clear it and start a new one
 6344                *context_menu = None;
 6345                cx.notify();
 6346            }
 6347        }
 6348        drop(context_menu);
 6349        let snapshot = self.snapshot(window, cx);
 6350        let deployed_from = action.deployed_from.clone();
 6351        let action = action.clone();
 6352        self.completion_tasks.clear();
 6353        self.discard_edit_prediction(false, cx);
 6354
 6355        let multibuffer_point = match &action.deployed_from {
 6356            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6357                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6358            }
 6359            _ => self
 6360                .selections
 6361                .newest::<Point>(&snapshot.display_snapshot)
 6362                .head(),
 6363        };
 6364        let Some((buffer, buffer_row)) = snapshot
 6365            .buffer_snapshot()
 6366            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6367            .and_then(|(buffer_snapshot, range)| {
 6368                self.buffer()
 6369                    .read(cx)
 6370                    .buffer(buffer_snapshot.remote_id())
 6371                    .map(|buffer| (buffer, range.start.row))
 6372            })
 6373        else {
 6374            return;
 6375        };
 6376        let buffer_id = buffer.read(cx).remote_id();
 6377        let tasks = self
 6378            .tasks
 6379            .get(&(buffer_id, buffer_row))
 6380            .map(|t| Arc::new(t.to_owned()));
 6381
 6382        if !self.focus_handle.is_focused(window) {
 6383            return;
 6384        }
 6385        let project = self.project.clone();
 6386
 6387        let code_actions_task = match deployed_from {
 6388            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6389            _ => self.code_actions(buffer_row, window, cx),
 6390        };
 6391
 6392        let runnable_task = match deployed_from {
 6393            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6394            _ => {
 6395                let mut task_context_task = Task::ready(None);
 6396                if let Some(tasks) = &tasks
 6397                    && let Some(project) = project
 6398                {
 6399                    task_context_task =
 6400                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6401                }
 6402
 6403                cx.spawn_in(window, {
 6404                    let buffer = buffer.clone();
 6405                    async move |editor, cx| {
 6406                        let task_context = task_context_task.await;
 6407
 6408                        let resolved_tasks =
 6409                            tasks
 6410                                .zip(task_context.clone())
 6411                                .map(|(tasks, task_context)| ResolvedTasks {
 6412                                    templates: tasks.resolve(&task_context).collect(),
 6413                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6414                                        multibuffer_point.row,
 6415                                        tasks.column,
 6416                                    )),
 6417                                });
 6418                        let debug_scenarios = editor
 6419                            .update(cx, |editor, cx| {
 6420                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6421                            })?
 6422                            .await;
 6423                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6424                    }
 6425                })
 6426            }
 6427        };
 6428
 6429        cx.spawn_in(window, async move |editor, cx| {
 6430            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6431            let code_actions = code_actions_task.await;
 6432            let spawn_straight_away = quick_launch
 6433                && resolved_tasks
 6434                    .as_ref()
 6435                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6436                && code_actions
 6437                    .as_ref()
 6438                    .is_none_or(|actions| actions.is_empty())
 6439                && debug_scenarios.is_empty();
 6440
 6441            editor.update_in(cx, |editor, window, cx| {
 6442                crate::hover_popover::hide_hover(editor, cx);
 6443                let actions = CodeActionContents::new(
 6444                    resolved_tasks,
 6445                    code_actions,
 6446                    debug_scenarios,
 6447                    task_context.unwrap_or_default(),
 6448                );
 6449
 6450                // Don't show the menu if there are no actions available
 6451                if actions.is_empty() {
 6452                    cx.notify();
 6453                    return Task::ready(Ok(()));
 6454                }
 6455
 6456                *editor.context_menu.borrow_mut() =
 6457                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6458                        buffer,
 6459                        actions,
 6460                        selected_item: Default::default(),
 6461                        scroll_handle: UniformListScrollHandle::default(),
 6462                        deployed_from,
 6463                    }));
 6464                cx.notify();
 6465                if spawn_straight_away
 6466                    && let Some(task) = editor.confirm_code_action(
 6467                        &ConfirmCodeAction { item_ix: Some(0) },
 6468                        window,
 6469                        cx,
 6470                    )
 6471                {
 6472                    return task;
 6473                }
 6474
 6475                Task::ready(Ok(()))
 6476            })
 6477        })
 6478        .detach_and_log_err(cx);
 6479    }
 6480
 6481    fn debug_scenarios(
 6482        &mut self,
 6483        resolved_tasks: &Option<ResolvedTasks>,
 6484        buffer: &Entity<Buffer>,
 6485        cx: &mut App,
 6486    ) -> Task<Vec<task::DebugScenario>> {
 6487        maybe!({
 6488            let project = self.project()?;
 6489            let dap_store = project.read(cx).dap_store();
 6490            let mut scenarios = vec![];
 6491            let resolved_tasks = resolved_tasks.as_ref()?;
 6492            let buffer = buffer.read(cx);
 6493            let language = buffer.language()?;
 6494            let file = buffer.file();
 6495            let debug_adapter = language_settings(language.name().into(), file, cx)
 6496                .debuggers
 6497                .first()
 6498                .map(SharedString::from)
 6499                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6500
 6501            dap_store.update(cx, |dap_store, cx| {
 6502                for (_, task) in &resolved_tasks.templates {
 6503                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6504                        task.original_task().clone(),
 6505                        debug_adapter.clone().into(),
 6506                        task.display_label().to_owned().into(),
 6507                        cx,
 6508                    );
 6509                    scenarios.push(maybe_scenario);
 6510                }
 6511            });
 6512            Some(cx.background_spawn(async move {
 6513                futures::future::join_all(scenarios)
 6514                    .await
 6515                    .into_iter()
 6516                    .flatten()
 6517                    .collect::<Vec<_>>()
 6518            }))
 6519        })
 6520        .unwrap_or_else(|| Task::ready(vec![]))
 6521    }
 6522
 6523    fn code_actions(
 6524        &mut self,
 6525        buffer_row: u32,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6529        let mut task = self.code_actions_task.take();
 6530        cx.spawn_in(window, async move |editor, cx| {
 6531            while let Some(prev_task) = task {
 6532                prev_task.await.log_err();
 6533                task = editor
 6534                    .update(cx, |this, _| this.code_actions_task.take())
 6535                    .ok()?;
 6536            }
 6537
 6538            editor
 6539                .update(cx, |editor, cx| {
 6540                    editor
 6541                        .available_code_actions
 6542                        .clone()
 6543                        .and_then(|(location, code_actions)| {
 6544                            let snapshot = location.buffer.read(cx).snapshot();
 6545                            let point_range = location.range.to_point(&snapshot);
 6546                            let point_range = point_range.start.row..=point_range.end.row;
 6547                            if point_range.contains(&buffer_row) {
 6548                                Some(code_actions)
 6549                            } else {
 6550                                None
 6551                            }
 6552                        })
 6553                })
 6554                .ok()
 6555                .flatten()
 6556        })
 6557    }
 6558
 6559    pub fn confirm_code_action(
 6560        &mut self,
 6561        action: &ConfirmCodeAction,
 6562        window: &mut Window,
 6563        cx: &mut Context<Self>,
 6564    ) -> Option<Task<Result<()>>> {
 6565        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6566
 6567        let actions_menu =
 6568            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6569                menu
 6570            } else {
 6571                return None;
 6572            };
 6573
 6574        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6575        let action = actions_menu.actions.get(action_ix)?;
 6576        let title = action.label();
 6577        let buffer = actions_menu.buffer;
 6578        let workspace = self.workspace()?;
 6579
 6580        match action {
 6581            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6582                workspace.update(cx, |workspace, cx| {
 6583                    workspace.schedule_resolved_task(
 6584                        task_source_kind,
 6585                        resolved_task,
 6586                        false,
 6587                        window,
 6588                        cx,
 6589                    );
 6590
 6591                    Some(Task::ready(Ok(())))
 6592                })
 6593            }
 6594            CodeActionsItem::CodeAction {
 6595                excerpt_id,
 6596                action,
 6597                provider,
 6598            } => {
 6599                let apply_code_action =
 6600                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6601                let workspace = workspace.downgrade();
 6602                Some(cx.spawn_in(window, async move |editor, cx| {
 6603                    let project_transaction = apply_code_action.await?;
 6604                    Self::open_project_transaction(
 6605                        &editor,
 6606                        workspace,
 6607                        project_transaction,
 6608                        title,
 6609                        cx,
 6610                    )
 6611                    .await
 6612                }))
 6613            }
 6614            CodeActionsItem::DebugScenario(scenario) => {
 6615                let context = actions_menu.actions.context;
 6616
 6617                workspace.update(cx, |workspace, cx| {
 6618                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6619                    workspace.start_debug_session(
 6620                        scenario,
 6621                        context,
 6622                        Some(buffer),
 6623                        None,
 6624                        window,
 6625                        cx,
 6626                    );
 6627                });
 6628                Some(Task::ready(Ok(())))
 6629            }
 6630        }
 6631    }
 6632
 6633    fn open_transaction_for_hidden_buffers(
 6634        workspace: Entity<Workspace>,
 6635        transaction: ProjectTransaction,
 6636        title: String,
 6637        window: &mut Window,
 6638        cx: &mut Context<Self>,
 6639    ) {
 6640        if transaction.0.is_empty() {
 6641            return;
 6642        }
 6643
 6644        let edited_buffers_already_open = {
 6645            let other_editors: Vec<Entity<Editor>> = workspace
 6646                .read(cx)
 6647                .panes()
 6648                .iter()
 6649                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6650                .filter(|editor| editor.entity_id() != cx.entity_id())
 6651                .collect();
 6652
 6653            transaction.0.keys().all(|buffer| {
 6654                other_editors.iter().any(|editor| {
 6655                    let multi_buffer = editor.read(cx).buffer();
 6656                    multi_buffer.read(cx).is_singleton()
 6657                        && multi_buffer
 6658                            .read(cx)
 6659                            .as_singleton()
 6660                            .map_or(false, |singleton| {
 6661                                singleton.entity_id() == buffer.entity_id()
 6662                            })
 6663                })
 6664            })
 6665        };
 6666        if !edited_buffers_already_open {
 6667            let workspace = workspace.downgrade();
 6668            cx.defer_in(window, move |_, window, cx| {
 6669                cx.spawn_in(window, async move |editor, cx| {
 6670                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6671                        .await
 6672                        .ok()
 6673                })
 6674                .detach();
 6675            });
 6676        }
 6677    }
 6678
 6679    pub async fn open_project_transaction(
 6680        editor: &WeakEntity<Editor>,
 6681        workspace: WeakEntity<Workspace>,
 6682        transaction: ProjectTransaction,
 6683        title: String,
 6684        cx: &mut AsyncWindowContext,
 6685    ) -> Result<()> {
 6686        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6687        cx.update(|_, cx| {
 6688            entries.sort_unstable_by_key(|(buffer, _)| {
 6689                buffer.read(cx).file().map(|f| f.path().clone())
 6690            });
 6691        })?;
 6692        if entries.is_empty() {
 6693            return Ok(());
 6694        }
 6695
 6696        // If the project transaction's edits are all contained within this editor, then
 6697        // avoid opening a new editor to display them.
 6698
 6699        if let [(buffer, transaction)] = &*entries {
 6700            let excerpt = editor.update(cx, |editor, cx| {
 6701                editor
 6702                    .buffer()
 6703                    .read(cx)
 6704                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6705            })?;
 6706            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6707                && excerpted_buffer == *buffer
 6708            {
 6709                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6710                    let excerpt_range = excerpt_range.to_offset(buffer);
 6711                    buffer
 6712                        .edited_ranges_for_transaction::<usize>(transaction)
 6713                        .all(|range| {
 6714                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6715                        })
 6716                })?;
 6717
 6718                if all_edits_within_excerpt {
 6719                    return Ok(());
 6720                }
 6721            }
 6722        }
 6723
 6724        let mut ranges_to_highlight = Vec::new();
 6725        let excerpt_buffer = cx.new(|cx| {
 6726            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6727            for (buffer_handle, transaction) in &entries {
 6728                let edited_ranges = buffer_handle
 6729                    .read(cx)
 6730                    .edited_ranges_for_transaction::<Point>(transaction)
 6731                    .collect::<Vec<_>>();
 6732                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6733                    PathKey::for_buffer(buffer_handle, cx),
 6734                    buffer_handle.clone(),
 6735                    edited_ranges,
 6736                    multibuffer_context_lines(cx),
 6737                    cx,
 6738                );
 6739
 6740                ranges_to_highlight.extend(ranges);
 6741            }
 6742            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6743            multibuffer
 6744        })?;
 6745
 6746        workspace.update_in(cx, |workspace, window, cx| {
 6747            let project = workspace.project().clone();
 6748            let editor =
 6749                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6750            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6751            editor.update(cx, |editor, cx| {
 6752                editor.highlight_background::<Self>(
 6753                    &ranges_to_highlight,
 6754                    |_, theme| theme.colors().editor_highlighted_line_background,
 6755                    cx,
 6756                );
 6757            });
 6758        })?;
 6759
 6760        Ok(())
 6761    }
 6762
 6763    pub fn clear_code_action_providers(&mut self) {
 6764        self.code_action_providers.clear();
 6765        self.available_code_actions.take();
 6766    }
 6767
 6768    pub fn add_code_action_provider(
 6769        &mut self,
 6770        provider: Rc<dyn CodeActionProvider>,
 6771        window: &mut Window,
 6772        cx: &mut Context<Self>,
 6773    ) {
 6774        if self
 6775            .code_action_providers
 6776            .iter()
 6777            .any(|existing_provider| existing_provider.id() == provider.id())
 6778        {
 6779            return;
 6780        }
 6781
 6782        self.code_action_providers.push(provider);
 6783        self.refresh_code_actions(window, cx);
 6784    }
 6785
 6786    pub fn remove_code_action_provider(
 6787        &mut self,
 6788        id: Arc<str>,
 6789        window: &mut Window,
 6790        cx: &mut Context<Self>,
 6791    ) {
 6792        self.code_action_providers
 6793            .retain(|provider| provider.id() != id);
 6794        self.refresh_code_actions(window, cx);
 6795    }
 6796
 6797    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6798        !self.code_action_providers.is_empty()
 6799            && EditorSettings::get_global(cx).toolbar.code_actions
 6800    }
 6801
 6802    pub fn has_available_code_actions(&self) -> bool {
 6803        self.available_code_actions
 6804            .as_ref()
 6805            .is_some_and(|(_, actions)| !actions.is_empty())
 6806    }
 6807
 6808    fn render_inline_code_actions(
 6809        &self,
 6810        icon_size: ui::IconSize,
 6811        display_row: DisplayRow,
 6812        is_active: bool,
 6813        cx: &mut Context<Self>,
 6814    ) -> AnyElement {
 6815        let show_tooltip = !self.context_menu_visible();
 6816        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6817            .icon_size(icon_size)
 6818            .shape(ui::IconButtonShape::Square)
 6819            .icon_color(ui::Color::Hidden)
 6820            .toggle_state(is_active)
 6821            .when(show_tooltip, |this| {
 6822                this.tooltip({
 6823                    let focus_handle = self.focus_handle.clone();
 6824                    move |_window, cx| {
 6825                        Tooltip::for_action_in(
 6826                            "Toggle Code Actions",
 6827                            &ToggleCodeActions {
 6828                                deployed_from: None,
 6829                                quick_launch: false,
 6830                            },
 6831                            &focus_handle,
 6832                            cx,
 6833                        )
 6834                    }
 6835                })
 6836            })
 6837            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6838                window.focus(&editor.focus_handle(cx), cx);
 6839                editor.toggle_code_actions(
 6840                    &crate::actions::ToggleCodeActions {
 6841                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6842                            display_row,
 6843                        )),
 6844                        quick_launch: false,
 6845                    },
 6846                    window,
 6847                    cx,
 6848                );
 6849            }))
 6850            .into_any_element()
 6851    }
 6852
 6853    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6854        &self.context_menu
 6855    }
 6856
 6857    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6858        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6859            cx.background_executor()
 6860                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6861                .await;
 6862
 6863            let (start_buffer, start, _, end, newest_selection) = this
 6864                .update(cx, |this, cx| {
 6865                    let newest_selection = this.selections.newest_anchor().clone();
 6866                    if newest_selection.head().diff_base_anchor.is_some() {
 6867                        return None;
 6868                    }
 6869                    let display_snapshot = this.display_snapshot(cx);
 6870                    let newest_selection_adjusted =
 6871                        this.selections.newest_adjusted(&display_snapshot);
 6872                    let buffer = this.buffer.read(cx);
 6873
 6874                    let (start_buffer, start) =
 6875                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6876                    let (end_buffer, end) =
 6877                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6878
 6879                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6880                })?
 6881                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6882                .context(
 6883                    "Expected selection to lie in a single buffer when refreshing code actions",
 6884                )?;
 6885            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6886                let providers = this.code_action_providers.clone();
 6887                let tasks = this
 6888                    .code_action_providers
 6889                    .iter()
 6890                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6891                    .collect::<Vec<_>>();
 6892                (providers, tasks)
 6893            })?;
 6894
 6895            let mut actions = Vec::new();
 6896            for (provider, provider_actions) in
 6897                providers.into_iter().zip(future::join_all(tasks).await)
 6898            {
 6899                if let Some(provider_actions) = provider_actions.log_err() {
 6900                    actions.extend(provider_actions.into_iter().map(|action| {
 6901                        AvailableCodeAction {
 6902                            excerpt_id: newest_selection.start.excerpt_id,
 6903                            action,
 6904                            provider: provider.clone(),
 6905                        }
 6906                    }));
 6907                }
 6908            }
 6909
 6910            this.update(cx, |this, cx| {
 6911                this.available_code_actions = if actions.is_empty() {
 6912                    None
 6913                } else {
 6914                    Some((
 6915                        Location {
 6916                            buffer: start_buffer,
 6917                            range: start..end,
 6918                        },
 6919                        actions.into(),
 6920                    ))
 6921                };
 6922                cx.notify();
 6923            })
 6924        }));
 6925    }
 6926
 6927    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6928        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6929            self.show_git_blame_inline = false;
 6930
 6931            self.show_git_blame_inline_delay_task =
 6932                Some(cx.spawn_in(window, async move |this, cx| {
 6933                    cx.background_executor().timer(delay).await;
 6934
 6935                    this.update(cx, |this, cx| {
 6936                        this.show_git_blame_inline = true;
 6937                        cx.notify();
 6938                    })
 6939                    .log_err();
 6940                }));
 6941        }
 6942    }
 6943
 6944    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6945        let snapshot = self.snapshot(window, cx);
 6946        let cursor = self
 6947            .selections
 6948            .newest::<Point>(&snapshot.display_snapshot)
 6949            .head();
 6950        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6951        else {
 6952            return;
 6953        };
 6954
 6955        if self.blame.is_none() {
 6956            self.start_git_blame(true, window, cx);
 6957        }
 6958        let Some(blame) = self.blame.as_ref() else {
 6959            return;
 6960        };
 6961
 6962        let row_info = RowInfo {
 6963            buffer_id: Some(buffer.remote_id()),
 6964            buffer_row: Some(point.row),
 6965            ..Default::default()
 6966        };
 6967        let Some((buffer, blame_entry)) = blame
 6968            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6969            .flatten()
 6970        else {
 6971            return;
 6972        };
 6973
 6974        let anchor = self.selections.newest_anchor().head();
 6975        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6976        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6977            self.show_blame_popover(
 6978                buffer,
 6979                &blame_entry,
 6980                position + last_bounds.origin,
 6981                true,
 6982                cx,
 6983            );
 6984        };
 6985    }
 6986
 6987    fn show_blame_popover(
 6988        &mut self,
 6989        buffer: BufferId,
 6990        blame_entry: &BlameEntry,
 6991        position: gpui::Point<Pixels>,
 6992        ignore_timeout: bool,
 6993        cx: &mut Context<Self>,
 6994    ) {
 6995        if let Some(state) = &mut self.inline_blame_popover {
 6996            state.hide_task.take();
 6997        } else {
 6998            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6999            let blame_entry = blame_entry.clone();
 7000            let show_task = cx.spawn(async move |editor, cx| {
 7001                if !ignore_timeout {
 7002                    cx.background_executor()
 7003                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7004                        .await;
 7005                }
 7006                editor
 7007                    .update(cx, |editor, cx| {
 7008                        editor.inline_blame_popover_show_task.take();
 7009                        let Some(blame) = editor.blame.as_ref() else {
 7010                            return;
 7011                        };
 7012                        let blame = blame.read(cx);
 7013                        let details = blame.details_for_entry(buffer, &blame_entry);
 7014                        let markdown = cx.new(|cx| {
 7015                            Markdown::new(
 7016                                details
 7017                                    .as_ref()
 7018                                    .map(|message| message.message.clone())
 7019                                    .unwrap_or_default(),
 7020                                None,
 7021                                None,
 7022                                cx,
 7023                            )
 7024                        });
 7025                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7026                            position,
 7027                            hide_task: None,
 7028                            popover_bounds: None,
 7029                            popover_state: InlineBlamePopoverState {
 7030                                scroll_handle: ScrollHandle::new(),
 7031                                commit_message: details,
 7032                                markdown,
 7033                            },
 7034                            keyboard_grace: ignore_timeout,
 7035                        });
 7036                        cx.notify();
 7037                    })
 7038                    .ok();
 7039            });
 7040            self.inline_blame_popover_show_task = Some(show_task);
 7041        }
 7042    }
 7043
 7044    pub fn has_mouse_context_menu(&self) -> bool {
 7045        self.mouse_context_menu.is_some()
 7046    }
 7047
 7048    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7049        self.inline_blame_popover_show_task.take();
 7050        if let Some(state) = &mut self.inline_blame_popover {
 7051            let hide_task = cx.spawn(async move |editor, cx| {
 7052                if !ignore_timeout {
 7053                    cx.background_executor()
 7054                        .timer(std::time::Duration::from_millis(100))
 7055                        .await;
 7056                }
 7057                editor
 7058                    .update(cx, |editor, cx| {
 7059                        editor.inline_blame_popover.take();
 7060                        cx.notify();
 7061                    })
 7062                    .ok();
 7063            });
 7064            state.hide_task = Some(hide_task);
 7065            true
 7066        } else {
 7067            false
 7068        }
 7069    }
 7070
 7071    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7072        if self.pending_rename.is_some() {
 7073            return None;
 7074        }
 7075
 7076        let provider = self.semantics_provider.clone()?;
 7077        let buffer = self.buffer.read(cx);
 7078        let newest_selection = self.selections.newest_anchor().clone();
 7079        let cursor_position = newest_selection.head();
 7080        let (cursor_buffer, cursor_buffer_position) =
 7081            buffer.text_anchor_for_position(cursor_position, cx)?;
 7082        let (tail_buffer, tail_buffer_position) =
 7083            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7084        if cursor_buffer != tail_buffer {
 7085            return None;
 7086        }
 7087
 7088        let snapshot = cursor_buffer.read(cx).snapshot();
 7089        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7090        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7091        if start_word_range != end_word_range {
 7092            self.document_highlights_task.take();
 7093            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7094            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7095            return None;
 7096        }
 7097
 7098        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7099        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7100            cx.background_executor()
 7101                .timer(Duration::from_millis(debounce))
 7102                .await;
 7103
 7104            let highlights = if let Some(highlights) = cx
 7105                .update(|cx| {
 7106                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7107                })
 7108                .ok()
 7109                .flatten()
 7110            {
 7111                highlights.await.log_err()
 7112            } else {
 7113                None
 7114            };
 7115
 7116            if let Some(highlights) = highlights {
 7117                this.update(cx, |this, cx| {
 7118                    if this.pending_rename.is_some() {
 7119                        return;
 7120                    }
 7121
 7122                    let buffer = this.buffer.read(cx);
 7123                    if buffer
 7124                        .text_anchor_for_position(cursor_position, cx)
 7125                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7126                    {
 7127                        return;
 7128                    }
 7129
 7130                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7131                    let mut write_ranges = Vec::new();
 7132                    let mut read_ranges = Vec::new();
 7133                    for highlight in highlights {
 7134                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7135                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7136                        {
 7137                            let start = highlight
 7138                                .range
 7139                                .start
 7140                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7141                            let end = highlight
 7142                                .range
 7143                                .end
 7144                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7145                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7146                                continue;
 7147                            }
 7148
 7149                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7150                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7151                                write_ranges.push(range);
 7152                            } else {
 7153                                read_ranges.push(range);
 7154                            }
 7155                        }
 7156                    }
 7157
 7158                    this.highlight_background::<DocumentHighlightRead>(
 7159                        &read_ranges,
 7160                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7161                        cx,
 7162                    );
 7163                    this.highlight_background::<DocumentHighlightWrite>(
 7164                        &write_ranges,
 7165                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7166                        cx,
 7167                    );
 7168                    cx.notify();
 7169                })
 7170                .log_err();
 7171            }
 7172        }));
 7173        None
 7174    }
 7175
 7176    fn prepare_highlight_query_from_selection(
 7177        &mut self,
 7178        window: &Window,
 7179        cx: &mut Context<Editor>,
 7180    ) -> Option<(String, Range<Anchor>)> {
 7181        if matches!(self.mode, EditorMode::SingleLine) {
 7182            return None;
 7183        }
 7184        if !EditorSettings::get_global(cx).selection_highlight {
 7185            return None;
 7186        }
 7187        if self.selections.count() != 1 || self.selections.line_mode() {
 7188            return None;
 7189        }
 7190        let snapshot = self.snapshot(window, cx);
 7191        let selection = self.selections.newest::<Point>(&snapshot);
 7192        // If the selection spans multiple rows OR it is empty
 7193        if selection.start.row != selection.end.row
 7194            || selection.start.column == selection.end.column
 7195        {
 7196            return None;
 7197        }
 7198        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7199        let query = snapshot
 7200            .buffer_snapshot()
 7201            .text_for_range(selection_anchor_range.clone())
 7202            .collect::<String>();
 7203        if query.trim().is_empty() {
 7204            return None;
 7205        }
 7206        Some((query, selection_anchor_range))
 7207    }
 7208
 7209    #[ztracing::instrument(skip_all)]
 7210    fn update_selection_occurrence_highlights(
 7211        &mut self,
 7212        query_text: String,
 7213        query_range: Range<Anchor>,
 7214        multi_buffer_range_to_query: Range<Point>,
 7215        use_debounce: bool,
 7216        window: &mut Window,
 7217        cx: &mut Context<Editor>,
 7218    ) -> Task<()> {
 7219        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7220        cx.spawn_in(window, async move |editor, cx| {
 7221            if use_debounce {
 7222                cx.background_executor()
 7223                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7224                    .await;
 7225            }
 7226            let match_task = cx.background_spawn(async move {
 7227                let buffer_ranges = multi_buffer_snapshot
 7228                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7229                    .into_iter()
 7230                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7231                let mut match_ranges = Vec::new();
 7232                let Ok(regex) = project::search::SearchQuery::text(
 7233                    query_text.clone(),
 7234                    false,
 7235                    false,
 7236                    false,
 7237                    Default::default(),
 7238                    Default::default(),
 7239                    false,
 7240                    None,
 7241                ) else {
 7242                    return Vec::default();
 7243                };
 7244                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7245                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7246                    match_ranges.extend(
 7247                        regex
 7248                            .search(
 7249                                buffer_snapshot,
 7250                                Some(search_range.start.0..search_range.end.0),
 7251                            )
 7252                            .await
 7253                            .into_iter()
 7254                            .filter_map(|match_range| {
 7255                                let match_start = buffer_snapshot
 7256                                    .anchor_after(search_range.start + match_range.start);
 7257                                let match_end = buffer_snapshot
 7258                                    .anchor_before(search_range.start + match_range.end);
 7259                                let match_anchor_range =
 7260                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7261                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7262                            }),
 7263                    );
 7264                }
 7265                match_ranges
 7266            });
 7267            let match_ranges = match_task.await;
 7268            editor
 7269                .update_in(cx, |editor, _, cx| {
 7270                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7271                    if !match_ranges.is_empty() {
 7272                        editor.highlight_background::<SelectedTextHighlight>(
 7273                            &match_ranges,
 7274                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7275                            cx,
 7276                        )
 7277                    }
 7278                })
 7279                .log_err();
 7280        })
 7281    }
 7282
 7283    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7284        struct NewlineFold;
 7285        let type_id = std::any::TypeId::of::<NewlineFold>();
 7286        if !self.mode.is_single_line() {
 7287            return;
 7288        }
 7289        let snapshot = self.snapshot(window, cx);
 7290        if snapshot.buffer_snapshot().max_point().row == 0 {
 7291            return;
 7292        }
 7293        let task = cx.background_spawn(async move {
 7294            let new_newlines = snapshot
 7295                .buffer_chars_at(MultiBufferOffset(0))
 7296                .filter_map(|(c, i)| {
 7297                    if c == '\n' {
 7298                        Some(
 7299                            snapshot.buffer_snapshot().anchor_after(i)
 7300                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7301                        )
 7302                    } else {
 7303                        None
 7304                    }
 7305                })
 7306                .collect::<Vec<_>>();
 7307            let existing_newlines = snapshot
 7308                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7309                .filter_map(|fold| {
 7310                    if fold.placeholder.type_tag == Some(type_id) {
 7311                        Some(fold.range.start..fold.range.end)
 7312                    } else {
 7313                        None
 7314                    }
 7315                })
 7316                .collect::<Vec<_>>();
 7317
 7318            (new_newlines, existing_newlines)
 7319        });
 7320        self.folding_newlines = cx.spawn(async move |this, cx| {
 7321            let (new_newlines, existing_newlines) = task.await;
 7322            if new_newlines == existing_newlines {
 7323                return;
 7324            }
 7325            let placeholder = FoldPlaceholder {
 7326                render: Arc::new(move |_, _, cx| {
 7327                    div()
 7328                        .bg(cx.theme().status().hint_background)
 7329                        .border_b_1()
 7330                        .size_full()
 7331                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7332                        .border_color(cx.theme().status().hint)
 7333                        .child("\\n")
 7334                        .into_any()
 7335                }),
 7336                constrain_width: false,
 7337                merge_adjacent: false,
 7338                type_tag: Some(type_id),
 7339            };
 7340            let creases = new_newlines
 7341                .into_iter()
 7342                .map(|range| Crease::simple(range, placeholder.clone()))
 7343                .collect();
 7344            this.update(cx, |this, cx| {
 7345                this.display_map.update(cx, |display_map, cx| {
 7346                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7347                    display_map.fold(creases, cx);
 7348                });
 7349            })
 7350            .ok();
 7351        });
 7352    }
 7353
 7354    #[ztracing::instrument(skip_all)]
 7355    fn refresh_selected_text_highlights(
 7356        &mut self,
 7357        on_buffer_edit: bool,
 7358        window: &mut Window,
 7359        cx: &mut Context<Editor>,
 7360    ) {
 7361        let Some((query_text, query_range)) =
 7362            self.prepare_highlight_query_from_selection(window, cx)
 7363        else {
 7364            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7365            self.quick_selection_highlight_task.take();
 7366            self.debounced_selection_highlight_task.take();
 7367            return;
 7368        };
 7369        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7370        if on_buffer_edit
 7371            || self
 7372                .quick_selection_highlight_task
 7373                .as_ref()
 7374                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7375        {
 7376            let multi_buffer_visible_start = self
 7377                .scroll_manager
 7378                .anchor()
 7379                .anchor
 7380                .to_point(&multi_buffer_snapshot);
 7381            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7382                multi_buffer_visible_start
 7383                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7384                Bias::Left,
 7385            );
 7386            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7387            self.quick_selection_highlight_task = Some((
 7388                query_range.clone(),
 7389                self.update_selection_occurrence_highlights(
 7390                    query_text.clone(),
 7391                    query_range.clone(),
 7392                    multi_buffer_visible_range,
 7393                    false,
 7394                    window,
 7395                    cx,
 7396                ),
 7397            ));
 7398        }
 7399        if on_buffer_edit
 7400            || self
 7401                .debounced_selection_highlight_task
 7402                .as_ref()
 7403                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7404        {
 7405            let multi_buffer_start = multi_buffer_snapshot
 7406                .anchor_before(MultiBufferOffset(0))
 7407                .to_point(&multi_buffer_snapshot);
 7408            let multi_buffer_end = multi_buffer_snapshot
 7409                .anchor_after(multi_buffer_snapshot.len())
 7410                .to_point(&multi_buffer_snapshot);
 7411            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7412            self.debounced_selection_highlight_task = Some((
 7413                query_range.clone(),
 7414                self.update_selection_occurrence_highlights(
 7415                    query_text,
 7416                    query_range,
 7417                    multi_buffer_full_range,
 7418                    true,
 7419                    window,
 7420                    cx,
 7421                ),
 7422            ));
 7423        }
 7424    }
 7425
 7426    pub fn refresh_edit_prediction(
 7427        &mut self,
 7428        debounce: bool,
 7429        user_requested: bool,
 7430        window: &mut Window,
 7431        cx: &mut Context<Self>,
 7432    ) -> Option<()> {
 7433        if DisableAiSettings::get_global(cx).disable_ai {
 7434            return None;
 7435        }
 7436
 7437        let provider = self.edit_prediction_provider()?;
 7438        let cursor = self.selections.newest_anchor().head();
 7439        let (buffer, cursor_buffer_position) =
 7440            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7441
 7442        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7443            self.discard_edit_prediction(false, cx);
 7444            return None;
 7445        }
 7446
 7447        self.update_visible_edit_prediction(window, cx);
 7448
 7449        if !user_requested
 7450            && (!self.should_show_edit_predictions()
 7451                || !self.is_focused(window)
 7452                || buffer.read(cx).is_empty())
 7453        {
 7454            self.discard_edit_prediction(false, cx);
 7455            return None;
 7456        }
 7457
 7458        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7459        Some(())
 7460    }
 7461
 7462    fn show_edit_predictions_in_menu(&self) -> bool {
 7463        match self.edit_prediction_settings {
 7464            EditPredictionSettings::Disabled => false,
 7465            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7466        }
 7467    }
 7468
 7469    pub fn edit_predictions_enabled(&self) -> bool {
 7470        match self.edit_prediction_settings {
 7471            EditPredictionSettings::Disabled => false,
 7472            EditPredictionSettings::Enabled { .. } => true,
 7473        }
 7474    }
 7475
 7476    fn edit_prediction_requires_modifier(&self) -> bool {
 7477        match self.edit_prediction_settings {
 7478            EditPredictionSettings::Disabled => false,
 7479            EditPredictionSettings::Enabled {
 7480                preview_requires_modifier,
 7481                ..
 7482            } => preview_requires_modifier,
 7483        }
 7484    }
 7485
 7486    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7487        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7488            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7489            self.discard_edit_prediction(false, cx);
 7490        } else {
 7491            let selection = self.selections.newest_anchor();
 7492            let cursor = selection.head();
 7493
 7494            if let Some((buffer, cursor_buffer_position)) =
 7495                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7496            {
 7497                self.edit_prediction_settings =
 7498                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7499            }
 7500        }
 7501    }
 7502
 7503    fn edit_prediction_settings_at_position(
 7504        &self,
 7505        buffer: &Entity<Buffer>,
 7506        buffer_position: language::Anchor,
 7507        cx: &App,
 7508    ) -> EditPredictionSettings {
 7509        if !self.mode.is_full()
 7510            || !self.show_edit_predictions_override.unwrap_or(true)
 7511            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7512        {
 7513            return EditPredictionSettings::Disabled;
 7514        }
 7515
 7516        let buffer = buffer.read(cx);
 7517
 7518        let file = buffer.file();
 7519
 7520        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7521            return EditPredictionSettings::Disabled;
 7522        };
 7523
 7524        let by_provider = matches!(
 7525            self.menu_edit_predictions_policy,
 7526            MenuEditPredictionsPolicy::ByProvider
 7527        );
 7528
 7529        let show_in_menu = by_provider
 7530            && self
 7531                .edit_prediction_provider
 7532                .as_ref()
 7533                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7534
 7535        let preview_requires_modifier =
 7536            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7537
 7538        EditPredictionSettings::Enabled {
 7539            show_in_menu,
 7540            preview_requires_modifier,
 7541        }
 7542    }
 7543
 7544    fn should_show_edit_predictions(&self) -> bool {
 7545        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7546    }
 7547
 7548    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7549        matches!(
 7550            self.edit_prediction_preview,
 7551            EditPredictionPreview::Active { .. }
 7552        )
 7553    }
 7554
 7555    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7556        let cursor = self.selections.newest_anchor().head();
 7557        if let Some((buffer, cursor_position)) =
 7558            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7559        {
 7560            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7561        } else {
 7562            false
 7563        }
 7564    }
 7565
 7566    pub fn supports_minimap(&self, cx: &App) -> bool {
 7567        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7568    }
 7569
 7570    fn edit_predictions_enabled_in_buffer(
 7571        &self,
 7572        buffer: &Entity<Buffer>,
 7573        buffer_position: language::Anchor,
 7574        cx: &App,
 7575    ) -> bool {
 7576        maybe!({
 7577            if self.read_only(cx) {
 7578                return Some(false);
 7579            }
 7580            let provider = self.edit_prediction_provider()?;
 7581            if !provider.is_enabled(buffer, buffer_position, cx) {
 7582                return Some(false);
 7583            }
 7584            let buffer = buffer.read(cx);
 7585            let Some(file) = buffer.file() else {
 7586                return Some(true);
 7587            };
 7588            let settings = all_language_settings(Some(file), cx);
 7589            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7590        })
 7591        .unwrap_or(false)
 7592    }
 7593
 7594    pub fn show_edit_prediction(
 7595        &mut self,
 7596        _: &ShowEditPrediction,
 7597        window: &mut Window,
 7598        cx: &mut Context<Self>,
 7599    ) {
 7600        if !self.has_active_edit_prediction() {
 7601            self.refresh_edit_prediction(false, true, window, cx);
 7602            return;
 7603        }
 7604
 7605        self.update_visible_edit_prediction(window, cx);
 7606    }
 7607
 7608    pub fn display_cursor_names(
 7609        &mut self,
 7610        _: &DisplayCursorNames,
 7611        window: &mut Window,
 7612        cx: &mut Context<Self>,
 7613    ) {
 7614        self.show_cursor_names(window, cx);
 7615    }
 7616
 7617    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7618        self.show_cursor_names = true;
 7619        cx.notify();
 7620        cx.spawn_in(window, async move |this, cx| {
 7621            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7622            this.update(cx, |this, cx| {
 7623                this.show_cursor_names = false;
 7624                cx.notify()
 7625            })
 7626            .ok()
 7627        })
 7628        .detach();
 7629    }
 7630
 7631    pub fn accept_partial_edit_prediction(
 7632        &mut self,
 7633        granularity: EditPredictionGranularity,
 7634        window: &mut Window,
 7635        cx: &mut Context<Self>,
 7636    ) {
 7637        if self.show_edit_predictions_in_menu() {
 7638            self.hide_context_menu(window, cx);
 7639        }
 7640
 7641        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7642            return;
 7643        };
 7644
 7645        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7646            return;
 7647        }
 7648
 7649        match &active_edit_prediction.completion {
 7650            EditPrediction::MoveWithin { target, .. } => {
 7651                let target = *target;
 7652
 7653                if matches!(granularity, EditPredictionGranularity::Full) {
 7654                    if let Some(position_map) = &self.last_position_map {
 7655                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7656                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7657
 7658                        if is_visible || !self.edit_prediction_requires_modifier() {
 7659                            self.unfold_ranges(&[target..target], true, false, cx);
 7660                            self.change_selections(
 7661                                SelectionEffects::scroll(Autoscroll::newest()),
 7662                                window,
 7663                                cx,
 7664                                |selections| {
 7665                                    selections.select_anchor_ranges([target..target]);
 7666                                },
 7667                            );
 7668                            self.clear_row_highlights::<EditPredictionPreview>();
 7669                            self.edit_prediction_preview
 7670                                .set_previous_scroll_position(None);
 7671                        } else {
 7672                            // Highlight and request scroll
 7673                            self.edit_prediction_preview
 7674                                .set_previous_scroll_position(Some(
 7675                                    position_map.snapshot.scroll_anchor,
 7676                                ));
 7677                            self.highlight_rows::<EditPredictionPreview>(
 7678                                target..target,
 7679                                cx.theme().colors().editor_highlighted_line_background,
 7680                                RowHighlightOptions {
 7681                                    autoscroll: true,
 7682                                    ..Default::default()
 7683                                },
 7684                                cx,
 7685                            );
 7686                            self.request_autoscroll(Autoscroll::fit(), cx);
 7687                        }
 7688                    }
 7689                } else {
 7690                    self.change_selections(
 7691                        SelectionEffects::scroll(Autoscroll::newest()),
 7692                        window,
 7693                        cx,
 7694                        |selections| {
 7695                            selections.select_anchor_ranges([target..target]);
 7696                        },
 7697                    );
 7698                }
 7699            }
 7700            EditPrediction::MoveOutside { snapshot, target } => {
 7701                if let Some(workspace) = self.workspace() {
 7702                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7703                        .detach_and_log_err(cx);
 7704                }
 7705            }
 7706            EditPrediction::Edit { edits, .. } => {
 7707                self.report_edit_prediction_event(
 7708                    active_edit_prediction.completion_id.clone(),
 7709                    true,
 7710                    cx,
 7711                );
 7712
 7713                match granularity {
 7714                    EditPredictionGranularity::Full => {
 7715                        if let Some(provider) = self.edit_prediction_provider() {
 7716                            provider.accept(cx);
 7717                        }
 7718
 7719                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7720                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7721                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7722
 7723                        self.buffer.update(cx, |buffer, cx| {
 7724                            buffer.edit(edits.iter().cloned(), None, cx)
 7725                        });
 7726
 7727                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7728                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7729                        });
 7730
 7731                        let selections = self.selections.disjoint_anchors_arc();
 7732                        if let Some(transaction_id_now) =
 7733                            self.buffer.read(cx).last_transaction_id(cx)
 7734                        {
 7735                            if transaction_id_prev != Some(transaction_id_now) {
 7736                                self.selection_history
 7737                                    .insert_transaction(transaction_id_now, selections);
 7738                            }
 7739                        }
 7740
 7741                        self.update_visible_edit_prediction(window, cx);
 7742                        if self.active_edit_prediction.is_none() {
 7743                            self.refresh_edit_prediction(true, true, window, cx);
 7744                        }
 7745                        cx.notify();
 7746                    }
 7747                    _ => {
 7748                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7749                        let cursor_offset = self
 7750                            .selections
 7751                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7752                            .head();
 7753
 7754                        let insertion = edits.iter().find_map(|(range, text)| {
 7755                            let range = range.to_offset(&snapshot);
 7756                            if range.is_empty() && range.start == cursor_offset {
 7757                                Some(text)
 7758                            } else {
 7759                                None
 7760                            }
 7761                        });
 7762
 7763                        if let Some(text) = insertion {
 7764                            let text_to_insert = match granularity {
 7765                                EditPredictionGranularity::Word => {
 7766                                    let mut partial = text
 7767                                        .chars()
 7768                                        .by_ref()
 7769                                        .take_while(|c| c.is_alphabetic())
 7770                                        .collect::<String>();
 7771                                    if partial.is_empty() {
 7772                                        partial = text
 7773                                            .chars()
 7774                                            .by_ref()
 7775                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7776                                            .collect::<String>();
 7777                                    }
 7778                                    partial
 7779                                }
 7780                                EditPredictionGranularity::Line => {
 7781                                    if let Some(line) = text.split_inclusive('\n').next() {
 7782                                        line.to_string()
 7783                                    } else {
 7784                                        text.to_string()
 7785                                    }
 7786                                }
 7787                                EditPredictionGranularity::Full => unreachable!(),
 7788                            };
 7789
 7790                            cx.emit(EditorEvent::InputHandled {
 7791                                utf16_range_to_replace: None,
 7792                                text: text_to_insert.clone().into(),
 7793                            });
 7794
 7795                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7796                            self.refresh_edit_prediction(true, true, window, cx);
 7797                            cx.notify();
 7798                        } else {
 7799                            self.accept_partial_edit_prediction(
 7800                                EditPredictionGranularity::Full,
 7801                                window,
 7802                                cx,
 7803                            );
 7804                        }
 7805                    }
 7806                }
 7807            }
 7808        }
 7809
 7810        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7811    }
 7812
 7813    pub fn accept_next_word_edit_prediction(
 7814        &mut self,
 7815        _: &AcceptNextWordEditPrediction,
 7816        window: &mut Window,
 7817        cx: &mut Context<Self>,
 7818    ) {
 7819        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7820    }
 7821
 7822    pub fn accept_next_line_edit_prediction(
 7823        &mut self,
 7824        _: &AcceptNextLineEditPrediction,
 7825        window: &mut Window,
 7826        cx: &mut Context<Self>,
 7827    ) {
 7828        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7829    }
 7830
 7831    pub fn accept_edit_prediction(
 7832        &mut self,
 7833        _: &AcceptEditPrediction,
 7834        window: &mut Window,
 7835        cx: &mut Context<Self>,
 7836    ) {
 7837        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7838    }
 7839
 7840    fn discard_edit_prediction(
 7841        &mut self,
 7842        should_report_edit_prediction_event: bool,
 7843        cx: &mut Context<Self>,
 7844    ) -> bool {
 7845        if should_report_edit_prediction_event {
 7846            let completion_id = self
 7847                .active_edit_prediction
 7848                .as_ref()
 7849                .and_then(|active_completion| active_completion.completion_id.clone());
 7850
 7851            self.report_edit_prediction_event(completion_id, false, cx);
 7852        }
 7853
 7854        if let Some(provider) = self.edit_prediction_provider() {
 7855            provider.discard(cx);
 7856        }
 7857
 7858        self.take_active_edit_prediction(cx)
 7859    }
 7860
 7861    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7862        let Some(provider) = self.edit_prediction_provider() else {
 7863            return;
 7864        };
 7865
 7866        let Some((_, buffer, _)) = self
 7867            .buffer
 7868            .read(cx)
 7869            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7870        else {
 7871            return;
 7872        };
 7873
 7874        let extension = buffer
 7875            .read(cx)
 7876            .file()
 7877            .and_then(|file| Some(file.path().extension()?.to_string()));
 7878
 7879        let event_type = match accepted {
 7880            true => "Edit Prediction Accepted",
 7881            false => "Edit Prediction Discarded",
 7882        };
 7883        telemetry::event!(
 7884            event_type,
 7885            provider = provider.name(),
 7886            prediction_id = id,
 7887            suggestion_accepted = accepted,
 7888            file_extension = extension,
 7889        );
 7890    }
 7891
 7892    fn open_editor_at_anchor(
 7893        snapshot: &language::BufferSnapshot,
 7894        target: language::Anchor,
 7895        workspace: &Entity<Workspace>,
 7896        window: &mut Window,
 7897        cx: &mut App,
 7898    ) -> Task<Result<()>> {
 7899        workspace.update(cx, |workspace, cx| {
 7900            let path = snapshot.file().map(|file| file.full_path(cx));
 7901            let Some(path) =
 7902                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7903            else {
 7904                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7905            };
 7906            let target = text::ToPoint::to_point(&target, snapshot);
 7907            let item = workspace.open_path(path, None, true, window, cx);
 7908            window.spawn(cx, async move |cx| {
 7909                let Some(editor) = item.await?.downcast::<Editor>() else {
 7910                    return Ok(());
 7911                };
 7912                editor
 7913                    .update_in(cx, |editor, window, cx| {
 7914                        editor.go_to_singleton_buffer_point(target, window, cx);
 7915                    })
 7916                    .ok();
 7917                anyhow::Ok(())
 7918            })
 7919        })
 7920    }
 7921
 7922    pub fn has_active_edit_prediction(&self) -> bool {
 7923        self.active_edit_prediction.is_some()
 7924    }
 7925
 7926    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7927        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7928            return false;
 7929        };
 7930
 7931        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7932        self.clear_highlights::<EditPredictionHighlight>(cx);
 7933        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7934        true
 7935    }
 7936
 7937    /// Returns true when we're displaying the edit prediction popover below the cursor
 7938    /// like we are not previewing and the LSP autocomplete menu is visible
 7939    /// or we are in `when_holding_modifier` mode.
 7940    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7941        if self.edit_prediction_preview_is_active()
 7942            || !self.show_edit_predictions_in_menu()
 7943            || !self.edit_predictions_enabled()
 7944        {
 7945            return false;
 7946        }
 7947
 7948        if self.has_visible_completions_menu() {
 7949            return true;
 7950        }
 7951
 7952        has_completion && self.edit_prediction_requires_modifier()
 7953    }
 7954
 7955    fn handle_modifiers_changed(
 7956        &mut self,
 7957        modifiers: Modifiers,
 7958        position_map: &PositionMap,
 7959        window: &mut Window,
 7960        cx: &mut Context<Self>,
 7961    ) {
 7962        // Ensure that the edit prediction preview is updated, even when not
 7963        // enabled, if there's an active edit prediction preview.
 7964        if self.show_edit_predictions_in_menu()
 7965            || matches!(
 7966                self.edit_prediction_preview,
 7967                EditPredictionPreview::Active { .. }
 7968            )
 7969        {
 7970            self.update_edit_prediction_preview(&modifiers, window, cx);
 7971        }
 7972
 7973        self.update_selection_mode(&modifiers, position_map, window, cx);
 7974
 7975        let mouse_position = window.mouse_position();
 7976        if !position_map.text_hitbox.is_hovered(window) {
 7977            return;
 7978        }
 7979
 7980        self.update_hovered_link(
 7981            position_map.point_for_position(mouse_position),
 7982            &position_map.snapshot,
 7983            modifiers,
 7984            window,
 7985            cx,
 7986        )
 7987    }
 7988
 7989    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7990        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7991            MultiCursorModifier::Alt => modifiers.secondary(),
 7992            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7993        }
 7994    }
 7995
 7996    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7997        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7998            MultiCursorModifier::Alt => modifiers.alt,
 7999            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8000        }
 8001    }
 8002
 8003    fn columnar_selection_mode(
 8004        modifiers: &Modifiers,
 8005        cx: &mut Context<Self>,
 8006    ) -> Option<ColumnarMode> {
 8007        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8008            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8009                Some(ColumnarMode::FromMouse)
 8010            } else if Self::is_alt_pressed(modifiers, cx) {
 8011                Some(ColumnarMode::FromSelection)
 8012            } else {
 8013                None
 8014            }
 8015        } else {
 8016            None
 8017        }
 8018    }
 8019
 8020    fn update_selection_mode(
 8021        &mut self,
 8022        modifiers: &Modifiers,
 8023        position_map: &PositionMap,
 8024        window: &mut Window,
 8025        cx: &mut Context<Self>,
 8026    ) {
 8027        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8028            return;
 8029        };
 8030        if self.selections.pending_anchor().is_none() {
 8031            return;
 8032        }
 8033
 8034        let mouse_position = window.mouse_position();
 8035        let point_for_position = position_map.point_for_position(mouse_position);
 8036        let position = point_for_position.previous_valid;
 8037
 8038        self.select(
 8039            SelectPhase::BeginColumnar {
 8040                position,
 8041                reset: false,
 8042                mode,
 8043                goal_column: point_for_position.exact_unclipped.column(),
 8044            },
 8045            window,
 8046            cx,
 8047        );
 8048    }
 8049
 8050    fn update_edit_prediction_preview(
 8051        &mut self,
 8052        modifiers: &Modifiers,
 8053        window: &mut Window,
 8054        cx: &mut Context<Self>,
 8055    ) {
 8056        let mut modifiers_held = false;
 8057
 8058        // Check bindings for all granularities.
 8059        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8060        let granularities = [
 8061            EditPredictionGranularity::Full,
 8062            EditPredictionGranularity::Line,
 8063            EditPredictionGranularity::Word,
 8064        ];
 8065
 8066        for granularity in granularities {
 8067            if let Some(keystroke) = self
 8068                .accept_edit_prediction_keybind(granularity, window, cx)
 8069                .keystroke()
 8070            {
 8071                modifiers_held = modifiers_held
 8072                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8073            }
 8074        }
 8075
 8076        if modifiers_held {
 8077            if matches!(
 8078                self.edit_prediction_preview,
 8079                EditPredictionPreview::Inactive { .. }
 8080            ) {
 8081                self.edit_prediction_preview = EditPredictionPreview::Active {
 8082                    previous_scroll_position: None,
 8083                    since: Instant::now(),
 8084                };
 8085
 8086                self.update_visible_edit_prediction(window, cx);
 8087                cx.notify();
 8088            }
 8089        } else if let EditPredictionPreview::Active {
 8090            previous_scroll_position,
 8091            since,
 8092        } = self.edit_prediction_preview
 8093        {
 8094            if let (Some(previous_scroll_position), Some(position_map)) =
 8095                (previous_scroll_position, self.last_position_map.as_ref())
 8096            {
 8097                self.set_scroll_position(
 8098                    previous_scroll_position
 8099                        .scroll_position(&position_map.snapshot.display_snapshot),
 8100                    window,
 8101                    cx,
 8102                );
 8103            }
 8104
 8105            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8106                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8107            };
 8108            self.clear_row_highlights::<EditPredictionPreview>();
 8109            self.update_visible_edit_prediction(window, cx);
 8110            cx.notify();
 8111        }
 8112    }
 8113
 8114    fn update_visible_edit_prediction(
 8115        &mut self,
 8116        _window: &mut Window,
 8117        cx: &mut Context<Self>,
 8118    ) -> Option<()> {
 8119        if DisableAiSettings::get_global(cx).disable_ai {
 8120            return None;
 8121        }
 8122
 8123        if self.ime_transaction.is_some() {
 8124            self.discard_edit_prediction(false, cx);
 8125            return None;
 8126        }
 8127
 8128        let selection = self.selections.newest_anchor();
 8129        let cursor = selection.head();
 8130        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8131        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8132        let excerpt_id = cursor.excerpt_id;
 8133
 8134        let show_in_menu = self.show_edit_predictions_in_menu();
 8135        let completions_menu_has_precedence = !show_in_menu
 8136            && (self.context_menu.borrow().is_some()
 8137                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8138
 8139        if completions_menu_has_precedence
 8140            || !offset_selection.is_empty()
 8141            || self
 8142                .active_edit_prediction
 8143                .as_ref()
 8144                .is_some_and(|completion| {
 8145                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8146                        return false;
 8147                    };
 8148                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8149                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8150                    !invalidation_range.contains(&offset_selection.head())
 8151                })
 8152        {
 8153            self.discard_edit_prediction(false, cx);
 8154            return None;
 8155        }
 8156
 8157        self.take_active_edit_prediction(cx);
 8158        let Some(provider) = self.edit_prediction_provider() else {
 8159            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8160            return None;
 8161        };
 8162
 8163        let (buffer, cursor_buffer_position) =
 8164            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8165
 8166        self.edit_prediction_settings =
 8167            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8168
 8169        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8170
 8171        if self.edit_prediction_indent_conflict {
 8172            let cursor_point = cursor.to_point(&multibuffer);
 8173            let mut suggested_indent = None;
 8174            multibuffer.suggested_indents_callback(
 8175                cursor_point.row..cursor_point.row + 1,
 8176                |_, indent| {
 8177                    suggested_indent = Some(indent);
 8178                    ControlFlow::Break(())
 8179                },
 8180                cx,
 8181            );
 8182
 8183            if let Some(indent) = suggested_indent
 8184                && indent.len == cursor_point.column
 8185            {
 8186                self.edit_prediction_indent_conflict = false;
 8187            }
 8188        }
 8189
 8190        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8191
 8192        let (completion_id, edits, edit_preview) = match edit_prediction {
 8193            edit_prediction_types::EditPrediction::Local {
 8194                id,
 8195                edits,
 8196                edit_preview,
 8197            } => (id, edits, edit_preview),
 8198            edit_prediction_types::EditPrediction::Jump {
 8199                id,
 8200                snapshot,
 8201                target,
 8202            } => {
 8203                if let Some(provider) = &self.edit_prediction_provider {
 8204                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8205                }
 8206                self.stale_edit_prediction_in_menu = None;
 8207                self.active_edit_prediction = Some(EditPredictionState {
 8208                    inlay_ids: vec![],
 8209                    completion: EditPrediction::MoveOutside { snapshot, target },
 8210                    completion_id: id,
 8211                    invalidation_range: None,
 8212                });
 8213                cx.notify();
 8214                return Some(());
 8215            }
 8216        };
 8217
 8218        let edits = edits
 8219            .into_iter()
 8220            .flat_map(|(range, new_text)| {
 8221                Some((
 8222                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8223                    new_text,
 8224                ))
 8225            })
 8226            .collect::<Vec<_>>();
 8227        if edits.is_empty() {
 8228            return None;
 8229        }
 8230
 8231        let first_edit_start = edits.first().unwrap().0.start;
 8232        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8233        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8234
 8235        let last_edit_end = edits.last().unwrap().0.end;
 8236        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8237        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8238
 8239        let cursor_row = cursor.to_point(&multibuffer).row;
 8240
 8241        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8242
 8243        let mut inlay_ids = Vec::new();
 8244        let invalidation_row_range;
 8245        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8246            Some(cursor_row..edit_end_row)
 8247        } else if cursor_row > edit_end_row {
 8248            Some(edit_start_row..cursor_row)
 8249        } else {
 8250            None
 8251        };
 8252        let supports_jump = self
 8253            .edit_prediction_provider
 8254            .as_ref()
 8255            .map(|provider| provider.provider.supports_jump_to_edit())
 8256            .unwrap_or(true);
 8257
 8258        let is_move = supports_jump
 8259            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8260        let completion = if is_move {
 8261            if let Some(provider) = &self.edit_prediction_provider {
 8262                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8263            }
 8264            invalidation_row_range =
 8265                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8266            let target = first_edit_start;
 8267            EditPrediction::MoveWithin { target, snapshot }
 8268        } else {
 8269            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8270                && !self.edit_predictions_hidden_for_vim_mode;
 8271
 8272            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8273                if provider.show_tab_accept_marker() {
 8274                    EditDisplayMode::TabAccept
 8275                } else {
 8276                    EditDisplayMode::Inline
 8277                }
 8278            } else {
 8279                EditDisplayMode::DiffPopover
 8280            };
 8281
 8282            if show_completions_in_buffer {
 8283                if let Some(provider) = &self.edit_prediction_provider {
 8284                    let suggestion_display_type = match display_mode {
 8285                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8286                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8287                            SuggestionDisplayType::GhostText
 8288                        }
 8289                    };
 8290                    provider.provider.did_show(suggestion_display_type, cx);
 8291                }
 8292                if edits
 8293                    .iter()
 8294                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8295                {
 8296                    let mut inlays = Vec::new();
 8297                    for (range, new_text) in &edits {
 8298                        let inlay = Inlay::edit_prediction(
 8299                            post_inc(&mut self.next_inlay_id),
 8300                            range.start,
 8301                            new_text.as_ref(),
 8302                        );
 8303                        inlay_ids.push(inlay.id);
 8304                        inlays.push(inlay);
 8305                    }
 8306
 8307                    self.splice_inlays(&[], inlays, cx);
 8308                } else {
 8309                    let background_color = cx.theme().status().deleted_background;
 8310                    self.highlight_text::<EditPredictionHighlight>(
 8311                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8312                        HighlightStyle {
 8313                            background_color: Some(background_color),
 8314                            ..Default::default()
 8315                        },
 8316                        cx,
 8317                    );
 8318                }
 8319            }
 8320
 8321            invalidation_row_range = edit_start_row..edit_end_row;
 8322
 8323            EditPrediction::Edit {
 8324                edits,
 8325                edit_preview,
 8326                display_mode,
 8327                snapshot,
 8328            }
 8329        };
 8330
 8331        let invalidation_range = multibuffer
 8332            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8333            ..multibuffer.anchor_after(Point::new(
 8334                invalidation_row_range.end,
 8335                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8336            ));
 8337
 8338        self.stale_edit_prediction_in_menu = None;
 8339        self.active_edit_prediction = Some(EditPredictionState {
 8340            inlay_ids,
 8341            completion,
 8342            completion_id,
 8343            invalidation_range: Some(invalidation_range),
 8344        });
 8345
 8346        cx.notify();
 8347
 8348        Some(())
 8349    }
 8350
 8351    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8352        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8353    }
 8354
 8355    fn clear_tasks(&mut self) {
 8356        self.tasks.clear()
 8357    }
 8358
 8359    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8360        if self.tasks.insert(key, value).is_some() {
 8361            // This case should hopefully be rare, but just in case...
 8362            log::error!(
 8363                "multiple different run targets found on a single line, only the last target will be rendered"
 8364            )
 8365        }
 8366    }
 8367
 8368    /// Get all display points of breakpoints that will be rendered within editor
 8369    ///
 8370    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8371    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8372    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8373    fn active_breakpoints(
 8374        &self,
 8375        range: Range<DisplayRow>,
 8376        window: &mut Window,
 8377        cx: &mut Context<Self>,
 8378    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8379        let mut breakpoint_display_points = HashMap::default();
 8380
 8381        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8382            return breakpoint_display_points;
 8383        };
 8384
 8385        let snapshot = self.snapshot(window, cx);
 8386
 8387        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8388        let Some(project) = self.project() else {
 8389            return breakpoint_display_points;
 8390        };
 8391
 8392        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8393            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8394
 8395        for (buffer_snapshot, range, excerpt_id) in
 8396            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8397        {
 8398            let Some(buffer) = project
 8399                .read(cx)
 8400                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8401            else {
 8402                continue;
 8403            };
 8404            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8405                &buffer,
 8406                Some(
 8407                    buffer_snapshot.anchor_before(range.start)
 8408                        ..buffer_snapshot.anchor_after(range.end),
 8409                ),
 8410                buffer_snapshot,
 8411                cx,
 8412            );
 8413            for (breakpoint, state) in breakpoints {
 8414                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8415                let position = multi_buffer_anchor
 8416                    .to_point(&multi_buffer_snapshot)
 8417                    .to_display_point(&snapshot);
 8418
 8419                breakpoint_display_points.insert(
 8420                    position.row(),
 8421                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8422                );
 8423            }
 8424        }
 8425
 8426        breakpoint_display_points
 8427    }
 8428
 8429    fn breakpoint_context_menu(
 8430        &self,
 8431        anchor: Anchor,
 8432        window: &mut Window,
 8433        cx: &mut Context<Self>,
 8434    ) -> Entity<ui::ContextMenu> {
 8435        let weak_editor = cx.weak_entity();
 8436        let focus_handle = self.focus_handle(cx);
 8437
 8438        let row = self
 8439            .buffer
 8440            .read(cx)
 8441            .snapshot(cx)
 8442            .summary_for_anchor::<Point>(&anchor)
 8443            .row;
 8444
 8445        let breakpoint = self
 8446            .breakpoint_at_row(row, window, cx)
 8447            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8448
 8449        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8450            "Edit Log Breakpoint"
 8451        } else {
 8452            "Set Log Breakpoint"
 8453        };
 8454
 8455        let condition_breakpoint_msg = if breakpoint
 8456            .as_ref()
 8457            .is_some_and(|bp| bp.1.condition.is_some())
 8458        {
 8459            "Edit Condition Breakpoint"
 8460        } else {
 8461            "Set Condition Breakpoint"
 8462        };
 8463
 8464        let hit_condition_breakpoint_msg = if breakpoint
 8465            .as_ref()
 8466            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8467        {
 8468            "Edit Hit Condition Breakpoint"
 8469        } else {
 8470            "Set Hit Condition Breakpoint"
 8471        };
 8472
 8473        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8474            "Unset Breakpoint"
 8475        } else {
 8476            "Set Breakpoint"
 8477        };
 8478
 8479        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8480
 8481        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8482            BreakpointState::Enabled => Some("Disable"),
 8483            BreakpointState::Disabled => Some("Enable"),
 8484        });
 8485
 8486        let (anchor, breakpoint) =
 8487            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8488
 8489        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8490            menu.on_blur_subscription(Subscription::new(|| {}))
 8491                .context(focus_handle)
 8492                .when(run_to_cursor, |this| {
 8493                    let weak_editor = weak_editor.clone();
 8494                    this.entry("Run to cursor", None, move |window, cx| {
 8495                        weak_editor
 8496                            .update(cx, |editor, cx| {
 8497                                editor.change_selections(
 8498                                    SelectionEffects::no_scroll(),
 8499                                    window,
 8500                                    cx,
 8501                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8502                                );
 8503                            })
 8504                            .ok();
 8505
 8506                        window.dispatch_action(Box::new(RunToCursor), cx);
 8507                    })
 8508                    .separator()
 8509                })
 8510                .when_some(toggle_state_msg, |this, msg| {
 8511                    this.entry(msg, None, {
 8512                        let weak_editor = weak_editor.clone();
 8513                        let breakpoint = breakpoint.clone();
 8514                        move |_window, cx| {
 8515                            weak_editor
 8516                                .update(cx, |this, cx| {
 8517                                    this.edit_breakpoint_at_anchor(
 8518                                        anchor,
 8519                                        breakpoint.as_ref().clone(),
 8520                                        BreakpointEditAction::InvertState,
 8521                                        cx,
 8522                                    );
 8523                                })
 8524                                .log_err();
 8525                        }
 8526                    })
 8527                })
 8528                .entry(set_breakpoint_msg, None, {
 8529                    let weak_editor = weak_editor.clone();
 8530                    let breakpoint = breakpoint.clone();
 8531                    move |_window, cx| {
 8532                        weak_editor
 8533                            .update(cx, |this, cx| {
 8534                                this.edit_breakpoint_at_anchor(
 8535                                    anchor,
 8536                                    breakpoint.as_ref().clone(),
 8537                                    BreakpointEditAction::Toggle,
 8538                                    cx,
 8539                                );
 8540                            })
 8541                            .log_err();
 8542                    }
 8543                })
 8544                .entry(log_breakpoint_msg, None, {
 8545                    let breakpoint = breakpoint.clone();
 8546                    let weak_editor = weak_editor.clone();
 8547                    move |window, cx| {
 8548                        weak_editor
 8549                            .update(cx, |this, cx| {
 8550                                this.add_edit_breakpoint_block(
 8551                                    anchor,
 8552                                    breakpoint.as_ref(),
 8553                                    BreakpointPromptEditAction::Log,
 8554                                    window,
 8555                                    cx,
 8556                                );
 8557                            })
 8558                            .log_err();
 8559                    }
 8560                })
 8561                .entry(condition_breakpoint_msg, None, {
 8562                    let breakpoint = breakpoint.clone();
 8563                    let weak_editor = weak_editor.clone();
 8564                    move |window, cx| {
 8565                        weak_editor
 8566                            .update(cx, |this, cx| {
 8567                                this.add_edit_breakpoint_block(
 8568                                    anchor,
 8569                                    breakpoint.as_ref(),
 8570                                    BreakpointPromptEditAction::Condition,
 8571                                    window,
 8572                                    cx,
 8573                                );
 8574                            })
 8575                            .log_err();
 8576                    }
 8577                })
 8578                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8579                    weak_editor
 8580                        .update(cx, |this, cx| {
 8581                            this.add_edit_breakpoint_block(
 8582                                anchor,
 8583                                breakpoint.as_ref(),
 8584                                BreakpointPromptEditAction::HitCondition,
 8585                                window,
 8586                                cx,
 8587                            );
 8588                        })
 8589                        .log_err();
 8590                })
 8591        })
 8592    }
 8593
 8594    fn render_breakpoint(
 8595        &self,
 8596        position: Anchor,
 8597        row: DisplayRow,
 8598        breakpoint: &Breakpoint,
 8599        state: Option<BreakpointSessionState>,
 8600        cx: &mut Context<Self>,
 8601    ) -> IconButton {
 8602        let is_rejected = state.is_some_and(|s| !s.verified);
 8603        // Is it a breakpoint that shows up when hovering over gutter?
 8604        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8605            (false, false),
 8606            |PhantomBreakpointIndicator {
 8607                 is_active,
 8608                 display_row,
 8609                 collides_with_existing_breakpoint,
 8610             }| {
 8611                (
 8612                    is_active && display_row == row,
 8613                    collides_with_existing_breakpoint,
 8614                )
 8615            },
 8616        );
 8617
 8618        let (color, icon) = {
 8619            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8620                (false, false) => ui::IconName::DebugBreakpoint,
 8621                (true, false) => ui::IconName::DebugLogBreakpoint,
 8622                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8623                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8624            };
 8625
 8626            let color = cx.theme().colors();
 8627
 8628            let color = if is_phantom {
 8629                if collides_with_existing {
 8630                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8631                } else {
 8632                    Color::Hint
 8633                }
 8634            } else if is_rejected {
 8635                Color::Disabled
 8636            } else {
 8637                Color::Debugger
 8638            };
 8639
 8640            (color, icon)
 8641        };
 8642
 8643        let breakpoint = Arc::from(breakpoint.clone());
 8644
 8645        let alt_as_text = gpui::Keystroke {
 8646            modifiers: Modifiers::secondary_key(),
 8647            ..Default::default()
 8648        };
 8649        let primary_action_text = if breakpoint.is_disabled() {
 8650            "Enable breakpoint"
 8651        } else if is_phantom && !collides_with_existing {
 8652            "Set breakpoint"
 8653        } else {
 8654            "Unset breakpoint"
 8655        };
 8656        let focus_handle = self.focus_handle.clone();
 8657
 8658        let meta = if is_rejected {
 8659            SharedString::from("No executable code is associated with this line.")
 8660        } else if collides_with_existing && !breakpoint.is_disabled() {
 8661            SharedString::from(format!(
 8662                "{alt_as_text}-click to disable,\nright-click for more options."
 8663            ))
 8664        } else {
 8665            SharedString::from("Right-click for more options.")
 8666        };
 8667        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8668            .icon_size(IconSize::XSmall)
 8669            .size(ui::ButtonSize::None)
 8670            .when(is_rejected, |this| {
 8671                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8672            })
 8673            .icon_color(color)
 8674            .style(ButtonStyle::Transparent)
 8675            .on_click(cx.listener({
 8676                move |editor, event: &ClickEvent, window, cx| {
 8677                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8678                        BreakpointEditAction::InvertState
 8679                    } else {
 8680                        BreakpointEditAction::Toggle
 8681                    };
 8682
 8683                    window.focus(&editor.focus_handle(cx), cx);
 8684                    editor.edit_breakpoint_at_anchor(
 8685                        position,
 8686                        breakpoint.as_ref().clone(),
 8687                        edit_action,
 8688                        cx,
 8689                    );
 8690                }
 8691            }))
 8692            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8693                editor.set_breakpoint_context_menu(
 8694                    row,
 8695                    Some(position),
 8696                    event.position(),
 8697                    window,
 8698                    cx,
 8699                );
 8700            }))
 8701            .tooltip(move |_window, cx| {
 8702                Tooltip::with_meta_in(
 8703                    primary_action_text,
 8704                    Some(&ToggleBreakpoint),
 8705                    meta.clone(),
 8706                    &focus_handle,
 8707                    cx,
 8708                )
 8709            })
 8710    }
 8711
 8712    fn build_tasks_context(
 8713        project: &Entity<Project>,
 8714        buffer: &Entity<Buffer>,
 8715        buffer_row: u32,
 8716        tasks: &Arc<RunnableTasks>,
 8717        cx: &mut Context<Self>,
 8718    ) -> Task<Option<task::TaskContext>> {
 8719        let position = Point::new(buffer_row, tasks.column);
 8720        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8721        let location = Location {
 8722            buffer: buffer.clone(),
 8723            range: range_start..range_start,
 8724        };
 8725        // Fill in the environmental variables from the tree-sitter captures
 8726        let mut captured_task_variables = TaskVariables::default();
 8727        for (capture_name, value) in tasks.extra_variables.clone() {
 8728            captured_task_variables.insert(
 8729                task::VariableName::Custom(capture_name.into()),
 8730                value.clone(),
 8731            );
 8732        }
 8733        project.update(cx, |project, cx| {
 8734            project.task_store().update(cx, |task_store, cx| {
 8735                task_store.task_context_for_location(captured_task_variables, location, cx)
 8736            })
 8737        })
 8738    }
 8739
 8740    pub fn spawn_nearest_task(
 8741        &mut self,
 8742        action: &SpawnNearestTask,
 8743        window: &mut Window,
 8744        cx: &mut Context<Self>,
 8745    ) {
 8746        let Some((workspace, _)) = self.workspace.clone() else {
 8747            return;
 8748        };
 8749        let Some(project) = self.project.clone() else {
 8750            return;
 8751        };
 8752
 8753        // Try to find a closest, enclosing node using tree-sitter that has a task
 8754        let Some((buffer, buffer_row, tasks)) = self
 8755            .find_enclosing_node_task(cx)
 8756            // Or find the task that's closest in row-distance.
 8757            .or_else(|| self.find_closest_task(cx))
 8758        else {
 8759            return;
 8760        };
 8761
 8762        let reveal_strategy = action.reveal;
 8763        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8764        cx.spawn_in(window, async move |_, cx| {
 8765            let context = task_context.await?;
 8766            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8767
 8768            let resolved = &mut resolved_task.resolved;
 8769            resolved.reveal = reveal_strategy;
 8770
 8771            workspace
 8772                .update_in(cx, |workspace, window, cx| {
 8773                    workspace.schedule_resolved_task(
 8774                        task_source_kind,
 8775                        resolved_task,
 8776                        false,
 8777                        window,
 8778                        cx,
 8779                    );
 8780                })
 8781                .ok()
 8782        })
 8783        .detach();
 8784    }
 8785
 8786    fn find_closest_task(
 8787        &mut self,
 8788        cx: &mut Context<Self>,
 8789    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8790        let cursor_row = self
 8791            .selections
 8792            .newest_adjusted(&self.display_snapshot(cx))
 8793            .head()
 8794            .row;
 8795
 8796        let ((buffer_id, row), tasks) = self
 8797            .tasks
 8798            .iter()
 8799            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8800
 8801        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8802        let tasks = Arc::new(tasks.to_owned());
 8803        Some((buffer, *row, tasks))
 8804    }
 8805
 8806    fn find_enclosing_node_task(
 8807        &mut self,
 8808        cx: &mut Context<Self>,
 8809    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8810        let snapshot = self.buffer.read(cx).snapshot(cx);
 8811        let offset = self
 8812            .selections
 8813            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8814            .head();
 8815        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8816        let offset = excerpt.map_offset_to_buffer(offset);
 8817        let buffer_id = excerpt.buffer().remote_id();
 8818
 8819        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8820        let mut cursor = layer.node().walk();
 8821
 8822        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8823            if cursor.node().end_byte() == offset.0 {
 8824                cursor.goto_next_sibling();
 8825            }
 8826        }
 8827
 8828        // Ascend to the smallest ancestor that contains the range and has a task.
 8829        loop {
 8830            let node = cursor.node();
 8831            let node_range = node.byte_range();
 8832            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8833
 8834            // Check if this node contains our offset
 8835            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8836                // If it contains offset, check for task
 8837                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8838                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8839                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8840                }
 8841            }
 8842
 8843            if !cursor.goto_parent() {
 8844                break;
 8845            }
 8846        }
 8847        None
 8848    }
 8849
 8850    fn render_run_indicator(
 8851        &self,
 8852        _style: &EditorStyle,
 8853        is_active: bool,
 8854        row: DisplayRow,
 8855        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8856        cx: &mut Context<Self>,
 8857    ) -> IconButton {
 8858        let color = Color::Muted;
 8859        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8860
 8861        IconButton::new(
 8862            ("run_indicator", row.0 as usize),
 8863            ui::IconName::PlayOutlined,
 8864        )
 8865        .shape(ui::IconButtonShape::Square)
 8866        .icon_size(IconSize::XSmall)
 8867        .icon_color(color)
 8868        .toggle_state(is_active)
 8869        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8870            let quick_launch = match e {
 8871                ClickEvent::Keyboard(_) => true,
 8872                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8873            };
 8874
 8875            window.focus(&editor.focus_handle(cx), cx);
 8876            editor.toggle_code_actions(
 8877                &ToggleCodeActions {
 8878                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8879                    quick_launch,
 8880                },
 8881                window,
 8882                cx,
 8883            );
 8884        }))
 8885        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8886            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8887        }))
 8888    }
 8889
 8890    pub fn context_menu_visible(&self) -> bool {
 8891        !self.edit_prediction_preview_is_active()
 8892            && self
 8893                .context_menu
 8894                .borrow()
 8895                .as_ref()
 8896                .is_some_and(|menu| menu.visible())
 8897    }
 8898
 8899    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8900        self.context_menu
 8901            .borrow()
 8902            .as_ref()
 8903            .map(|menu| menu.origin())
 8904    }
 8905
 8906    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8907        self.context_menu_options = Some(options);
 8908    }
 8909
 8910    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8911    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8912
 8913    fn render_edit_prediction_popover(
 8914        &mut self,
 8915        text_bounds: &Bounds<Pixels>,
 8916        content_origin: gpui::Point<Pixels>,
 8917        right_margin: Pixels,
 8918        editor_snapshot: &EditorSnapshot,
 8919        visible_row_range: Range<DisplayRow>,
 8920        scroll_top: ScrollOffset,
 8921        scroll_bottom: ScrollOffset,
 8922        line_layouts: &[LineWithInvisibles],
 8923        line_height: Pixels,
 8924        scroll_position: gpui::Point<ScrollOffset>,
 8925        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8926        newest_selection_head: Option<DisplayPoint>,
 8927        editor_width: Pixels,
 8928        style: &EditorStyle,
 8929        window: &mut Window,
 8930        cx: &mut App,
 8931    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8932        if self.mode().is_minimap() {
 8933            return None;
 8934        }
 8935        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8936
 8937        if self.edit_prediction_visible_in_cursor_popover(true) {
 8938            return None;
 8939        }
 8940
 8941        match &active_edit_prediction.completion {
 8942            EditPrediction::MoveWithin { target, .. } => {
 8943                let target_display_point = target.to_display_point(editor_snapshot);
 8944
 8945                if self.edit_prediction_requires_modifier() {
 8946                    if !self.edit_prediction_preview_is_active() {
 8947                        return None;
 8948                    }
 8949
 8950                    self.render_edit_prediction_modifier_jump_popover(
 8951                        text_bounds,
 8952                        content_origin,
 8953                        visible_row_range,
 8954                        line_layouts,
 8955                        line_height,
 8956                        scroll_pixel_position,
 8957                        newest_selection_head,
 8958                        target_display_point,
 8959                        window,
 8960                        cx,
 8961                    )
 8962                } else {
 8963                    self.render_edit_prediction_eager_jump_popover(
 8964                        text_bounds,
 8965                        content_origin,
 8966                        editor_snapshot,
 8967                        visible_row_range,
 8968                        scroll_top,
 8969                        scroll_bottom,
 8970                        line_height,
 8971                        scroll_pixel_position,
 8972                        target_display_point,
 8973                        editor_width,
 8974                        window,
 8975                        cx,
 8976                    )
 8977                }
 8978            }
 8979            EditPrediction::Edit {
 8980                display_mode: EditDisplayMode::Inline,
 8981                ..
 8982            } => None,
 8983            EditPrediction::Edit {
 8984                display_mode: EditDisplayMode::TabAccept,
 8985                edits,
 8986                ..
 8987            } => {
 8988                let range = &edits.first()?.0;
 8989                let target_display_point = range.end.to_display_point(editor_snapshot);
 8990
 8991                self.render_edit_prediction_end_of_line_popover(
 8992                    "Accept",
 8993                    editor_snapshot,
 8994                    visible_row_range,
 8995                    target_display_point,
 8996                    line_height,
 8997                    scroll_pixel_position,
 8998                    content_origin,
 8999                    editor_width,
 9000                    window,
 9001                    cx,
 9002                )
 9003            }
 9004            EditPrediction::Edit {
 9005                edits,
 9006                edit_preview,
 9007                display_mode: EditDisplayMode::DiffPopover,
 9008                snapshot,
 9009            } => self.render_edit_prediction_diff_popover(
 9010                text_bounds,
 9011                content_origin,
 9012                right_margin,
 9013                editor_snapshot,
 9014                visible_row_range,
 9015                line_layouts,
 9016                line_height,
 9017                scroll_position,
 9018                scroll_pixel_position,
 9019                newest_selection_head,
 9020                editor_width,
 9021                style,
 9022                edits,
 9023                edit_preview,
 9024                snapshot,
 9025                window,
 9026                cx,
 9027            ),
 9028            EditPrediction::MoveOutside { snapshot, .. } => {
 9029                let mut element = self
 9030                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9031                    .into_any();
 9032
 9033                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9034                let origin_x = text_bounds.size.width - size.width - px(30.);
 9035                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9036                element.prepaint_at(origin, window, cx);
 9037
 9038                Some((element, origin))
 9039            }
 9040        }
 9041    }
 9042
 9043    fn render_edit_prediction_modifier_jump_popover(
 9044        &mut self,
 9045        text_bounds: &Bounds<Pixels>,
 9046        content_origin: gpui::Point<Pixels>,
 9047        visible_row_range: Range<DisplayRow>,
 9048        line_layouts: &[LineWithInvisibles],
 9049        line_height: Pixels,
 9050        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9051        newest_selection_head: Option<DisplayPoint>,
 9052        target_display_point: DisplayPoint,
 9053        window: &mut Window,
 9054        cx: &mut App,
 9055    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9056        let scrolled_content_origin =
 9057            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9058
 9059        const SCROLL_PADDING_Y: Pixels = px(12.);
 9060
 9061        if target_display_point.row() < visible_row_range.start {
 9062            return self.render_edit_prediction_scroll_popover(
 9063                |_| SCROLL_PADDING_Y,
 9064                IconName::ArrowUp,
 9065                visible_row_range,
 9066                line_layouts,
 9067                newest_selection_head,
 9068                scrolled_content_origin,
 9069                window,
 9070                cx,
 9071            );
 9072        } else if target_display_point.row() >= visible_row_range.end {
 9073            return self.render_edit_prediction_scroll_popover(
 9074                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9075                IconName::ArrowDown,
 9076                visible_row_range,
 9077                line_layouts,
 9078                newest_selection_head,
 9079                scrolled_content_origin,
 9080                window,
 9081                cx,
 9082            );
 9083        }
 9084
 9085        const POLE_WIDTH: Pixels = px(2.);
 9086
 9087        let line_layout =
 9088            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9089        let target_column = target_display_point.column() as usize;
 9090
 9091        let target_x = line_layout.x_for_index(target_column);
 9092        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9093            - scroll_pixel_position.y;
 9094
 9095        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9096
 9097        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9098        border_color.l += 0.001;
 9099
 9100        let mut element = v_flex()
 9101            .items_end()
 9102            .when(flag_on_right, |el| el.items_start())
 9103            .child(if flag_on_right {
 9104                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9105                    .rounded_bl(px(0.))
 9106                    .rounded_tl(px(0.))
 9107                    .border_l_2()
 9108                    .border_color(border_color)
 9109            } else {
 9110                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9111                    .rounded_br(px(0.))
 9112                    .rounded_tr(px(0.))
 9113                    .border_r_2()
 9114                    .border_color(border_color)
 9115            })
 9116            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9117            .into_any();
 9118
 9119        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9120
 9121        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9122            - point(
 9123                if flag_on_right {
 9124                    POLE_WIDTH
 9125                } else {
 9126                    size.width - POLE_WIDTH
 9127                },
 9128                size.height - line_height,
 9129            );
 9130
 9131        origin.x = origin.x.max(content_origin.x);
 9132
 9133        element.prepaint_at(origin, window, cx);
 9134
 9135        Some((element, origin))
 9136    }
 9137
 9138    fn render_edit_prediction_scroll_popover(
 9139        &mut self,
 9140        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9141        scroll_icon: IconName,
 9142        visible_row_range: Range<DisplayRow>,
 9143        line_layouts: &[LineWithInvisibles],
 9144        newest_selection_head: Option<DisplayPoint>,
 9145        scrolled_content_origin: gpui::Point<Pixels>,
 9146        window: &mut Window,
 9147        cx: &mut App,
 9148    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9149        let mut element = self
 9150            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9151            .into_any();
 9152
 9153        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9154
 9155        let cursor = newest_selection_head?;
 9156        let cursor_row_layout =
 9157            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9158        let cursor_column = cursor.column() as usize;
 9159
 9160        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9161
 9162        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9163
 9164        element.prepaint_at(origin, window, cx);
 9165        Some((element, origin))
 9166    }
 9167
 9168    fn render_edit_prediction_eager_jump_popover(
 9169        &mut self,
 9170        text_bounds: &Bounds<Pixels>,
 9171        content_origin: gpui::Point<Pixels>,
 9172        editor_snapshot: &EditorSnapshot,
 9173        visible_row_range: Range<DisplayRow>,
 9174        scroll_top: ScrollOffset,
 9175        scroll_bottom: ScrollOffset,
 9176        line_height: Pixels,
 9177        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9178        target_display_point: DisplayPoint,
 9179        editor_width: Pixels,
 9180        window: &mut Window,
 9181        cx: &mut App,
 9182    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9183        if target_display_point.row().as_f64() < scroll_top {
 9184            let mut element = self
 9185                .render_edit_prediction_line_popover(
 9186                    "Jump to Edit",
 9187                    Some(IconName::ArrowUp),
 9188                    window,
 9189                    cx,
 9190                )
 9191                .into_any();
 9192
 9193            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9194            let offset = point(
 9195                (text_bounds.size.width - size.width) / 2.,
 9196                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9197            );
 9198
 9199            let origin = text_bounds.origin + offset;
 9200            element.prepaint_at(origin, window, cx);
 9201            Some((element, origin))
 9202        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9203            let mut element = self
 9204                .render_edit_prediction_line_popover(
 9205                    "Jump to Edit",
 9206                    Some(IconName::ArrowDown),
 9207                    window,
 9208                    cx,
 9209                )
 9210                .into_any();
 9211
 9212            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9213            let offset = point(
 9214                (text_bounds.size.width - size.width) / 2.,
 9215                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9216            );
 9217
 9218            let origin = text_bounds.origin + offset;
 9219            element.prepaint_at(origin, window, cx);
 9220            Some((element, origin))
 9221        } else {
 9222            self.render_edit_prediction_end_of_line_popover(
 9223                "Jump to Edit",
 9224                editor_snapshot,
 9225                visible_row_range,
 9226                target_display_point,
 9227                line_height,
 9228                scroll_pixel_position,
 9229                content_origin,
 9230                editor_width,
 9231                window,
 9232                cx,
 9233            )
 9234        }
 9235    }
 9236
 9237    fn render_edit_prediction_end_of_line_popover(
 9238        self: &mut Editor,
 9239        label: &'static str,
 9240        editor_snapshot: &EditorSnapshot,
 9241        visible_row_range: Range<DisplayRow>,
 9242        target_display_point: DisplayPoint,
 9243        line_height: Pixels,
 9244        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9245        content_origin: gpui::Point<Pixels>,
 9246        editor_width: Pixels,
 9247        window: &mut Window,
 9248        cx: &mut App,
 9249    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9250        let target_line_end = DisplayPoint::new(
 9251            target_display_point.row(),
 9252            editor_snapshot.line_len(target_display_point.row()),
 9253        );
 9254
 9255        let mut element = self
 9256            .render_edit_prediction_line_popover(label, None, window, cx)
 9257            .into_any();
 9258
 9259        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9260
 9261        let line_origin =
 9262            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9263
 9264        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9265        let mut origin = start_point
 9266            + line_origin
 9267            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9268        origin.x = origin.x.max(content_origin.x);
 9269
 9270        let max_x = content_origin.x + editor_width - size.width;
 9271
 9272        if origin.x > max_x {
 9273            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9274
 9275            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9276                origin.y += offset;
 9277                IconName::ArrowUp
 9278            } else {
 9279                origin.y -= offset;
 9280                IconName::ArrowDown
 9281            };
 9282
 9283            element = self
 9284                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9285                .into_any();
 9286
 9287            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9288
 9289            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9290        }
 9291
 9292        element.prepaint_at(origin, window, cx);
 9293        Some((element, origin))
 9294    }
 9295
 9296    fn render_edit_prediction_diff_popover(
 9297        self: &Editor,
 9298        text_bounds: &Bounds<Pixels>,
 9299        content_origin: gpui::Point<Pixels>,
 9300        right_margin: Pixels,
 9301        editor_snapshot: &EditorSnapshot,
 9302        visible_row_range: Range<DisplayRow>,
 9303        line_layouts: &[LineWithInvisibles],
 9304        line_height: Pixels,
 9305        scroll_position: gpui::Point<ScrollOffset>,
 9306        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9307        newest_selection_head: Option<DisplayPoint>,
 9308        editor_width: Pixels,
 9309        style: &EditorStyle,
 9310        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9311        edit_preview: &Option<language::EditPreview>,
 9312        snapshot: &language::BufferSnapshot,
 9313        window: &mut Window,
 9314        cx: &mut App,
 9315    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9316        let edit_start = edits
 9317            .first()
 9318            .unwrap()
 9319            .0
 9320            .start
 9321            .to_display_point(editor_snapshot);
 9322        let edit_end = edits
 9323            .last()
 9324            .unwrap()
 9325            .0
 9326            .end
 9327            .to_display_point(editor_snapshot);
 9328
 9329        let is_visible = visible_row_range.contains(&edit_start.row())
 9330            || visible_row_range.contains(&edit_end.row());
 9331        if !is_visible {
 9332            return None;
 9333        }
 9334
 9335        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9336            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9337        } else {
 9338            // Fallback for providers without edit_preview
 9339            crate::edit_prediction_fallback_text(edits, cx)
 9340        };
 9341
 9342        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9343        let line_count = highlighted_edits.text.lines().count();
 9344
 9345        const BORDER_WIDTH: Pixels = px(1.);
 9346
 9347        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9348        let has_keybind = keybind.is_some();
 9349
 9350        let mut element = h_flex()
 9351            .items_start()
 9352            .child(
 9353                h_flex()
 9354                    .bg(cx.theme().colors().editor_background)
 9355                    .border(BORDER_WIDTH)
 9356                    .shadow_xs()
 9357                    .border_color(cx.theme().colors().border)
 9358                    .rounded_l_lg()
 9359                    .when(line_count > 1, |el| el.rounded_br_lg())
 9360                    .pr_1()
 9361                    .child(styled_text),
 9362            )
 9363            .child(
 9364                h_flex()
 9365                    .h(line_height + BORDER_WIDTH * 2.)
 9366                    .px_1p5()
 9367                    .gap_1()
 9368                    // Workaround: For some reason, there's a gap if we don't do this
 9369                    .ml(-BORDER_WIDTH)
 9370                    .shadow(vec![gpui::BoxShadow {
 9371                        color: gpui::black().opacity(0.05),
 9372                        offset: point(px(1.), px(1.)),
 9373                        blur_radius: px(2.),
 9374                        spread_radius: px(0.),
 9375                    }])
 9376                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9377                    .border(BORDER_WIDTH)
 9378                    .border_color(cx.theme().colors().border)
 9379                    .rounded_r_lg()
 9380                    .id("edit_prediction_diff_popover_keybind")
 9381                    .when(!has_keybind, |el| {
 9382                        let status_colors = cx.theme().status();
 9383
 9384                        el.bg(status_colors.error_background)
 9385                            .border_color(status_colors.error.opacity(0.6))
 9386                            .child(Icon::new(IconName::Info).color(Color::Error))
 9387                            .cursor_default()
 9388                            .hoverable_tooltip(move |_window, cx| {
 9389                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9390                            })
 9391                    })
 9392                    .children(keybind),
 9393            )
 9394            .into_any();
 9395
 9396        let longest_row =
 9397            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9398        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9399            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9400        } else {
 9401            layout_line(
 9402                longest_row,
 9403                editor_snapshot,
 9404                style,
 9405                editor_width,
 9406                |_| false,
 9407                window,
 9408                cx,
 9409            )
 9410            .width
 9411        };
 9412
 9413        let viewport_bounds =
 9414            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9415                right: -right_margin,
 9416                ..Default::default()
 9417            });
 9418
 9419        let x_after_longest = Pixels::from(
 9420            ScrollPixelOffset::from(
 9421                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9422            ) - scroll_pixel_position.x,
 9423        );
 9424
 9425        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9426
 9427        // Fully visible if it can be displayed within the window (allow overlapping other
 9428        // panes). However, this is only allowed if the popover starts within text_bounds.
 9429        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9430            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9431
 9432        let mut origin = if can_position_to_the_right {
 9433            point(
 9434                x_after_longest,
 9435                text_bounds.origin.y
 9436                    + Pixels::from(
 9437                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9438                            - scroll_pixel_position.y,
 9439                    ),
 9440            )
 9441        } else {
 9442            let cursor_row = newest_selection_head.map(|head| head.row());
 9443            let above_edit = edit_start
 9444                .row()
 9445                .0
 9446                .checked_sub(line_count as u32)
 9447                .map(DisplayRow);
 9448            let below_edit = Some(edit_end.row() + 1);
 9449            let above_cursor =
 9450                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9451            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9452
 9453            // Place the edit popover adjacent to the edit if there is a location
 9454            // available that is onscreen and does not obscure the cursor. Otherwise,
 9455            // place it adjacent to the cursor.
 9456            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9457                .into_iter()
 9458                .flatten()
 9459                .find(|&start_row| {
 9460                    let end_row = start_row + line_count as u32;
 9461                    visible_row_range.contains(&start_row)
 9462                        && visible_row_range.contains(&end_row)
 9463                        && cursor_row
 9464                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9465                })?;
 9466
 9467            content_origin
 9468                + point(
 9469                    Pixels::from(-scroll_pixel_position.x),
 9470                    Pixels::from(
 9471                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9472                    ),
 9473                )
 9474        };
 9475
 9476        origin.x -= BORDER_WIDTH;
 9477
 9478        window.defer_draw(element, origin, 1);
 9479
 9480        // Do not return an element, since it will already be drawn due to defer_draw.
 9481        None
 9482    }
 9483
 9484    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9485        px(30.)
 9486    }
 9487
 9488    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9489        if self.read_only(cx) {
 9490            cx.theme().players().read_only()
 9491        } else {
 9492            self.style.as_ref().unwrap().local_player
 9493        }
 9494    }
 9495
 9496    fn render_edit_prediction_accept_keybind(
 9497        &self,
 9498        window: &mut Window,
 9499        cx: &mut App,
 9500    ) -> Option<AnyElement> {
 9501        let accept_binding =
 9502            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9503        let accept_keystroke = accept_binding.keystroke()?;
 9504
 9505        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9506
 9507        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9508            Color::Accent
 9509        } else {
 9510            Color::Muted
 9511        };
 9512
 9513        h_flex()
 9514            .px_0p5()
 9515            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9516            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9517            .text_size(TextSize::XSmall.rems(cx))
 9518            .child(h_flex().children(ui::render_modifiers(
 9519                accept_keystroke.modifiers(),
 9520                PlatformStyle::platform(),
 9521                Some(modifiers_color),
 9522                Some(IconSize::XSmall.rems().into()),
 9523                true,
 9524            )))
 9525            .when(is_platform_style_mac, |parent| {
 9526                parent.child(accept_keystroke.key().to_string())
 9527            })
 9528            .when(!is_platform_style_mac, |parent| {
 9529                parent.child(
 9530                    Key::new(
 9531                        util::capitalize(accept_keystroke.key()),
 9532                        Some(Color::Default),
 9533                    )
 9534                    .size(Some(IconSize::XSmall.rems().into())),
 9535                )
 9536            })
 9537            .into_any()
 9538            .into()
 9539    }
 9540
 9541    fn render_edit_prediction_line_popover(
 9542        &self,
 9543        label: impl Into<SharedString>,
 9544        icon: Option<IconName>,
 9545        window: &mut Window,
 9546        cx: &mut App,
 9547    ) -> Stateful<Div> {
 9548        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9549
 9550        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9551        let has_keybind = keybind.is_some();
 9552
 9553        h_flex()
 9554            .id("ep-line-popover")
 9555            .py_0p5()
 9556            .pl_1()
 9557            .pr(padding_right)
 9558            .gap_1()
 9559            .rounded_md()
 9560            .border_1()
 9561            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9562            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9563            .shadow_xs()
 9564            .when(!has_keybind, |el| {
 9565                let status_colors = cx.theme().status();
 9566
 9567                el.bg(status_colors.error_background)
 9568                    .border_color(status_colors.error.opacity(0.6))
 9569                    .pl_2()
 9570                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9571                    .cursor_default()
 9572                    .hoverable_tooltip(move |_window, cx| {
 9573                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9574                    })
 9575            })
 9576            .children(keybind)
 9577            .child(
 9578                Label::new(label)
 9579                    .size(LabelSize::Small)
 9580                    .when(!has_keybind, |el| {
 9581                        el.color(cx.theme().status().error.into()).strikethrough()
 9582                    }),
 9583            )
 9584            .when(!has_keybind, |el| {
 9585                el.child(
 9586                    h_flex().ml_1().child(
 9587                        Icon::new(IconName::Info)
 9588                            .size(IconSize::Small)
 9589                            .color(cx.theme().status().error.into()),
 9590                    ),
 9591                )
 9592            })
 9593            .when_some(icon, |element, icon| {
 9594                element.child(
 9595                    div()
 9596                        .mt(px(1.5))
 9597                        .child(Icon::new(icon).size(IconSize::Small)),
 9598                )
 9599            })
 9600    }
 9601
 9602    fn render_edit_prediction_jump_outside_popover(
 9603        &self,
 9604        snapshot: &BufferSnapshot,
 9605        window: &mut Window,
 9606        cx: &mut App,
 9607    ) -> Stateful<Div> {
 9608        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9609        let has_keybind = keybind.is_some();
 9610
 9611        let file_name = snapshot
 9612            .file()
 9613            .map(|file| SharedString::new(file.file_name(cx)))
 9614            .unwrap_or(SharedString::new_static("untitled"));
 9615
 9616        h_flex()
 9617            .id("ep-jump-outside-popover")
 9618            .py_1()
 9619            .px_2()
 9620            .gap_1()
 9621            .rounded_md()
 9622            .border_1()
 9623            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9624            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9625            .shadow_xs()
 9626            .when(!has_keybind, |el| {
 9627                let status_colors = cx.theme().status();
 9628
 9629                el.bg(status_colors.error_background)
 9630                    .border_color(status_colors.error.opacity(0.6))
 9631                    .pl_2()
 9632                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9633                    .cursor_default()
 9634                    .hoverable_tooltip(move |_window, cx| {
 9635                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9636                    })
 9637            })
 9638            .children(keybind)
 9639            .child(
 9640                Label::new(file_name)
 9641                    .size(LabelSize::Small)
 9642                    .buffer_font(cx)
 9643                    .when(!has_keybind, |el| {
 9644                        el.color(cx.theme().status().error.into()).strikethrough()
 9645                    }),
 9646            )
 9647            .when(!has_keybind, |el| {
 9648                el.child(
 9649                    h_flex().ml_1().child(
 9650                        Icon::new(IconName::Info)
 9651                            .size(IconSize::Small)
 9652                            .color(cx.theme().status().error.into()),
 9653                    ),
 9654                )
 9655            })
 9656            .child(
 9657                div()
 9658                    .mt(px(1.5))
 9659                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9660            )
 9661    }
 9662
 9663    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9664        let accent_color = cx.theme().colors().text_accent;
 9665        let editor_bg_color = cx.theme().colors().editor_background;
 9666        editor_bg_color.blend(accent_color.opacity(0.1))
 9667    }
 9668
 9669    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9670        let accent_color = cx.theme().colors().text_accent;
 9671        let editor_bg_color = cx.theme().colors().editor_background;
 9672        editor_bg_color.blend(accent_color.opacity(0.6))
 9673    }
 9674    fn get_prediction_provider_icon_name(
 9675        provider: &Option<RegisteredEditPredictionDelegate>,
 9676    ) -> IconName {
 9677        match provider {
 9678            Some(provider) => match provider.provider.name() {
 9679                "copilot" => IconName::Copilot,
 9680                "supermaven" => IconName::Supermaven,
 9681                _ => IconName::ZedPredict,
 9682            },
 9683            None => IconName::ZedPredict,
 9684        }
 9685    }
 9686
 9687    fn render_edit_prediction_cursor_popover(
 9688        &self,
 9689        min_width: Pixels,
 9690        max_width: Pixels,
 9691        cursor_point: Point,
 9692        style: &EditorStyle,
 9693        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9694        _window: &Window,
 9695        cx: &mut Context<Editor>,
 9696    ) -> Option<AnyElement> {
 9697        let provider = self.edit_prediction_provider.as_ref()?;
 9698        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9699
 9700        let is_refreshing = provider.provider.is_refreshing(cx);
 9701
 9702        fn pending_completion_container(icon: IconName) -> Div {
 9703            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9704        }
 9705
 9706        let completion = match &self.active_edit_prediction {
 9707            Some(prediction) => {
 9708                if !self.has_visible_completions_menu() {
 9709                    const RADIUS: Pixels = px(6.);
 9710                    const BORDER_WIDTH: Pixels = px(1.);
 9711
 9712                    return Some(
 9713                        h_flex()
 9714                            .elevation_2(cx)
 9715                            .border(BORDER_WIDTH)
 9716                            .border_color(cx.theme().colors().border)
 9717                            .when(accept_keystroke.is_none(), |el| {
 9718                                el.border_color(cx.theme().status().error)
 9719                            })
 9720                            .rounded(RADIUS)
 9721                            .rounded_tl(px(0.))
 9722                            .overflow_hidden()
 9723                            .child(div().px_1p5().child(match &prediction.completion {
 9724                                EditPrediction::MoveWithin { target, snapshot } => {
 9725                                    use text::ToPoint as _;
 9726                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9727                                    {
 9728                                        Icon::new(IconName::ZedPredictDown)
 9729                                    } else {
 9730                                        Icon::new(IconName::ZedPredictUp)
 9731                                    }
 9732                                }
 9733                                EditPrediction::MoveOutside { .. } => {
 9734                                    // TODO [zeta2] custom icon for external jump?
 9735                                    Icon::new(provider_icon)
 9736                                }
 9737                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9738                            }))
 9739                            .child(
 9740                                h_flex()
 9741                                    .gap_1()
 9742                                    .py_1()
 9743                                    .px_2()
 9744                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9745                                    .border_l_1()
 9746                                    .border_color(cx.theme().colors().border)
 9747                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9748                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9749                                        el.child(
 9750                                            Label::new("Hold")
 9751                                                .size(LabelSize::Small)
 9752                                                .when(accept_keystroke.is_none(), |el| {
 9753                                                    el.strikethrough()
 9754                                                })
 9755                                                .line_height_style(LineHeightStyle::UiLabel),
 9756                                        )
 9757                                    })
 9758                                    .id("edit_prediction_cursor_popover_keybind")
 9759                                    .when(accept_keystroke.is_none(), |el| {
 9760                                        let status_colors = cx.theme().status();
 9761
 9762                                        el.bg(status_colors.error_background)
 9763                                            .border_color(status_colors.error.opacity(0.6))
 9764                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9765                                            .cursor_default()
 9766                                            .hoverable_tooltip(move |_window, cx| {
 9767                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9768                                                    .into()
 9769                                            })
 9770                                    })
 9771                                    .when_some(
 9772                                        accept_keystroke.as_ref(),
 9773                                        |el, accept_keystroke| {
 9774                                            el.child(h_flex().children(ui::render_modifiers(
 9775                                                accept_keystroke.modifiers(),
 9776                                                PlatformStyle::platform(),
 9777                                                Some(Color::Default),
 9778                                                Some(IconSize::XSmall.rems().into()),
 9779                                                false,
 9780                                            )))
 9781                                        },
 9782                                    ),
 9783                            )
 9784                            .into_any(),
 9785                    );
 9786                }
 9787
 9788                self.render_edit_prediction_cursor_popover_preview(
 9789                    prediction,
 9790                    cursor_point,
 9791                    style,
 9792                    cx,
 9793                )?
 9794            }
 9795
 9796            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9797                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9798                    stale_completion,
 9799                    cursor_point,
 9800                    style,
 9801                    cx,
 9802                )?,
 9803
 9804                None => pending_completion_container(provider_icon)
 9805                    .child(Label::new("...").size(LabelSize::Small)),
 9806            },
 9807
 9808            None => pending_completion_container(provider_icon)
 9809                .child(Label::new("...").size(LabelSize::Small)),
 9810        };
 9811
 9812        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9813            completion
 9814                .with_animation(
 9815                    "loading-completion",
 9816                    Animation::new(Duration::from_secs(2))
 9817                        .repeat()
 9818                        .with_easing(pulsating_between(0.4, 0.8)),
 9819                    |label, delta| label.opacity(delta),
 9820                )
 9821                .into_any_element()
 9822        } else {
 9823            completion.into_any_element()
 9824        };
 9825
 9826        let has_completion = self.active_edit_prediction.is_some();
 9827
 9828        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9829        Some(
 9830            h_flex()
 9831                .min_w(min_width)
 9832                .max_w(max_width)
 9833                .flex_1()
 9834                .elevation_2(cx)
 9835                .border_color(cx.theme().colors().border)
 9836                .child(
 9837                    div()
 9838                        .flex_1()
 9839                        .py_1()
 9840                        .px_2()
 9841                        .overflow_hidden()
 9842                        .child(completion),
 9843                )
 9844                .when_some(accept_keystroke, |el, accept_keystroke| {
 9845                    if !accept_keystroke.modifiers().modified() {
 9846                        return el;
 9847                    }
 9848
 9849                    el.child(
 9850                        h_flex()
 9851                            .h_full()
 9852                            .border_l_1()
 9853                            .rounded_r_lg()
 9854                            .border_color(cx.theme().colors().border)
 9855                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9856                            .gap_1()
 9857                            .py_1()
 9858                            .px_2()
 9859                            .child(
 9860                                h_flex()
 9861                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9862                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9863                                    .child(h_flex().children(ui::render_modifiers(
 9864                                        accept_keystroke.modifiers(),
 9865                                        PlatformStyle::platform(),
 9866                                        Some(if !has_completion {
 9867                                            Color::Muted
 9868                                        } else {
 9869                                            Color::Default
 9870                                        }),
 9871                                        None,
 9872                                        false,
 9873                                    ))),
 9874                            )
 9875                            .child(Label::new("Preview").into_any_element())
 9876                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9877                    )
 9878                })
 9879                .into_any(),
 9880        )
 9881    }
 9882
 9883    fn render_edit_prediction_cursor_popover_preview(
 9884        &self,
 9885        completion: &EditPredictionState,
 9886        cursor_point: Point,
 9887        style: &EditorStyle,
 9888        cx: &mut Context<Editor>,
 9889    ) -> Option<Div> {
 9890        use text::ToPoint as _;
 9891
 9892        fn render_relative_row_jump(
 9893            prefix: impl Into<String>,
 9894            current_row: u32,
 9895            target_row: u32,
 9896        ) -> Div {
 9897            let (row_diff, arrow) = if target_row < current_row {
 9898                (current_row - target_row, IconName::ArrowUp)
 9899            } else {
 9900                (target_row - current_row, IconName::ArrowDown)
 9901            };
 9902
 9903            h_flex()
 9904                .child(
 9905                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9906                        .color(Color::Muted)
 9907                        .size(LabelSize::Small),
 9908                )
 9909                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9910        }
 9911
 9912        let supports_jump = self
 9913            .edit_prediction_provider
 9914            .as_ref()
 9915            .map(|provider| provider.provider.supports_jump_to_edit())
 9916            .unwrap_or(true);
 9917
 9918        match &completion.completion {
 9919            EditPrediction::MoveWithin {
 9920                target, snapshot, ..
 9921            } => {
 9922                if !supports_jump {
 9923                    return None;
 9924                }
 9925
 9926                Some(
 9927                    h_flex()
 9928                        .px_2()
 9929                        .gap_2()
 9930                        .flex_1()
 9931                        .child(
 9932                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9933                                Icon::new(IconName::ZedPredictDown)
 9934                            } else {
 9935                                Icon::new(IconName::ZedPredictUp)
 9936                            },
 9937                        )
 9938                        .child(Label::new("Jump to Edit")),
 9939                )
 9940            }
 9941            EditPrediction::MoveOutside { snapshot, .. } => {
 9942                let file_name = snapshot
 9943                    .file()
 9944                    .map(|file| file.file_name(cx))
 9945                    .unwrap_or("untitled");
 9946                Some(
 9947                    h_flex()
 9948                        .px_2()
 9949                        .gap_2()
 9950                        .flex_1()
 9951                        .child(Icon::new(IconName::ZedPredict))
 9952                        .child(Label::new(format!("Jump to {file_name}"))),
 9953                )
 9954            }
 9955            EditPrediction::Edit {
 9956                edits,
 9957                edit_preview,
 9958                snapshot,
 9959                display_mode: _,
 9960            } => {
 9961                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9962
 9963                let (highlighted_edits, has_more_lines) =
 9964                    if let Some(edit_preview) = edit_preview.as_ref() {
 9965                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9966                            .first_line_preview()
 9967                    } else {
 9968                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9969                    };
 9970
 9971                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9972                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9973
 9974                let preview = h_flex()
 9975                    .gap_1()
 9976                    .min_w_16()
 9977                    .child(styled_text)
 9978                    .when(has_more_lines, |parent| parent.child(""));
 9979
 9980                let left = if supports_jump && first_edit_row != cursor_point.row {
 9981                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9982                        .into_any_element()
 9983                } else {
 9984                    let icon_name =
 9985                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9986                    Icon::new(icon_name).into_any_element()
 9987                };
 9988
 9989                Some(
 9990                    h_flex()
 9991                        .h_full()
 9992                        .flex_1()
 9993                        .gap_2()
 9994                        .pr_1()
 9995                        .overflow_x_hidden()
 9996                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9997                        .child(left)
 9998                        .child(preview),
 9999                )
10000            }
10001        }
10002    }
10003
10004    pub fn render_context_menu(
10005        &mut self,
10006        max_height_in_lines: u32,
10007        window: &mut Window,
10008        cx: &mut Context<Editor>,
10009    ) -> Option<AnyElement> {
10010        let menu = self.context_menu.borrow();
10011        let menu = menu.as_ref()?;
10012        if !menu.visible() {
10013            return None;
10014        };
10015        self.style
10016            .as_ref()
10017            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10018    }
10019
10020    fn render_context_menu_aside(
10021        &mut self,
10022        max_size: Size<Pixels>,
10023        window: &mut Window,
10024        cx: &mut Context<Editor>,
10025    ) -> Option<AnyElement> {
10026        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10027            if menu.visible() {
10028                menu.render_aside(max_size, window, cx)
10029            } else {
10030                None
10031            }
10032        })
10033    }
10034
10035    fn hide_context_menu(
10036        &mut self,
10037        window: &mut Window,
10038        cx: &mut Context<Self>,
10039    ) -> Option<CodeContextMenu> {
10040        cx.notify();
10041        self.completion_tasks.clear();
10042        let context_menu = self.context_menu.borrow_mut().take();
10043        self.stale_edit_prediction_in_menu.take();
10044        self.update_visible_edit_prediction(window, cx);
10045        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10046            && let Some(completion_provider) = &self.completion_provider
10047        {
10048            completion_provider.selection_changed(None, window, cx);
10049        }
10050        context_menu
10051    }
10052
10053    fn show_snippet_choices(
10054        &mut self,
10055        choices: &Vec<String>,
10056        selection: Range<Anchor>,
10057        cx: &mut Context<Self>,
10058    ) {
10059        let Some((_, buffer, _)) = self
10060            .buffer()
10061            .read(cx)
10062            .excerpt_containing(selection.start, cx)
10063        else {
10064            return;
10065        };
10066        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10067        else {
10068            return;
10069        };
10070        if buffer != end_buffer {
10071            log::error!("expected anchor range to have matching buffer IDs");
10072            return;
10073        }
10074
10075        let id = post_inc(&mut self.next_completion_id);
10076        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10077        let mut context_menu = self.context_menu.borrow_mut();
10078        let old_menu = context_menu.take();
10079        *context_menu = Some(CodeContextMenu::Completions(
10080            CompletionsMenu::new_snippet_choices(
10081                id,
10082                true,
10083                choices,
10084                selection,
10085                buffer,
10086                old_menu.map(|menu| menu.primary_scroll_handle()),
10087                snippet_sort_order,
10088            ),
10089        ));
10090    }
10091
10092    pub fn insert_snippet(
10093        &mut self,
10094        insertion_ranges: &[Range<MultiBufferOffset>],
10095        snippet: Snippet,
10096        window: &mut Window,
10097        cx: &mut Context<Self>,
10098    ) -> Result<()> {
10099        struct Tabstop<T> {
10100            is_end_tabstop: bool,
10101            ranges: Vec<Range<T>>,
10102            choices: Option<Vec<String>>,
10103        }
10104
10105        let tabstops = self.buffer.update(cx, |buffer, cx| {
10106            let snippet_text: Arc<str> = snippet.text.clone().into();
10107            let edits = insertion_ranges
10108                .iter()
10109                .cloned()
10110                .map(|range| (range, snippet_text.clone()));
10111            let autoindent_mode = AutoindentMode::Block {
10112                original_indent_columns: Vec::new(),
10113            };
10114            buffer.edit(edits, Some(autoindent_mode), cx);
10115
10116            let snapshot = &*buffer.read(cx);
10117            let snippet = &snippet;
10118            snippet
10119                .tabstops
10120                .iter()
10121                .map(|tabstop| {
10122                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10123                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10124                    });
10125                    let mut tabstop_ranges = tabstop
10126                        .ranges
10127                        .iter()
10128                        .flat_map(|tabstop_range| {
10129                            let mut delta = 0_isize;
10130                            insertion_ranges.iter().map(move |insertion_range| {
10131                                let insertion_start = insertion_range.start + delta;
10132                                delta += snippet.text.len() as isize
10133                                    - (insertion_range.end - insertion_range.start) as isize;
10134
10135                                let start =
10136                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10137                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10138                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10139                            })
10140                        })
10141                        .collect::<Vec<_>>();
10142                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10143
10144                    Tabstop {
10145                        is_end_tabstop,
10146                        ranges: tabstop_ranges,
10147                        choices: tabstop.choices.clone(),
10148                    }
10149                })
10150                .collect::<Vec<_>>()
10151        });
10152        if let Some(tabstop) = tabstops.first() {
10153            self.change_selections(Default::default(), window, cx, |s| {
10154                // Reverse order so that the first range is the newest created selection.
10155                // Completions will use it and autoscroll will prioritize it.
10156                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10157            });
10158
10159            if let Some(choices) = &tabstop.choices
10160                && let Some(selection) = tabstop.ranges.first()
10161            {
10162                self.show_snippet_choices(choices, selection.clone(), cx)
10163            }
10164
10165            // If we're already at the last tabstop and it's at the end of the snippet,
10166            // we're done, we don't need to keep the state around.
10167            if !tabstop.is_end_tabstop {
10168                let choices = tabstops
10169                    .iter()
10170                    .map(|tabstop| tabstop.choices.clone())
10171                    .collect();
10172
10173                let ranges = tabstops
10174                    .into_iter()
10175                    .map(|tabstop| tabstop.ranges)
10176                    .collect::<Vec<_>>();
10177
10178                self.snippet_stack.push(SnippetState {
10179                    active_index: 0,
10180                    ranges,
10181                    choices,
10182                });
10183            }
10184
10185            // Check whether the just-entered snippet ends with an auto-closable bracket.
10186            if self.autoclose_regions.is_empty() {
10187                let snapshot = self.buffer.read(cx).snapshot(cx);
10188                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10189                    let selection_head = selection.head();
10190                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10191                        continue;
10192                    };
10193
10194                    let mut bracket_pair = None;
10195                    let max_lookup_length = scope
10196                        .brackets()
10197                        .map(|(pair, _)| {
10198                            pair.start
10199                                .as_str()
10200                                .chars()
10201                                .count()
10202                                .max(pair.end.as_str().chars().count())
10203                        })
10204                        .max();
10205                    if let Some(max_lookup_length) = max_lookup_length {
10206                        let next_text = snapshot
10207                            .chars_at(selection_head)
10208                            .take(max_lookup_length)
10209                            .collect::<String>();
10210                        let prev_text = snapshot
10211                            .reversed_chars_at(selection_head)
10212                            .take(max_lookup_length)
10213                            .collect::<String>();
10214
10215                        for (pair, enabled) in scope.brackets() {
10216                            if enabled
10217                                && pair.close
10218                                && prev_text.starts_with(pair.start.as_str())
10219                                && next_text.starts_with(pair.end.as_str())
10220                            {
10221                                bracket_pair = Some(pair.clone());
10222                                break;
10223                            }
10224                        }
10225                    }
10226
10227                    if let Some(pair) = bracket_pair {
10228                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10229                        let autoclose_enabled =
10230                            self.use_autoclose && snapshot_settings.use_autoclose;
10231                        if autoclose_enabled {
10232                            let start = snapshot.anchor_after(selection_head);
10233                            let end = snapshot.anchor_after(selection_head);
10234                            self.autoclose_regions.push(AutocloseRegion {
10235                                selection_id: selection.id,
10236                                range: start..end,
10237                                pair,
10238                            });
10239                        }
10240                    }
10241                }
10242            }
10243        }
10244        Ok(())
10245    }
10246
10247    pub fn move_to_next_snippet_tabstop(
10248        &mut self,
10249        window: &mut Window,
10250        cx: &mut Context<Self>,
10251    ) -> bool {
10252        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10253    }
10254
10255    pub fn move_to_prev_snippet_tabstop(
10256        &mut self,
10257        window: &mut Window,
10258        cx: &mut Context<Self>,
10259    ) -> bool {
10260        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10261    }
10262
10263    pub fn move_to_snippet_tabstop(
10264        &mut self,
10265        bias: Bias,
10266        window: &mut Window,
10267        cx: &mut Context<Self>,
10268    ) -> bool {
10269        if let Some(mut snippet) = self.snippet_stack.pop() {
10270            match bias {
10271                Bias::Left => {
10272                    if snippet.active_index > 0 {
10273                        snippet.active_index -= 1;
10274                    } else {
10275                        self.snippet_stack.push(snippet);
10276                        return false;
10277                    }
10278                }
10279                Bias::Right => {
10280                    if snippet.active_index + 1 < snippet.ranges.len() {
10281                        snippet.active_index += 1;
10282                    } else {
10283                        self.snippet_stack.push(snippet);
10284                        return false;
10285                    }
10286                }
10287            }
10288            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10289                self.change_selections(Default::default(), window, cx, |s| {
10290                    // Reverse order so that the first range is the newest created selection.
10291                    // Completions will use it and autoscroll will prioritize it.
10292                    s.select_ranges(current_ranges.iter().rev().cloned())
10293                });
10294
10295                if let Some(choices) = &snippet.choices[snippet.active_index]
10296                    && let Some(selection) = current_ranges.first()
10297                {
10298                    self.show_snippet_choices(choices, selection.clone(), cx);
10299                }
10300
10301                // If snippet state is not at the last tabstop, push it back on the stack
10302                if snippet.active_index + 1 < snippet.ranges.len() {
10303                    self.snippet_stack.push(snippet);
10304                }
10305                return true;
10306            }
10307        }
10308
10309        false
10310    }
10311
10312    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10313        self.transact(window, cx, |this, window, cx| {
10314            this.select_all(&SelectAll, window, cx);
10315            this.insert("", window, cx);
10316        });
10317    }
10318
10319    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10320        if self.read_only(cx) {
10321            return;
10322        }
10323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10324        self.transact(window, cx, |this, window, cx| {
10325            this.select_autoclose_pair(window, cx);
10326
10327            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10328
10329            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10330            if !this.linked_edit_ranges.is_empty() {
10331                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10332                let snapshot = this.buffer.read(cx).snapshot(cx);
10333
10334                for selection in selections.iter() {
10335                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10336                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10337                    if selection_start.buffer_id != selection_end.buffer_id {
10338                        continue;
10339                    }
10340                    if let Some(ranges) =
10341                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10342                    {
10343                        for (buffer, entries) in ranges {
10344                            linked_ranges.entry(buffer).or_default().extend(entries);
10345                        }
10346                    }
10347                }
10348            }
10349
10350            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10351            for selection in &mut selections {
10352                if selection.is_empty() {
10353                    let old_head = selection.head();
10354                    let mut new_head =
10355                        movement::left(&display_map, old_head.to_display_point(&display_map))
10356                            .to_point(&display_map);
10357                    if let Some((buffer, line_buffer_range)) = display_map
10358                        .buffer_snapshot()
10359                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10360                    {
10361                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10362                        let indent_len = match indent_size.kind {
10363                            IndentKind::Space => {
10364                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10365                            }
10366                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10367                        };
10368                        if old_head.column <= indent_size.len && old_head.column > 0 {
10369                            let indent_len = indent_len.get();
10370                            new_head = cmp::min(
10371                                new_head,
10372                                MultiBufferPoint::new(
10373                                    old_head.row,
10374                                    ((old_head.column - 1) / indent_len) * indent_len,
10375                                ),
10376                            );
10377                        }
10378                    }
10379
10380                    selection.set_head(new_head, SelectionGoal::None);
10381                }
10382            }
10383
10384            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10385            this.insert("", window, cx);
10386            let empty_str: Arc<str> = Arc::from("");
10387            for (buffer, edits) in linked_ranges {
10388                let snapshot = buffer.read(cx).snapshot();
10389                use text::ToPoint as TP;
10390
10391                let edits = edits
10392                    .into_iter()
10393                    .map(|range| {
10394                        let end_point = TP::to_point(&range.end, &snapshot);
10395                        let mut start_point = TP::to_point(&range.start, &snapshot);
10396
10397                        if end_point == start_point {
10398                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10399                                .saturating_sub(1);
10400                            start_point =
10401                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10402                        };
10403
10404                        (start_point..end_point, empty_str.clone())
10405                    })
10406                    .sorted_by_key(|(range, _)| range.start)
10407                    .collect::<Vec<_>>();
10408                buffer.update(cx, |this, cx| {
10409                    this.edit(edits, None, cx);
10410                })
10411            }
10412            this.refresh_edit_prediction(true, false, window, cx);
10413            refresh_linked_ranges(this, window, cx);
10414        });
10415    }
10416
10417    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10418        if self.read_only(cx) {
10419            return;
10420        }
10421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10422        self.transact(window, cx, |this, window, cx| {
10423            this.change_selections(Default::default(), window, cx, |s| {
10424                s.move_with(|map, selection| {
10425                    if selection.is_empty() {
10426                        let cursor = movement::right(map, selection.head());
10427                        selection.end = cursor;
10428                        selection.reversed = true;
10429                        selection.goal = SelectionGoal::None;
10430                    }
10431                })
10432            });
10433            this.insert("", window, cx);
10434            this.refresh_edit_prediction(true, false, window, cx);
10435        });
10436    }
10437
10438    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10439        if self.mode.is_single_line() {
10440            cx.propagate();
10441            return;
10442        }
10443
10444        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10445        if self.move_to_prev_snippet_tabstop(window, cx) {
10446            return;
10447        }
10448        self.outdent(&Outdent, window, cx);
10449    }
10450
10451    pub fn next_snippet_tabstop(
10452        &mut self,
10453        _: &NextSnippetTabstop,
10454        window: &mut Window,
10455        cx: &mut Context<Self>,
10456    ) {
10457        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10458            cx.propagate();
10459            return;
10460        }
10461
10462        if self.move_to_next_snippet_tabstop(window, cx) {
10463            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10464            return;
10465        }
10466        cx.propagate();
10467    }
10468
10469    pub fn previous_snippet_tabstop(
10470        &mut self,
10471        _: &PreviousSnippetTabstop,
10472        window: &mut Window,
10473        cx: &mut Context<Self>,
10474    ) {
10475        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10476            cx.propagate();
10477            return;
10478        }
10479
10480        if self.move_to_prev_snippet_tabstop(window, cx) {
10481            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482            return;
10483        }
10484        cx.propagate();
10485    }
10486
10487    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10488        if self.mode.is_single_line() {
10489            cx.propagate();
10490            return;
10491        }
10492
10493        if self.move_to_next_snippet_tabstop(window, cx) {
10494            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10495            return;
10496        }
10497        if self.read_only(cx) {
10498            return;
10499        }
10500        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10501        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10502        let buffer = self.buffer.read(cx);
10503        let snapshot = buffer.snapshot(cx);
10504        let rows_iter = selections.iter().map(|s| s.head().row);
10505        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10506
10507        let has_some_cursor_in_whitespace = selections
10508            .iter()
10509            .filter(|selection| selection.is_empty())
10510            .any(|selection| {
10511                let cursor = selection.head();
10512                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10513                cursor.column < current_indent.len
10514            });
10515
10516        let mut edits = Vec::new();
10517        let mut prev_edited_row = 0;
10518        let mut row_delta = 0;
10519        for selection in &mut selections {
10520            if selection.start.row != prev_edited_row {
10521                row_delta = 0;
10522            }
10523            prev_edited_row = selection.end.row;
10524
10525            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10526            if selection.is_empty() {
10527                let cursor = selection.head();
10528                let settings = buffer.language_settings_at(cursor, cx);
10529                if settings.indent_list_on_tab {
10530                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10531                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10532                            row_delta = Self::indent_selection(
10533                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10534                            );
10535                            continue;
10536                        }
10537                    }
10538                }
10539            }
10540
10541            // If the selection is non-empty, then increase the indentation of the selected lines.
10542            if !selection.is_empty() {
10543                row_delta =
10544                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10545                continue;
10546            }
10547
10548            let cursor = selection.head();
10549            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10550            if let Some(suggested_indent) =
10551                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10552            {
10553                // Don't do anything if already at suggested indent
10554                // and there is any other cursor which is not
10555                if has_some_cursor_in_whitespace
10556                    && cursor.column == current_indent.len
10557                    && current_indent.len == suggested_indent.len
10558                {
10559                    continue;
10560                }
10561
10562                // Adjust line and move cursor to suggested indent
10563                // if cursor is not at suggested indent
10564                if cursor.column < suggested_indent.len
10565                    && cursor.column <= current_indent.len
10566                    && current_indent.len <= suggested_indent.len
10567                {
10568                    selection.start = Point::new(cursor.row, suggested_indent.len);
10569                    selection.end = selection.start;
10570                    if row_delta == 0 {
10571                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10572                            cursor.row,
10573                            current_indent,
10574                            suggested_indent,
10575                        ));
10576                        row_delta = suggested_indent.len - current_indent.len;
10577                    }
10578                    continue;
10579                }
10580
10581                // If current indent is more than suggested indent
10582                // only move cursor to current indent and skip indent
10583                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10584                    selection.start = Point::new(cursor.row, current_indent.len);
10585                    selection.end = selection.start;
10586                    continue;
10587                }
10588            }
10589
10590            // Otherwise, insert a hard or soft tab.
10591            let settings = buffer.language_settings_at(cursor, cx);
10592            let tab_size = if settings.hard_tabs {
10593                IndentSize::tab()
10594            } else {
10595                let tab_size = settings.tab_size.get();
10596                let indent_remainder = snapshot
10597                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10598                    .flat_map(str::chars)
10599                    .fold(row_delta % tab_size, |counter: u32, c| {
10600                        if c == '\t' {
10601                            0
10602                        } else {
10603                            (counter + 1) % tab_size
10604                        }
10605                    });
10606
10607                let chars_to_next_tab_stop = tab_size - indent_remainder;
10608                IndentSize::spaces(chars_to_next_tab_stop)
10609            };
10610            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10611            selection.end = selection.start;
10612            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10613            row_delta += tab_size.len;
10614        }
10615
10616        self.transact(window, cx, |this, window, cx| {
10617            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10618            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10619            this.refresh_edit_prediction(true, false, window, cx);
10620        });
10621    }
10622
10623    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10624        if self.read_only(cx) {
10625            return;
10626        }
10627        if self.mode.is_single_line() {
10628            cx.propagate();
10629            return;
10630        }
10631
10632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10633        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10634        let mut prev_edited_row = 0;
10635        let mut row_delta = 0;
10636        let mut edits = Vec::new();
10637        let buffer = self.buffer.read(cx);
10638        let snapshot = buffer.snapshot(cx);
10639        for selection in &mut selections {
10640            if selection.start.row != prev_edited_row {
10641                row_delta = 0;
10642            }
10643            prev_edited_row = selection.end.row;
10644
10645            row_delta =
10646                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10647        }
10648
10649        self.transact(window, cx, |this, window, cx| {
10650            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10651            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10652        });
10653    }
10654
10655    fn indent_selection(
10656        buffer: &MultiBuffer,
10657        snapshot: &MultiBufferSnapshot,
10658        selection: &mut Selection<Point>,
10659        edits: &mut Vec<(Range<Point>, String)>,
10660        delta_for_start_row: u32,
10661        cx: &App,
10662    ) -> u32 {
10663        let settings = buffer.language_settings_at(selection.start, cx);
10664        let tab_size = settings.tab_size.get();
10665        let indent_kind = if settings.hard_tabs {
10666            IndentKind::Tab
10667        } else {
10668            IndentKind::Space
10669        };
10670        let mut start_row = selection.start.row;
10671        let mut end_row = selection.end.row + 1;
10672
10673        // If a selection ends at the beginning of a line, don't indent
10674        // that last line.
10675        if selection.end.column == 0 && selection.end.row > selection.start.row {
10676            end_row -= 1;
10677        }
10678
10679        // Avoid re-indenting a row that has already been indented by a
10680        // previous selection, but still update this selection's column
10681        // to reflect that indentation.
10682        if delta_for_start_row > 0 {
10683            start_row += 1;
10684            selection.start.column += delta_for_start_row;
10685            if selection.end.row == selection.start.row {
10686                selection.end.column += delta_for_start_row;
10687            }
10688        }
10689
10690        let mut delta_for_end_row = 0;
10691        let has_multiple_rows = start_row + 1 != end_row;
10692        for row in start_row..end_row {
10693            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10694            let indent_delta = match (current_indent.kind, indent_kind) {
10695                (IndentKind::Space, IndentKind::Space) => {
10696                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10697                    IndentSize::spaces(columns_to_next_tab_stop)
10698                }
10699                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10700                (_, IndentKind::Tab) => IndentSize::tab(),
10701            };
10702
10703            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10704                0
10705            } else {
10706                selection.start.column
10707            };
10708            let row_start = Point::new(row, start);
10709            edits.push((
10710                row_start..row_start,
10711                indent_delta.chars().collect::<String>(),
10712            ));
10713
10714            // Update this selection's endpoints to reflect the indentation.
10715            if row == selection.start.row {
10716                selection.start.column += indent_delta.len;
10717            }
10718            if row == selection.end.row {
10719                selection.end.column += indent_delta.len;
10720                delta_for_end_row = indent_delta.len;
10721            }
10722        }
10723
10724        if selection.start.row == selection.end.row {
10725            delta_for_start_row + delta_for_end_row
10726        } else {
10727            delta_for_end_row
10728        }
10729    }
10730
10731    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10732        if self.read_only(cx) {
10733            return;
10734        }
10735        if self.mode.is_single_line() {
10736            cx.propagate();
10737            return;
10738        }
10739
10740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10742        let selections = self.selections.all::<Point>(&display_map);
10743        let mut deletion_ranges = Vec::new();
10744        let mut last_outdent = None;
10745        {
10746            let buffer = self.buffer.read(cx);
10747            let snapshot = buffer.snapshot(cx);
10748            for selection in &selections {
10749                let settings = buffer.language_settings_at(selection.start, cx);
10750                let tab_size = settings.tab_size.get();
10751                let mut rows = selection.spanned_rows(false, &display_map);
10752
10753                // Avoid re-outdenting a row that has already been outdented by a
10754                // previous selection.
10755                if let Some(last_row) = last_outdent
10756                    && last_row == rows.start
10757                {
10758                    rows.start = rows.start.next_row();
10759                }
10760                let has_multiple_rows = rows.len() > 1;
10761                for row in rows.iter_rows() {
10762                    let indent_size = snapshot.indent_size_for_line(row);
10763                    if indent_size.len > 0 {
10764                        let deletion_len = match indent_size.kind {
10765                            IndentKind::Space => {
10766                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10767                                if columns_to_prev_tab_stop == 0 {
10768                                    tab_size
10769                                } else {
10770                                    columns_to_prev_tab_stop
10771                                }
10772                            }
10773                            IndentKind::Tab => 1,
10774                        };
10775                        let start = if has_multiple_rows
10776                            || deletion_len > selection.start.column
10777                            || indent_size.len < selection.start.column
10778                        {
10779                            0
10780                        } else {
10781                            selection.start.column - deletion_len
10782                        };
10783                        deletion_ranges.push(
10784                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10785                        );
10786                        last_outdent = Some(row);
10787                    }
10788                }
10789            }
10790        }
10791
10792        self.transact(window, cx, |this, window, cx| {
10793            this.buffer.update(cx, |buffer, cx| {
10794                let empty_str: Arc<str> = Arc::default();
10795                buffer.edit(
10796                    deletion_ranges
10797                        .into_iter()
10798                        .map(|range| (range, empty_str.clone())),
10799                    None,
10800                    cx,
10801                );
10802            });
10803            let selections = this
10804                .selections
10805                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10806            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10807        });
10808    }
10809
10810    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10811        if self.read_only(cx) {
10812            return;
10813        }
10814        if self.mode.is_single_line() {
10815            cx.propagate();
10816            return;
10817        }
10818
10819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10820        let selections = self
10821            .selections
10822            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10823            .into_iter()
10824            .map(|s| s.range());
10825
10826        self.transact(window, cx, |this, window, cx| {
10827            this.buffer.update(cx, |buffer, cx| {
10828                buffer.autoindent_ranges(selections, cx);
10829            });
10830            let selections = this
10831                .selections
10832                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10833            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10834        });
10835    }
10836
10837    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10839        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10840        let selections = self.selections.all::<Point>(&display_map);
10841
10842        let mut new_cursors = Vec::new();
10843        let mut edit_ranges = Vec::new();
10844        let mut selections = selections.iter().peekable();
10845        while let Some(selection) = selections.next() {
10846            let mut rows = selection.spanned_rows(false, &display_map);
10847
10848            // Accumulate contiguous regions of rows that we want to delete.
10849            while let Some(next_selection) = selections.peek() {
10850                let next_rows = next_selection.spanned_rows(false, &display_map);
10851                if next_rows.start <= rows.end {
10852                    rows.end = next_rows.end;
10853                    selections.next().unwrap();
10854                } else {
10855                    break;
10856                }
10857            }
10858
10859            let buffer = display_map.buffer_snapshot();
10860            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10861            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10862                // If there's a line after the range, delete the \n from the end of the row range
10863                (
10864                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10865                    rows.end,
10866                )
10867            } else {
10868                // If there isn't a line after the range, delete the \n from the line before the
10869                // start of the row range
10870                edit_start = edit_start.saturating_sub_usize(1);
10871                (buffer.len(), rows.start.previous_row())
10872            };
10873
10874            let text_layout_details = self.text_layout_details(window);
10875            let x = display_map.x_for_display_point(
10876                selection.head().to_display_point(&display_map),
10877                &text_layout_details,
10878            );
10879            let row = Point::new(target_row.0, 0)
10880                .to_display_point(&display_map)
10881                .row();
10882            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10883
10884            new_cursors.push((
10885                selection.id,
10886                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10887                SelectionGoal::None,
10888            ));
10889            edit_ranges.push(edit_start..edit_end);
10890        }
10891
10892        self.transact(window, cx, |this, window, cx| {
10893            let buffer = this.buffer.update(cx, |buffer, cx| {
10894                let empty_str: Arc<str> = Arc::default();
10895                buffer.edit(
10896                    edit_ranges
10897                        .into_iter()
10898                        .map(|range| (range, empty_str.clone())),
10899                    None,
10900                    cx,
10901                );
10902                buffer.snapshot(cx)
10903            });
10904            let new_selections = new_cursors
10905                .into_iter()
10906                .map(|(id, cursor, goal)| {
10907                    let cursor = cursor.to_point(&buffer);
10908                    Selection {
10909                        id,
10910                        start: cursor,
10911                        end: cursor,
10912                        reversed: false,
10913                        goal,
10914                    }
10915                })
10916                .collect();
10917
10918            this.change_selections(Default::default(), window, cx, |s| {
10919                s.select(new_selections);
10920            });
10921        });
10922    }
10923
10924    pub fn join_lines_impl(
10925        &mut self,
10926        insert_whitespace: bool,
10927        window: &mut Window,
10928        cx: &mut Context<Self>,
10929    ) {
10930        if self.read_only(cx) {
10931            return;
10932        }
10933        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10934        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10935            let start = MultiBufferRow(selection.start.row);
10936            // Treat single line selections as if they include the next line. Otherwise this action
10937            // would do nothing for single line selections individual cursors.
10938            let end = if selection.start.row == selection.end.row {
10939                MultiBufferRow(selection.start.row + 1)
10940            } else {
10941                MultiBufferRow(selection.end.row)
10942            };
10943
10944            if let Some(last_row_range) = row_ranges.last_mut()
10945                && start <= last_row_range.end
10946            {
10947                last_row_range.end = end;
10948                continue;
10949            }
10950            row_ranges.push(start..end);
10951        }
10952
10953        let snapshot = self.buffer.read(cx).snapshot(cx);
10954        let mut cursor_positions = Vec::new();
10955        for row_range in &row_ranges {
10956            let anchor = snapshot.anchor_before(Point::new(
10957                row_range.end.previous_row().0,
10958                snapshot.line_len(row_range.end.previous_row()),
10959            ));
10960            cursor_positions.push(anchor..anchor);
10961        }
10962
10963        self.transact(window, cx, |this, window, cx| {
10964            for row_range in row_ranges.into_iter().rev() {
10965                for row in row_range.iter_rows().rev() {
10966                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10967                    let next_line_row = row.next_row();
10968                    let indent = snapshot.indent_size_for_line(next_line_row);
10969                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10970
10971                    let replace =
10972                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10973                            " "
10974                        } else {
10975                            ""
10976                        };
10977
10978                    this.buffer.update(cx, |buffer, cx| {
10979                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10980                    });
10981                }
10982            }
10983
10984            this.change_selections(Default::default(), window, cx, |s| {
10985                s.select_anchor_ranges(cursor_positions)
10986            });
10987        });
10988    }
10989
10990    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10992        self.join_lines_impl(true, window, cx);
10993    }
10994
10995    pub fn sort_lines_case_sensitive(
10996        &mut self,
10997        _: &SortLinesCaseSensitive,
10998        window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11002    }
11003
11004    pub fn sort_lines_by_length(
11005        &mut self,
11006        _: &SortLinesByLength,
11007        window: &mut Window,
11008        cx: &mut Context<Self>,
11009    ) {
11010        self.manipulate_immutable_lines(window, cx, |lines| {
11011            lines.sort_by_key(|&line| line.chars().count())
11012        })
11013    }
11014
11015    pub fn sort_lines_case_insensitive(
11016        &mut self,
11017        _: &SortLinesCaseInsensitive,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) {
11021        self.manipulate_immutable_lines(window, cx, |lines| {
11022            lines.sort_by_key(|line| line.to_lowercase())
11023        })
11024    }
11025
11026    pub fn unique_lines_case_insensitive(
11027        &mut self,
11028        _: &UniqueLinesCaseInsensitive,
11029        window: &mut Window,
11030        cx: &mut Context<Self>,
11031    ) {
11032        self.manipulate_immutable_lines(window, cx, |lines| {
11033            let mut seen = HashSet::default();
11034            lines.retain(|line| seen.insert(line.to_lowercase()));
11035        })
11036    }
11037
11038    pub fn unique_lines_case_sensitive(
11039        &mut self,
11040        _: &UniqueLinesCaseSensitive,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) {
11044        self.manipulate_immutable_lines(window, cx, |lines| {
11045            let mut seen = HashSet::default();
11046            lines.retain(|line| seen.insert(*line));
11047        })
11048    }
11049
11050    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11051        let snapshot = self.buffer.read(cx).snapshot(cx);
11052        for selection in self.selections.disjoint_anchors_arc().iter() {
11053            if snapshot
11054                .language_at(selection.start)
11055                .and_then(|lang| lang.config().wrap_characters.as_ref())
11056                .is_some()
11057            {
11058                return true;
11059            }
11060        }
11061        false
11062    }
11063
11064    fn wrap_selections_in_tag(
11065        &mut self,
11066        _: &WrapSelectionsInTag,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) {
11070        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11071
11072        let snapshot = self.buffer.read(cx).snapshot(cx);
11073
11074        let mut edits = Vec::new();
11075        let mut boundaries = Vec::new();
11076
11077        for selection in self
11078            .selections
11079            .all_adjusted(&self.display_snapshot(cx))
11080            .iter()
11081        {
11082            let Some(wrap_config) = snapshot
11083                .language_at(selection.start)
11084                .and_then(|lang| lang.config().wrap_characters.clone())
11085            else {
11086                continue;
11087            };
11088
11089            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11090            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11091
11092            let start_before = snapshot.anchor_before(selection.start);
11093            let end_after = snapshot.anchor_after(selection.end);
11094
11095            edits.push((start_before..start_before, open_tag));
11096            edits.push((end_after..end_after, close_tag));
11097
11098            boundaries.push((
11099                start_before,
11100                end_after,
11101                wrap_config.start_prefix.len(),
11102                wrap_config.end_suffix.len(),
11103            ));
11104        }
11105
11106        if edits.is_empty() {
11107            return;
11108        }
11109
11110        self.transact(window, cx, |this, window, cx| {
11111            let buffer = this.buffer.update(cx, |buffer, cx| {
11112                buffer.edit(edits, None, cx);
11113                buffer.snapshot(cx)
11114            });
11115
11116            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11117            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11118                boundaries.into_iter()
11119            {
11120                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11121                let close_offset = end_after
11122                    .to_offset(&buffer)
11123                    .saturating_sub_usize(end_suffix_len);
11124                new_selections.push(open_offset..open_offset);
11125                new_selections.push(close_offset..close_offset);
11126            }
11127
11128            this.change_selections(Default::default(), window, cx, |s| {
11129                s.select_ranges(new_selections);
11130            });
11131
11132            this.request_autoscroll(Autoscroll::fit(), cx);
11133        });
11134    }
11135
11136    pub fn toggle_read_only(
11137        &mut self,
11138        _: &workspace::ToggleReadOnlyFile,
11139        _: &mut Window,
11140        cx: &mut Context<Self>,
11141    ) {
11142        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11143            buffer.update(cx, |buffer, cx| {
11144                buffer.set_capability(
11145                    match buffer.capability() {
11146                        Capability::ReadWrite => Capability::Read,
11147                        Capability::Read => Capability::ReadWrite,
11148                        Capability::ReadOnly => Capability::ReadOnly,
11149                    },
11150                    cx,
11151                );
11152            })
11153        }
11154    }
11155
11156    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11157        let Some(project) = self.project.clone() else {
11158            return;
11159        };
11160        self.reload(project, window, cx)
11161            .detach_and_notify_err(window, cx);
11162    }
11163
11164    pub fn restore_file(
11165        &mut self,
11166        _: &::git::RestoreFile,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11171        let mut buffer_ids = HashSet::default();
11172        let snapshot = self.buffer().read(cx).snapshot(cx);
11173        for selection in self
11174            .selections
11175            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11176        {
11177            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11178        }
11179
11180        let buffer = self.buffer().read(cx);
11181        let ranges = buffer_ids
11182            .into_iter()
11183            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11184            .collect::<Vec<_>>();
11185
11186        self.restore_hunks_in_ranges(ranges, window, cx);
11187    }
11188
11189    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11191        let selections = self
11192            .selections
11193            .all(&self.display_snapshot(cx))
11194            .into_iter()
11195            .map(|s| s.range())
11196            .collect();
11197        self.restore_hunks_in_ranges(selections, window, cx);
11198    }
11199
11200    pub fn restore_hunks_in_ranges(
11201        &mut self,
11202        ranges: Vec<Range<Point>>,
11203        window: &mut Window,
11204        cx: &mut Context<Editor>,
11205    ) {
11206        let mut revert_changes = HashMap::default();
11207        let chunk_by = self
11208            .snapshot(window, cx)
11209            .hunks_for_ranges(ranges)
11210            .into_iter()
11211            .chunk_by(|hunk| hunk.buffer_id);
11212        for (buffer_id, hunks) in &chunk_by {
11213            let hunks = hunks.collect::<Vec<_>>();
11214            for hunk in &hunks {
11215                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11216            }
11217            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11218        }
11219        drop(chunk_by);
11220        if !revert_changes.is_empty() {
11221            self.transact(window, cx, |editor, window, cx| {
11222                editor.restore(revert_changes, window, cx);
11223            });
11224        }
11225    }
11226
11227    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11228        if let Some(status) = self
11229            .addons
11230            .iter()
11231            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11232        {
11233            return Some(status);
11234        }
11235        self.project
11236            .as_ref()?
11237            .read(cx)
11238            .status_for_buffer_id(buffer_id, cx)
11239    }
11240
11241    pub fn open_active_item_in_terminal(
11242        &mut self,
11243        _: &OpenInTerminal,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11248            let project_path = buffer.read(cx).project_path(cx)?;
11249            let project = self.project()?.read(cx);
11250            let entry = project.entry_for_path(&project_path, cx)?;
11251            let parent = match &entry.canonical_path {
11252                Some(canonical_path) => canonical_path.to_path_buf(),
11253                None => project.absolute_path(&project_path, cx)?,
11254            }
11255            .parent()?
11256            .to_path_buf();
11257            Some(parent)
11258        }) {
11259            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11260        }
11261    }
11262
11263    fn set_breakpoint_context_menu(
11264        &mut self,
11265        display_row: DisplayRow,
11266        position: Option<Anchor>,
11267        clicked_point: gpui::Point<Pixels>,
11268        window: &mut Window,
11269        cx: &mut Context<Self>,
11270    ) {
11271        let source = self
11272            .buffer
11273            .read(cx)
11274            .snapshot(cx)
11275            .anchor_before(Point::new(display_row.0, 0u32));
11276
11277        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11278
11279        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11280            self,
11281            source,
11282            clicked_point,
11283            context_menu,
11284            window,
11285            cx,
11286        );
11287    }
11288
11289    fn add_edit_breakpoint_block(
11290        &mut self,
11291        anchor: Anchor,
11292        breakpoint: &Breakpoint,
11293        edit_action: BreakpointPromptEditAction,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        let weak_editor = cx.weak_entity();
11298        let bp_prompt = cx.new(|cx| {
11299            BreakpointPromptEditor::new(
11300                weak_editor,
11301                anchor,
11302                breakpoint.clone(),
11303                edit_action,
11304                window,
11305                cx,
11306            )
11307        });
11308
11309        let height = bp_prompt.update(cx, |this, cx| {
11310            this.prompt
11311                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11312        });
11313        let cloned_prompt = bp_prompt.clone();
11314        let blocks = vec![BlockProperties {
11315            style: BlockStyle::Sticky,
11316            placement: BlockPlacement::Above(anchor),
11317            height: Some(height),
11318            render: Arc::new(move |cx| {
11319                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11320                cloned_prompt.clone().into_any_element()
11321            }),
11322            priority: 0,
11323        }];
11324
11325        let focus_handle = bp_prompt.focus_handle(cx);
11326        window.focus(&focus_handle, cx);
11327
11328        let block_ids = self.insert_blocks(blocks, None, cx);
11329        bp_prompt.update(cx, |prompt, _| {
11330            prompt.add_block_ids(block_ids);
11331        });
11332    }
11333
11334    pub(crate) fn breakpoint_at_row(
11335        &self,
11336        row: u32,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) -> Option<(Anchor, Breakpoint)> {
11340        let snapshot = self.snapshot(window, cx);
11341        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11342
11343        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11344    }
11345
11346    pub(crate) fn breakpoint_at_anchor(
11347        &self,
11348        breakpoint_position: Anchor,
11349        snapshot: &EditorSnapshot,
11350        cx: &mut Context<Self>,
11351    ) -> Option<(Anchor, Breakpoint)> {
11352        let buffer = self
11353            .buffer
11354            .read(cx)
11355            .buffer_for_anchor(breakpoint_position, cx)?;
11356
11357        let enclosing_excerpt = breakpoint_position.excerpt_id;
11358        let buffer_snapshot = buffer.read(cx).snapshot();
11359
11360        let row = buffer_snapshot
11361            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11362            .row;
11363
11364        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11365        let anchor_end = snapshot
11366            .buffer_snapshot()
11367            .anchor_after(Point::new(row, line_len));
11368
11369        self.breakpoint_store
11370            .as_ref()?
11371            .read_with(cx, |breakpoint_store, cx| {
11372                breakpoint_store
11373                    .breakpoints(
11374                        &buffer,
11375                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11376                        &buffer_snapshot,
11377                        cx,
11378                    )
11379                    .next()
11380                    .and_then(|(bp, _)| {
11381                        let breakpoint_row = buffer_snapshot
11382                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11383                            .row;
11384
11385                        if breakpoint_row == row {
11386                            snapshot
11387                                .buffer_snapshot()
11388                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11389                                .map(|position| (position, bp.bp.clone()))
11390                        } else {
11391                            None
11392                        }
11393                    })
11394            })
11395    }
11396
11397    pub fn edit_log_breakpoint(
11398        &mut self,
11399        _: &EditLogBreakpoint,
11400        window: &mut Window,
11401        cx: &mut Context<Self>,
11402    ) {
11403        if self.breakpoint_store.is_none() {
11404            return;
11405        }
11406
11407        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11408            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11409                message: None,
11410                state: BreakpointState::Enabled,
11411                condition: None,
11412                hit_condition: None,
11413            });
11414
11415            self.add_edit_breakpoint_block(
11416                anchor,
11417                &breakpoint,
11418                BreakpointPromptEditAction::Log,
11419                window,
11420                cx,
11421            );
11422        }
11423    }
11424
11425    fn breakpoints_at_cursors(
11426        &self,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11430        let snapshot = self.snapshot(window, cx);
11431        let cursors = self
11432            .selections
11433            .disjoint_anchors_arc()
11434            .iter()
11435            .map(|selection| {
11436                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11437
11438                let breakpoint_position = self
11439                    .breakpoint_at_row(cursor_position.row, window, cx)
11440                    .map(|bp| bp.0)
11441                    .unwrap_or_else(|| {
11442                        snapshot
11443                            .display_snapshot
11444                            .buffer_snapshot()
11445                            .anchor_after(Point::new(cursor_position.row, 0))
11446                    });
11447
11448                let breakpoint = self
11449                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11450                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11451
11452                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11453            })
11454            // 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.
11455            .collect::<HashMap<Anchor, _>>();
11456
11457        cursors.into_iter().collect()
11458    }
11459
11460    pub fn enable_breakpoint(
11461        &mut self,
11462        _: &crate::actions::EnableBreakpoint,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        if self.breakpoint_store.is_none() {
11467            return;
11468        }
11469
11470        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11471            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11472                continue;
11473            };
11474            self.edit_breakpoint_at_anchor(
11475                anchor,
11476                breakpoint,
11477                BreakpointEditAction::InvertState,
11478                cx,
11479            );
11480        }
11481    }
11482
11483    pub fn disable_breakpoint(
11484        &mut self,
11485        _: &crate::actions::DisableBreakpoint,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        if self.breakpoint_store.is_none() {
11490            return;
11491        }
11492
11493        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11494            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11495                continue;
11496            };
11497            self.edit_breakpoint_at_anchor(
11498                anchor,
11499                breakpoint,
11500                BreakpointEditAction::InvertState,
11501                cx,
11502            );
11503        }
11504    }
11505
11506    pub fn toggle_breakpoint(
11507        &mut self,
11508        _: &crate::actions::ToggleBreakpoint,
11509        window: &mut Window,
11510        cx: &mut Context<Self>,
11511    ) {
11512        if self.breakpoint_store.is_none() {
11513            return;
11514        }
11515
11516        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11517            if let Some(breakpoint) = breakpoint {
11518                self.edit_breakpoint_at_anchor(
11519                    anchor,
11520                    breakpoint,
11521                    BreakpointEditAction::Toggle,
11522                    cx,
11523                );
11524            } else {
11525                self.edit_breakpoint_at_anchor(
11526                    anchor,
11527                    Breakpoint::new_standard(),
11528                    BreakpointEditAction::Toggle,
11529                    cx,
11530                );
11531            }
11532        }
11533    }
11534
11535    pub fn edit_breakpoint_at_anchor(
11536        &mut self,
11537        breakpoint_position: Anchor,
11538        breakpoint: Breakpoint,
11539        edit_action: BreakpointEditAction,
11540        cx: &mut Context<Self>,
11541    ) {
11542        let Some(breakpoint_store) = &self.breakpoint_store else {
11543            return;
11544        };
11545
11546        let Some(buffer) = self
11547            .buffer
11548            .read(cx)
11549            .buffer_for_anchor(breakpoint_position, cx)
11550        else {
11551            return;
11552        };
11553
11554        breakpoint_store.update(cx, |breakpoint_store, cx| {
11555            breakpoint_store.toggle_breakpoint(
11556                buffer,
11557                BreakpointWithPosition {
11558                    position: breakpoint_position.text_anchor,
11559                    bp: breakpoint,
11560                },
11561                edit_action,
11562                cx,
11563            );
11564        });
11565
11566        cx.notify();
11567    }
11568
11569    #[cfg(any(test, feature = "test-support"))]
11570    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11571        self.breakpoint_store.clone()
11572    }
11573
11574    pub fn prepare_restore_change(
11575        &self,
11576        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11577        hunk: &MultiBufferDiffHunk,
11578        cx: &mut App,
11579    ) -> Option<()> {
11580        if hunk.is_created_file() {
11581            return None;
11582        }
11583        let buffer = self.buffer.read(cx);
11584        let diff = buffer.diff_for(hunk.buffer_id)?;
11585        let buffer = buffer.buffer(hunk.buffer_id)?;
11586        let buffer = buffer.read(cx);
11587        let original_text = diff
11588            .read(cx)
11589            .base_text(cx)
11590            .as_rope()
11591            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11592        let buffer_snapshot = buffer.snapshot();
11593        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11594        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11595            probe
11596                .0
11597                .start
11598                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11599                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11600        }) {
11601            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11602            Some(())
11603        } else {
11604            None
11605        }
11606    }
11607
11608    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11609        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11610    }
11611
11612    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11613        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11614    }
11615
11616    pub fn rotate_selections_forward(
11617        &mut self,
11618        _: &RotateSelectionsForward,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        self.rotate_selections(window, cx, false)
11623    }
11624
11625    pub fn rotate_selections_backward(
11626        &mut self,
11627        _: &RotateSelectionsBackward,
11628        window: &mut Window,
11629        cx: &mut Context<Self>,
11630    ) {
11631        self.rotate_selections(window, cx, true)
11632    }
11633
11634    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11635        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11636        let display_snapshot = self.display_snapshot(cx);
11637        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11638
11639        if selections.len() < 2 {
11640            return;
11641        }
11642
11643        let (edits, new_selections) = {
11644            let buffer = self.buffer.read(cx).read(cx);
11645            let has_selections = selections.iter().any(|s| !s.is_empty());
11646            if has_selections {
11647                let mut selected_texts: Vec<String> = selections
11648                    .iter()
11649                    .map(|selection| {
11650                        buffer
11651                            .text_for_range(selection.start..selection.end)
11652                            .collect()
11653                    })
11654                    .collect();
11655
11656                if reverse {
11657                    selected_texts.rotate_left(1);
11658                } else {
11659                    selected_texts.rotate_right(1);
11660                }
11661
11662                let mut offset_delta: i64 = 0;
11663                let mut new_selections = Vec::new();
11664                let edits: Vec<_> = selections
11665                    .iter()
11666                    .zip(selected_texts.iter())
11667                    .map(|(selection, new_text)| {
11668                        let old_len = (selection.end.0 - selection.start.0) as i64;
11669                        let new_len = new_text.len() as i64;
11670                        let adjusted_start =
11671                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11672                        let adjusted_end =
11673                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11674
11675                        new_selections.push(Selection {
11676                            id: selection.id,
11677                            start: adjusted_start,
11678                            end: adjusted_end,
11679                            reversed: selection.reversed,
11680                            goal: selection.goal,
11681                        });
11682
11683                        offset_delta += new_len - old_len;
11684                        (selection.start..selection.end, new_text.clone())
11685                    })
11686                    .collect();
11687                (edits, new_selections)
11688            } else {
11689                let mut all_rows: Vec<u32> = selections
11690                    .iter()
11691                    .map(|selection| buffer.offset_to_point(selection.start).row)
11692                    .collect();
11693                all_rows.sort_unstable();
11694                all_rows.dedup();
11695
11696                if all_rows.len() < 2 {
11697                    return;
11698                }
11699
11700                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11701                    .iter()
11702                    .map(|&row| {
11703                        let start = Point::new(row, 0);
11704                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11705                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11706                    })
11707                    .collect();
11708
11709                let mut line_texts: Vec<String> = line_ranges
11710                    .iter()
11711                    .map(|range| buffer.text_for_range(range.clone()).collect())
11712                    .collect();
11713
11714                if reverse {
11715                    line_texts.rotate_left(1);
11716                } else {
11717                    line_texts.rotate_right(1);
11718                }
11719
11720                let edits = line_ranges
11721                    .iter()
11722                    .zip(line_texts.iter())
11723                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11724                    .collect();
11725
11726                let num_rows = all_rows.len();
11727                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11728                    .iter()
11729                    .enumerate()
11730                    .map(|(i, &row)| (row, i))
11731                    .collect();
11732
11733                // Compute new line start offsets after rotation (handles CRLF)
11734                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11735                let first_line_start = line_ranges[0].start.0;
11736                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11737                for text in line_texts.iter().take(num_rows - 1) {
11738                    let prev_start = *new_line_starts.last().unwrap();
11739                    new_line_starts.push(prev_start + text.len() + newline_len);
11740                }
11741
11742                let new_selections = selections
11743                    .iter()
11744                    .map(|selection| {
11745                        let point = buffer.offset_to_point(selection.start);
11746                        let old_index = row_to_index[&point.row];
11747                        let new_index = if reverse {
11748                            (old_index + num_rows - 1) % num_rows
11749                        } else {
11750                            (old_index + 1) % num_rows
11751                        };
11752                        let new_offset =
11753                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11754                        Selection {
11755                            id: selection.id,
11756                            start: new_offset,
11757                            end: new_offset,
11758                            reversed: selection.reversed,
11759                            goal: selection.goal,
11760                        }
11761                    })
11762                    .collect();
11763
11764                (edits, new_selections)
11765            }
11766        };
11767
11768        self.transact(window, cx, |this, window, cx| {
11769            this.buffer.update(cx, |buffer, cx| {
11770                buffer.edit(edits, None, cx);
11771            });
11772            this.change_selections(Default::default(), window, cx, |s| {
11773                s.select(new_selections);
11774            });
11775        });
11776    }
11777
11778    fn manipulate_lines<M>(
11779        &mut self,
11780        window: &mut Window,
11781        cx: &mut Context<Self>,
11782        mut manipulate: M,
11783    ) where
11784        M: FnMut(&str) -> LineManipulationResult,
11785    {
11786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11787
11788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11789        let buffer = self.buffer.read(cx).snapshot(cx);
11790
11791        let mut edits = Vec::new();
11792
11793        let selections = self.selections.all::<Point>(&display_map);
11794        let mut selections = selections.iter().peekable();
11795        let mut contiguous_row_selections = Vec::new();
11796        let mut new_selections = Vec::new();
11797        let mut added_lines = 0;
11798        let mut removed_lines = 0;
11799
11800        while let Some(selection) = selections.next() {
11801            let (start_row, end_row) = consume_contiguous_rows(
11802                &mut contiguous_row_selections,
11803                selection,
11804                &display_map,
11805                &mut selections,
11806            );
11807
11808            let start_point = Point::new(start_row.0, 0);
11809            let end_point = Point::new(
11810                end_row.previous_row().0,
11811                buffer.line_len(end_row.previous_row()),
11812            );
11813            let text = buffer
11814                .text_for_range(start_point..end_point)
11815                .collect::<String>();
11816
11817            let LineManipulationResult {
11818                new_text,
11819                line_count_before,
11820                line_count_after,
11821            } = manipulate(&text);
11822
11823            edits.push((start_point..end_point, new_text));
11824
11825            // Selections must change based on added and removed line count
11826            let start_row =
11827                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11828            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11829            new_selections.push(Selection {
11830                id: selection.id,
11831                start: start_row,
11832                end: end_row,
11833                goal: SelectionGoal::None,
11834                reversed: selection.reversed,
11835            });
11836
11837            if line_count_after > line_count_before {
11838                added_lines += line_count_after - line_count_before;
11839            } else if line_count_before > line_count_after {
11840                removed_lines += line_count_before - line_count_after;
11841            }
11842        }
11843
11844        self.transact(window, cx, |this, window, cx| {
11845            let buffer = this.buffer.update(cx, |buffer, cx| {
11846                buffer.edit(edits, None, cx);
11847                buffer.snapshot(cx)
11848            });
11849
11850            // Recalculate offsets on newly edited buffer
11851            let new_selections = new_selections
11852                .iter()
11853                .map(|s| {
11854                    let start_point = Point::new(s.start.0, 0);
11855                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11856                    Selection {
11857                        id: s.id,
11858                        start: buffer.point_to_offset(start_point),
11859                        end: buffer.point_to_offset(end_point),
11860                        goal: s.goal,
11861                        reversed: s.reversed,
11862                    }
11863                })
11864                .collect();
11865
11866            this.change_selections(Default::default(), window, cx, |s| {
11867                s.select(new_selections);
11868            });
11869
11870            this.request_autoscroll(Autoscroll::fit(), cx);
11871        });
11872    }
11873
11874    fn manipulate_immutable_lines<Fn>(
11875        &mut self,
11876        window: &mut Window,
11877        cx: &mut Context<Self>,
11878        mut callback: Fn,
11879    ) where
11880        Fn: FnMut(&mut Vec<&str>),
11881    {
11882        self.manipulate_lines(window, cx, |text| {
11883            let mut lines: Vec<&str> = text.split('\n').collect();
11884            let line_count_before = lines.len();
11885
11886            callback(&mut lines);
11887
11888            LineManipulationResult {
11889                new_text: lines.join("\n"),
11890                line_count_before,
11891                line_count_after: lines.len(),
11892            }
11893        });
11894    }
11895
11896    fn manipulate_mutable_lines<Fn>(
11897        &mut self,
11898        window: &mut Window,
11899        cx: &mut Context<Self>,
11900        mut callback: Fn,
11901    ) where
11902        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11903    {
11904        self.manipulate_lines(window, cx, |text| {
11905            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11906            let line_count_before = lines.len();
11907
11908            callback(&mut lines);
11909
11910            LineManipulationResult {
11911                new_text: lines.join("\n"),
11912                line_count_before,
11913                line_count_after: lines.len(),
11914            }
11915        });
11916    }
11917
11918    pub fn convert_indentation_to_spaces(
11919        &mut self,
11920        _: &ConvertIndentationToSpaces,
11921        window: &mut Window,
11922        cx: &mut Context<Self>,
11923    ) {
11924        let settings = self.buffer.read(cx).language_settings(cx);
11925        let tab_size = settings.tab_size.get() as usize;
11926
11927        self.manipulate_mutable_lines(window, cx, |lines| {
11928            // Allocates a reasonably sized scratch buffer once for the whole loop
11929            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11930            // Avoids recomputing spaces that could be inserted many times
11931            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11932                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11933                .collect();
11934
11935            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11936                let mut chars = line.as_ref().chars();
11937                let mut col = 0;
11938                let mut changed = false;
11939
11940                for ch in chars.by_ref() {
11941                    match ch {
11942                        ' ' => {
11943                            reindented_line.push(' ');
11944                            col += 1;
11945                        }
11946                        '\t' => {
11947                            // \t are converted to spaces depending on the current column
11948                            let spaces_len = tab_size - (col % tab_size);
11949                            reindented_line.extend(&space_cache[spaces_len - 1]);
11950                            col += spaces_len;
11951                            changed = true;
11952                        }
11953                        _ => {
11954                            // If we dont append before break, the character is consumed
11955                            reindented_line.push(ch);
11956                            break;
11957                        }
11958                    }
11959                }
11960
11961                if !changed {
11962                    reindented_line.clear();
11963                    continue;
11964                }
11965                // Append the rest of the line and replace old reference with new one
11966                reindented_line.extend(chars);
11967                *line = Cow::Owned(reindented_line.clone());
11968                reindented_line.clear();
11969            }
11970        });
11971    }
11972
11973    pub fn convert_indentation_to_tabs(
11974        &mut self,
11975        _: &ConvertIndentationToTabs,
11976        window: &mut Window,
11977        cx: &mut Context<Self>,
11978    ) {
11979        let settings = self.buffer.read(cx).language_settings(cx);
11980        let tab_size = settings.tab_size.get() as usize;
11981
11982        self.manipulate_mutable_lines(window, cx, |lines| {
11983            // Allocates a reasonably sized buffer once for the whole loop
11984            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11985            // Avoids recomputing spaces that could be inserted many times
11986            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11987                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11988                .collect();
11989
11990            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11991                let mut chars = line.chars();
11992                let mut spaces_count = 0;
11993                let mut first_non_indent_char = None;
11994                let mut changed = false;
11995
11996                for ch in chars.by_ref() {
11997                    match ch {
11998                        ' ' => {
11999                            // Keep track of spaces. Append \t when we reach tab_size
12000                            spaces_count += 1;
12001                            changed = true;
12002                            if spaces_count == tab_size {
12003                                reindented_line.push('\t');
12004                                spaces_count = 0;
12005                            }
12006                        }
12007                        '\t' => {
12008                            reindented_line.push('\t');
12009                            spaces_count = 0;
12010                        }
12011                        _ => {
12012                            // Dont append it yet, we might have remaining spaces
12013                            first_non_indent_char = Some(ch);
12014                            break;
12015                        }
12016                    }
12017                }
12018
12019                if !changed {
12020                    reindented_line.clear();
12021                    continue;
12022                }
12023                // Remaining spaces that didn't make a full tab stop
12024                if spaces_count > 0 {
12025                    reindented_line.extend(&space_cache[spaces_count - 1]);
12026                }
12027                // If we consume an extra character that was not indentation, add it back
12028                if let Some(extra_char) = first_non_indent_char {
12029                    reindented_line.push(extra_char);
12030                }
12031                // Append the rest of the line and replace old reference with new one
12032                reindented_line.extend(chars);
12033                *line = Cow::Owned(reindented_line.clone());
12034                reindented_line.clear();
12035            }
12036        });
12037    }
12038
12039    pub fn convert_to_upper_case(
12040        &mut self,
12041        _: &ConvertToUpperCase,
12042        window: &mut Window,
12043        cx: &mut Context<Self>,
12044    ) {
12045        self.manipulate_text(window, cx, |text| text.to_uppercase())
12046    }
12047
12048    pub fn convert_to_lower_case(
12049        &mut self,
12050        _: &ConvertToLowerCase,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.manipulate_text(window, cx, |text| text.to_lowercase())
12055    }
12056
12057    pub fn convert_to_title_case(
12058        &mut self,
12059        _: &ConvertToTitleCase,
12060        window: &mut Window,
12061        cx: &mut Context<Self>,
12062    ) {
12063        self.manipulate_text(window, cx, |text| {
12064            text.split('\n')
12065                .map(|line| line.to_case(Case::Title))
12066                .join("\n")
12067        })
12068    }
12069
12070    pub fn convert_to_snake_case(
12071        &mut self,
12072        _: &ConvertToSnakeCase,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12077    }
12078
12079    pub fn convert_to_kebab_case(
12080        &mut self,
12081        _: &ConvertToKebabCase,
12082        window: &mut Window,
12083        cx: &mut Context<Self>,
12084    ) {
12085        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12086    }
12087
12088    pub fn convert_to_upper_camel_case(
12089        &mut self,
12090        _: &ConvertToUpperCamelCase,
12091        window: &mut Window,
12092        cx: &mut Context<Self>,
12093    ) {
12094        self.manipulate_text(window, cx, |text| {
12095            text.split('\n')
12096                .map(|line| line.to_case(Case::UpperCamel))
12097                .join("\n")
12098        })
12099    }
12100
12101    pub fn convert_to_lower_camel_case(
12102        &mut self,
12103        _: &ConvertToLowerCamelCase,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12108    }
12109
12110    pub fn convert_to_opposite_case(
12111        &mut self,
12112        _: &ConvertToOppositeCase,
12113        window: &mut Window,
12114        cx: &mut Context<Self>,
12115    ) {
12116        self.manipulate_text(window, cx, |text| {
12117            text.chars()
12118                .fold(String::with_capacity(text.len()), |mut t, c| {
12119                    if c.is_uppercase() {
12120                        t.extend(c.to_lowercase());
12121                    } else {
12122                        t.extend(c.to_uppercase());
12123                    }
12124                    t
12125                })
12126        })
12127    }
12128
12129    pub fn convert_to_sentence_case(
12130        &mut self,
12131        _: &ConvertToSentenceCase,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12136    }
12137
12138    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12139        self.manipulate_text(window, cx, |text| {
12140            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12141            if has_upper_case_characters {
12142                text.to_lowercase()
12143            } else {
12144                text.to_uppercase()
12145            }
12146        })
12147    }
12148
12149    pub fn convert_to_rot13(
12150        &mut self,
12151        _: &ConvertToRot13,
12152        window: &mut Window,
12153        cx: &mut Context<Self>,
12154    ) {
12155        self.manipulate_text(window, cx, |text| {
12156            text.chars()
12157                .map(|c| match c {
12158                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12159                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12160                    _ => c,
12161                })
12162                .collect()
12163        })
12164    }
12165
12166    pub fn convert_to_rot47(
12167        &mut self,
12168        _: &ConvertToRot47,
12169        window: &mut Window,
12170        cx: &mut Context<Self>,
12171    ) {
12172        self.manipulate_text(window, cx, |text| {
12173            text.chars()
12174                .map(|c| {
12175                    let code_point = c as u32;
12176                    if code_point >= 33 && code_point <= 126 {
12177                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12178                    }
12179                    c
12180                })
12181                .collect()
12182        })
12183    }
12184
12185    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12186    where
12187        Fn: FnMut(&str) -> String,
12188    {
12189        let buffer = self.buffer.read(cx).snapshot(cx);
12190
12191        let mut new_selections = Vec::new();
12192        let mut edits = Vec::new();
12193        let mut selection_adjustment = 0isize;
12194
12195        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12196            let selection_is_empty = selection.is_empty();
12197
12198            let (start, end) = if selection_is_empty {
12199                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12200                (word_range.start, word_range.end)
12201            } else {
12202                (
12203                    buffer.point_to_offset(selection.start),
12204                    buffer.point_to_offset(selection.end),
12205                )
12206            };
12207
12208            let text = buffer.text_for_range(start..end).collect::<String>();
12209            let old_length = text.len() as isize;
12210            let text = callback(&text);
12211
12212            new_selections.push(Selection {
12213                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12214                end: MultiBufferOffset(
12215                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12216                ),
12217                goal: SelectionGoal::None,
12218                id: selection.id,
12219                reversed: selection.reversed,
12220            });
12221
12222            selection_adjustment += old_length - text.len() as isize;
12223
12224            edits.push((start..end, text));
12225        }
12226
12227        self.transact(window, cx, |this, window, cx| {
12228            this.buffer.update(cx, |buffer, cx| {
12229                buffer.edit(edits, None, cx);
12230            });
12231
12232            this.change_selections(Default::default(), window, cx, |s| {
12233                s.select(new_selections);
12234            });
12235
12236            this.request_autoscroll(Autoscroll::fit(), cx);
12237        });
12238    }
12239
12240    pub fn move_selection_on_drop(
12241        &mut self,
12242        selection: &Selection<Anchor>,
12243        target: DisplayPoint,
12244        is_cut: bool,
12245        window: &mut Window,
12246        cx: &mut Context<Self>,
12247    ) {
12248        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12249        let buffer = display_map.buffer_snapshot();
12250        let mut edits = Vec::new();
12251        let insert_point = display_map
12252            .clip_point(target, Bias::Left)
12253            .to_point(&display_map);
12254        let text = buffer
12255            .text_for_range(selection.start..selection.end)
12256            .collect::<String>();
12257        if is_cut {
12258            edits.push(((selection.start..selection.end), String::new()));
12259        }
12260        let insert_anchor = buffer.anchor_before(insert_point);
12261        edits.push(((insert_anchor..insert_anchor), text));
12262        let last_edit_start = insert_anchor.bias_left(buffer);
12263        let last_edit_end = insert_anchor.bias_right(buffer);
12264        self.transact(window, cx, |this, window, cx| {
12265            this.buffer.update(cx, |buffer, cx| {
12266                buffer.edit(edits, None, cx);
12267            });
12268            this.change_selections(Default::default(), window, cx, |s| {
12269                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12270            });
12271        });
12272    }
12273
12274    pub fn clear_selection_drag_state(&mut self) {
12275        self.selection_drag_state = SelectionDragState::None;
12276    }
12277
12278    pub fn duplicate(
12279        &mut self,
12280        upwards: bool,
12281        whole_lines: bool,
12282        window: &mut Window,
12283        cx: &mut Context<Self>,
12284    ) {
12285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12286
12287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12288        let buffer = display_map.buffer_snapshot();
12289        let selections = self.selections.all::<Point>(&display_map);
12290
12291        let mut edits = Vec::new();
12292        let mut selections_iter = selections.iter().peekable();
12293        while let Some(selection) = selections_iter.next() {
12294            let mut rows = selection.spanned_rows(false, &display_map);
12295            // duplicate line-wise
12296            if whole_lines || selection.start == selection.end {
12297                // Avoid duplicating the same lines twice.
12298                while let Some(next_selection) = selections_iter.peek() {
12299                    let next_rows = next_selection.spanned_rows(false, &display_map);
12300                    if next_rows.start < rows.end {
12301                        rows.end = next_rows.end;
12302                        selections_iter.next().unwrap();
12303                    } else {
12304                        break;
12305                    }
12306                }
12307
12308                // Copy the text from the selected row region and splice it either at the start
12309                // or end of the region.
12310                let start = Point::new(rows.start.0, 0);
12311                let end = Point::new(
12312                    rows.end.previous_row().0,
12313                    buffer.line_len(rows.end.previous_row()),
12314                );
12315
12316                let mut text = buffer.text_for_range(start..end).collect::<String>();
12317
12318                let insert_location = if upwards {
12319                    // When duplicating upward, we need to insert before the current line.
12320                    // If we're on the last line and it doesn't end with a newline,
12321                    // we need to add a newline before the duplicated content.
12322                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12323                        && buffer.max_point().column > 0
12324                        && !text.ends_with('\n');
12325
12326                    if needs_leading_newline {
12327                        text.insert(0, '\n');
12328                        end
12329                    } else {
12330                        text.push('\n');
12331                        Point::new(rows.start.0, 0)
12332                    }
12333                } else {
12334                    text.push('\n');
12335                    start
12336                };
12337                edits.push((insert_location..insert_location, text));
12338            } else {
12339                // duplicate character-wise
12340                let start = selection.start;
12341                let end = selection.end;
12342                let text = buffer.text_for_range(start..end).collect::<String>();
12343                edits.push((selection.end..selection.end, text));
12344            }
12345        }
12346
12347        self.transact(window, cx, |this, window, cx| {
12348            this.buffer.update(cx, |buffer, cx| {
12349                buffer.edit(edits, None, cx);
12350            });
12351
12352            // When duplicating upward with whole lines, move the cursor to the duplicated line
12353            if upwards && whole_lines {
12354                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12355
12356                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12357                    let mut new_ranges = Vec::new();
12358                    let selections = s.all::<Point>(&display_map);
12359                    let mut selections_iter = selections.iter().peekable();
12360
12361                    while let Some(first_selection) = selections_iter.next() {
12362                        // Group contiguous selections together to find the total row span
12363                        let mut group_selections = vec![first_selection];
12364                        let mut rows = first_selection.spanned_rows(false, &display_map);
12365
12366                        while let Some(next_selection) = selections_iter.peek() {
12367                            let next_rows = next_selection.spanned_rows(false, &display_map);
12368                            if next_rows.start < rows.end {
12369                                rows.end = next_rows.end;
12370                                group_selections.push(selections_iter.next().unwrap());
12371                            } else {
12372                                break;
12373                            }
12374                        }
12375
12376                        let row_count = rows.end.0 - rows.start.0;
12377
12378                        // Move all selections in this group up by the total number of duplicated rows
12379                        for selection in group_selections {
12380                            let new_start = Point::new(
12381                                selection.start.row.saturating_sub(row_count),
12382                                selection.start.column,
12383                            );
12384
12385                            let new_end = Point::new(
12386                                selection.end.row.saturating_sub(row_count),
12387                                selection.end.column,
12388                            );
12389
12390                            new_ranges.push(new_start..new_end);
12391                        }
12392                    }
12393
12394                    s.select_ranges(new_ranges);
12395                });
12396            }
12397
12398            this.request_autoscroll(Autoscroll::fit(), cx);
12399        });
12400    }
12401
12402    pub fn duplicate_line_up(
12403        &mut self,
12404        _: &DuplicateLineUp,
12405        window: &mut Window,
12406        cx: &mut Context<Self>,
12407    ) {
12408        self.duplicate(true, true, window, cx);
12409    }
12410
12411    pub fn duplicate_line_down(
12412        &mut self,
12413        _: &DuplicateLineDown,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        self.duplicate(false, true, window, cx);
12418    }
12419
12420    pub fn duplicate_selection(
12421        &mut self,
12422        _: &DuplicateSelection,
12423        window: &mut Window,
12424        cx: &mut Context<Self>,
12425    ) {
12426        self.duplicate(false, false, window, cx);
12427    }
12428
12429    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12431        if self.mode.is_single_line() {
12432            cx.propagate();
12433            return;
12434        }
12435
12436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12437        let buffer = self.buffer.read(cx).snapshot(cx);
12438
12439        let mut edits = Vec::new();
12440        let mut unfold_ranges = Vec::new();
12441        let mut refold_creases = Vec::new();
12442
12443        let selections = self.selections.all::<Point>(&display_map);
12444        let mut selections = selections.iter().peekable();
12445        let mut contiguous_row_selections = Vec::new();
12446        let mut new_selections = Vec::new();
12447
12448        while let Some(selection) = selections.next() {
12449            // Find all the selections that span a contiguous row range
12450            let (start_row, end_row) = consume_contiguous_rows(
12451                &mut contiguous_row_selections,
12452                selection,
12453                &display_map,
12454                &mut selections,
12455            );
12456
12457            // Move the text spanned by the row range to be before the line preceding the row range
12458            if start_row.0 > 0 {
12459                let range_to_move = Point::new(
12460                    start_row.previous_row().0,
12461                    buffer.line_len(start_row.previous_row()),
12462                )
12463                    ..Point::new(
12464                        end_row.previous_row().0,
12465                        buffer.line_len(end_row.previous_row()),
12466                    );
12467                let insertion_point = display_map
12468                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12469                    .0;
12470
12471                // Don't move lines across excerpts
12472                if buffer
12473                    .excerpt_containing(insertion_point..range_to_move.end)
12474                    .is_some()
12475                {
12476                    let text = buffer
12477                        .text_for_range(range_to_move.clone())
12478                        .flat_map(|s| s.chars())
12479                        .skip(1)
12480                        .chain(['\n'])
12481                        .collect::<String>();
12482
12483                    edits.push((
12484                        buffer.anchor_after(range_to_move.start)
12485                            ..buffer.anchor_before(range_to_move.end),
12486                        String::new(),
12487                    ));
12488                    let insertion_anchor = buffer.anchor_after(insertion_point);
12489                    edits.push((insertion_anchor..insertion_anchor, text));
12490
12491                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12492
12493                    // Move selections up
12494                    new_selections.extend(contiguous_row_selections.drain(..).map(
12495                        |mut selection| {
12496                            selection.start.row -= row_delta;
12497                            selection.end.row -= row_delta;
12498                            selection
12499                        },
12500                    ));
12501
12502                    // Move folds up
12503                    unfold_ranges.push(range_to_move.clone());
12504                    for fold in display_map.folds_in_range(
12505                        buffer.anchor_before(range_to_move.start)
12506                            ..buffer.anchor_after(range_to_move.end),
12507                    ) {
12508                        let mut start = fold.range.start.to_point(&buffer);
12509                        let mut end = fold.range.end.to_point(&buffer);
12510                        start.row -= row_delta;
12511                        end.row -= row_delta;
12512                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12513                    }
12514                }
12515            }
12516
12517            // If we didn't move line(s), preserve the existing selections
12518            new_selections.append(&mut contiguous_row_selections);
12519        }
12520
12521        self.transact(window, cx, |this, window, cx| {
12522            this.unfold_ranges(&unfold_ranges, true, true, cx);
12523            this.buffer.update(cx, |buffer, cx| {
12524                for (range, text) in edits {
12525                    buffer.edit([(range, text)], None, cx);
12526                }
12527            });
12528            this.fold_creases(refold_creases, true, window, cx);
12529            this.change_selections(Default::default(), window, cx, |s| {
12530                s.select(new_selections);
12531            })
12532        });
12533    }
12534
12535    pub fn move_line_down(
12536        &mut self,
12537        _: &MoveLineDown,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12542        if self.mode.is_single_line() {
12543            cx.propagate();
12544            return;
12545        }
12546
12547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12548        let buffer = self.buffer.read(cx).snapshot(cx);
12549
12550        let mut edits = Vec::new();
12551        let mut unfold_ranges = Vec::new();
12552        let mut refold_creases = Vec::new();
12553
12554        let selections = self.selections.all::<Point>(&display_map);
12555        let mut selections = selections.iter().peekable();
12556        let mut contiguous_row_selections = Vec::new();
12557        let mut new_selections = Vec::new();
12558
12559        while let Some(selection) = selections.next() {
12560            // Find all the selections that span a contiguous row range
12561            let (start_row, end_row) = consume_contiguous_rows(
12562                &mut contiguous_row_selections,
12563                selection,
12564                &display_map,
12565                &mut selections,
12566            );
12567
12568            // Move the text spanned by the row range to be after the last line of the row range
12569            if end_row.0 <= buffer.max_point().row {
12570                let range_to_move =
12571                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12572                let insertion_point = display_map
12573                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12574                    .0;
12575
12576                // Don't move lines across excerpt boundaries
12577                if buffer
12578                    .excerpt_containing(range_to_move.start..insertion_point)
12579                    .is_some()
12580                {
12581                    let mut text = String::from("\n");
12582                    text.extend(buffer.text_for_range(range_to_move.clone()));
12583                    text.pop(); // Drop trailing newline
12584                    edits.push((
12585                        buffer.anchor_after(range_to_move.start)
12586                            ..buffer.anchor_before(range_to_move.end),
12587                        String::new(),
12588                    ));
12589                    let insertion_anchor = buffer.anchor_after(insertion_point);
12590                    edits.push((insertion_anchor..insertion_anchor, text));
12591
12592                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12593
12594                    // Move selections down
12595                    new_selections.extend(contiguous_row_selections.drain(..).map(
12596                        |mut selection| {
12597                            selection.start.row += row_delta;
12598                            selection.end.row += row_delta;
12599                            selection
12600                        },
12601                    ));
12602
12603                    // Move folds down
12604                    unfold_ranges.push(range_to_move.clone());
12605                    for fold in display_map.folds_in_range(
12606                        buffer.anchor_before(range_to_move.start)
12607                            ..buffer.anchor_after(range_to_move.end),
12608                    ) {
12609                        let mut start = fold.range.start.to_point(&buffer);
12610                        let mut end = fold.range.end.to_point(&buffer);
12611                        start.row += row_delta;
12612                        end.row += row_delta;
12613                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12614                    }
12615                }
12616            }
12617
12618            // If we didn't move line(s), preserve the existing selections
12619            new_selections.append(&mut contiguous_row_selections);
12620        }
12621
12622        self.transact(window, cx, |this, window, cx| {
12623            this.unfold_ranges(&unfold_ranges, true, true, cx);
12624            this.buffer.update(cx, |buffer, cx| {
12625                for (range, text) in edits {
12626                    buffer.edit([(range, text)], None, cx);
12627                }
12628            });
12629            this.fold_creases(refold_creases, true, window, cx);
12630            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12631        });
12632    }
12633
12634    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12635        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12636        let text_layout_details = &self.text_layout_details(window);
12637        self.transact(window, cx, |this, window, cx| {
12638            let edits = this.change_selections(Default::default(), window, cx, |s| {
12639                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12640                s.move_with(|display_map, selection| {
12641                    if !selection.is_empty() {
12642                        return;
12643                    }
12644
12645                    let mut head = selection.head();
12646                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12647                    if head.column() == display_map.line_len(head.row()) {
12648                        transpose_offset = display_map
12649                            .buffer_snapshot()
12650                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12651                    }
12652
12653                    if transpose_offset == MultiBufferOffset(0) {
12654                        return;
12655                    }
12656
12657                    *head.column_mut() += 1;
12658                    head = display_map.clip_point(head, Bias::Right);
12659                    let goal = SelectionGoal::HorizontalPosition(
12660                        display_map
12661                            .x_for_display_point(head, text_layout_details)
12662                            .into(),
12663                    );
12664                    selection.collapse_to(head, goal);
12665
12666                    let transpose_start = display_map
12667                        .buffer_snapshot()
12668                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12669                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12670                        let transpose_end = display_map
12671                            .buffer_snapshot()
12672                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12673                        if let Some(ch) = display_map
12674                            .buffer_snapshot()
12675                            .chars_at(transpose_start)
12676                            .next()
12677                        {
12678                            edits.push((transpose_start..transpose_offset, String::new()));
12679                            edits.push((transpose_end..transpose_end, ch.to_string()));
12680                        }
12681                    }
12682                });
12683                edits
12684            });
12685            this.buffer
12686                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12687            let selections = this
12688                .selections
12689                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12690            this.change_selections(Default::default(), window, cx, |s| {
12691                s.select(selections);
12692            });
12693        });
12694    }
12695
12696    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12698        if self.mode.is_single_line() {
12699            cx.propagate();
12700            return;
12701        }
12702
12703        self.rewrap_impl(RewrapOptions::default(), cx)
12704    }
12705
12706    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12707        let buffer = self.buffer.read(cx).snapshot(cx);
12708        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12709
12710        #[derive(Clone, Debug, PartialEq)]
12711        enum CommentFormat {
12712            /// single line comment, with prefix for line
12713            Line(String),
12714            /// single line within a block comment, with prefix for line
12715            BlockLine(String),
12716            /// a single line of a block comment that includes the initial delimiter
12717            BlockCommentWithStart(BlockCommentConfig),
12718            /// a single line of a block comment that includes the ending delimiter
12719            BlockCommentWithEnd(BlockCommentConfig),
12720        }
12721
12722        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12723        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12724            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12725                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12726                .peekable();
12727
12728            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12729                row
12730            } else {
12731                return Vec::new();
12732            };
12733
12734            let language_settings = buffer.language_settings_at(selection.head(), cx);
12735            let language_scope = buffer.language_scope_at(selection.head());
12736
12737            let indent_and_prefix_for_row =
12738                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12739                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12740                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12741                        &language_scope
12742                    {
12743                        let indent_end = Point::new(row, indent.len);
12744                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12745                        let line_text_after_indent = buffer
12746                            .text_for_range(indent_end..line_end)
12747                            .collect::<String>();
12748
12749                        let is_within_comment_override = buffer
12750                            .language_scope_at(indent_end)
12751                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12752                        let comment_delimiters = if is_within_comment_override {
12753                            // we are within a comment syntax node, but we don't
12754                            // yet know what kind of comment: block, doc or line
12755                            match (
12756                                language_scope.documentation_comment(),
12757                                language_scope.block_comment(),
12758                            ) {
12759                                (Some(config), _) | (_, Some(config))
12760                                    if buffer.contains_str_at(indent_end, &config.start) =>
12761                                {
12762                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12763                                }
12764                                (Some(config), _) | (_, Some(config))
12765                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12766                                {
12767                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12768                                }
12769                                (Some(config), _) | (_, Some(config))
12770                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12771                                {
12772                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12773                                }
12774                                (_, _) => language_scope
12775                                    .line_comment_prefixes()
12776                                    .iter()
12777                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12778                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12779                            }
12780                        } else {
12781                            // we not in an overridden comment node, but we may
12782                            // be within a non-overridden line comment node
12783                            language_scope
12784                                .line_comment_prefixes()
12785                                .iter()
12786                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12787                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12788                        };
12789
12790                        let rewrap_prefix = language_scope
12791                            .rewrap_prefixes()
12792                            .iter()
12793                            .find_map(|prefix_regex| {
12794                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12795                                    if mat.start() == 0 {
12796                                        Some(mat.as_str().to_string())
12797                                    } else {
12798                                        None
12799                                    }
12800                                })
12801                            })
12802                            .flatten();
12803                        (comment_delimiters, rewrap_prefix)
12804                    } else {
12805                        (None, None)
12806                    };
12807                    (indent, comment_prefix, rewrap_prefix)
12808                };
12809
12810            let mut ranges = Vec::new();
12811            let from_empty_selection = selection.is_empty();
12812
12813            let mut current_range_start = first_row;
12814            let mut prev_row = first_row;
12815            let (
12816                mut current_range_indent,
12817                mut current_range_comment_delimiters,
12818                mut current_range_rewrap_prefix,
12819            ) = indent_and_prefix_for_row(first_row);
12820
12821            for row in non_blank_rows_iter.skip(1) {
12822                let has_paragraph_break = row > prev_row + 1;
12823
12824                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12825                    indent_and_prefix_for_row(row);
12826
12827                let has_indent_change = row_indent != current_range_indent;
12828                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12829
12830                let has_boundary_change = has_comment_change
12831                    || row_rewrap_prefix.is_some()
12832                    || (has_indent_change && current_range_comment_delimiters.is_some());
12833
12834                if has_paragraph_break || has_boundary_change {
12835                    ranges.push((
12836                        language_settings.clone(),
12837                        Point::new(current_range_start, 0)
12838                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12839                        current_range_indent,
12840                        current_range_comment_delimiters.clone(),
12841                        current_range_rewrap_prefix.clone(),
12842                        from_empty_selection,
12843                    ));
12844                    current_range_start = row;
12845                    current_range_indent = row_indent;
12846                    current_range_comment_delimiters = row_comment_delimiters;
12847                    current_range_rewrap_prefix = row_rewrap_prefix;
12848                }
12849                prev_row = row;
12850            }
12851
12852            ranges.push((
12853                language_settings.clone(),
12854                Point::new(current_range_start, 0)
12855                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12856                current_range_indent,
12857                current_range_comment_delimiters,
12858                current_range_rewrap_prefix,
12859                from_empty_selection,
12860            ));
12861
12862            ranges
12863        });
12864
12865        let mut edits = Vec::new();
12866        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12867
12868        for (
12869            language_settings,
12870            wrap_range,
12871            mut indent_size,
12872            comment_prefix,
12873            rewrap_prefix,
12874            from_empty_selection,
12875        ) in wrap_ranges
12876        {
12877            let mut start_row = wrap_range.start.row;
12878            let mut end_row = wrap_range.end.row;
12879
12880            // Skip selections that overlap with a range that has already been rewrapped.
12881            let selection_range = start_row..end_row;
12882            if rewrapped_row_ranges
12883                .iter()
12884                .any(|range| range.overlaps(&selection_range))
12885            {
12886                continue;
12887            }
12888
12889            let tab_size = language_settings.tab_size;
12890
12891            let (line_prefix, inside_comment) = match &comment_prefix {
12892                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12893                    (Some(prefix.as_str()), true)
12894                }
12895                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12896                    (Some(prefix.as_ref()), true)
12897                }
12898                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12899                    start: _,
12900                    end: _,
12901                    prefix,
12902                    tab_size,
12903                })) => {
12904                    indent_size.len += tab_size;
12905                    (Some(prefix.as_ref()), true)
12906                }
12907                None => (None, false),
12908            };
12909            let indent_prefix = indent_size.chars().collect::<String>();
12910            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12911
12912            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12913                RewrapBehavior::InComments => inside_comment,
12914                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12915                RewrapBehavior::Anywhere => true,
12916            };
12917
12918            let should_rewrap = options.override_language_settings
12919                || allow_rewrap_based_on_language
12920                || self.hard_wrap.is_some();
12921            if !should_rewrap {
12922                continue;
12923            }
12924
12925            if from_empty_selection {
12926                'expand_upwards: while start_row > 0 {
12927                    let prev_row = start_row - 1;
12928                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12929                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12930                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12931                    {
12932                        start_row = prev_row;
12933                    } else {
12934                        break 'expand_upwards;
12935                    }
12936                }
12937
12938                'expand_downwards: while end_row < buffer.max_point().row {
12939                    let next_row = end_row + 1;
12940                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12941                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12942                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12943                    {
12944                        end_row = next_row;
12945                    } else {
12946                        break 'expand_downwards;
12947                    }
12948                }
12949            }
12950
12951            let start = Point::new(start_row, 0);
12952            let start_offset = ToOffset::to_offset(&start, &buffer);
12953            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12954            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12955            let mut first_line_delimiter = None;
12956            let mut last_line_delimiter = None;
12957            let Some(lines_without_prefixes) = selection_text
12958                .lines()
12959                .enumerate()
12960                .map(|(ix, line)| {
12961                    let line_trimmed = line.trim_start();
12962                    if rewrap_prefix.is_some() && ix > 0 {
12963                        Ok(line_trimmed)
12964                    } else if let Some(
12965                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12966                            start,
12967                            prefix,
12968                            end,
12969                            tab_size,
12970                        })
12971                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12972                            start,
12973                            prefix,
12974                            end,
12975                            tab_size,
12976                        }),
12977                    ) = &comment_prefix
12978                    {
12979                        let line_trimmed = line_trimmed
12980                            .strip_prefix(start.as_ref())
12981                            .map(|s| {
12982                                let mut indent_size = indent_size;
12983                                indent_size.len -= tab_size;
12984                                let indent_prefix: String = indent_size.chars().collect();
12985                                first_line_delimiter = Some((indent_prefix, start));
12986                                s.trim_start()
12987                            })
12988                            .unwrap_or(line_trimmed);
12989                        let line_trimmed = line_trimmed
12990                            .strip_suffix(end.as_ref())
12991                            .map(|s| {
12992                                last_line_delimiter = Some(end);
12993                                s.trim_end()
12994                            })
12995                            .unwrap_or(line_trimmed);
12996                        let line_trimmed = line_trimmed
12997                            .strip_prefix(prefix.as_ref())
12998                            .unwrap_or(line_trimmed);
12999                        Ok(line_trimmed)
13000                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13001                        line_trimmed.strip_prefix(prefix).with_context(|| {
13002                            format!("line did not start with prefix {prefix:?}: {line:?}")
13003                        })
13004                    } else {
13005                        line_trimmed
13006                            .strip_prefix(&line_prefix.trim_start())
13007                            .with_context(|| {
13008                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13009                            })
13010                    }
13011                })
13012                .collect::<Result<Vec<_>, _>>()
13013                .log_err()
13014            else {
13015                continue;
13016            };
13017
13018            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13019                buffer
13020                    .language_settings_at(Point::new(start_row, 0), cx)
13021                    .preferred_line_length as usize
13022            });
13023
13024            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13025                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13026            } else {
13027                line_prefix.clone()
13028            };
13029
13030            let wrapped_text = {
13031                let mut wrapped_text = wrap_with_prefix(
13032                    line_prefix,
13033                    subsequent_lines_prefix,
13034                    lines_without_prefixes.join("\n"),
13035                    wrap_column,
13036                    tab_size,
13037                    options.preserve_existing_whitespace,
13038                );
13039
13040                if let Some((indent, delimiter)) = first_line_delimiter {
13041                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13042                }
13043                if let Some(last_line) = last_line_delimiter {
13044                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13045                }
13046
13047                wrapped_text
13048            };
13049
13050            // TODO: should always use char-based diff while still supporting cursor behavior that
13051            // matches vim.
13052            let mut diff_options = DiffOptions::default();
13053            if options.override_language_settings {
13054                diff_options.max_word_diff_len = 0;
13055                diff_options.max_word_diff_line_count = 0;
13056            } else {
13057                diff_options.max_word_diff_len = usize::MAX;
13058                diff_options.max_word_diff_line_count = usize::MAX;
13059            }
13060
13061            for (old_range, new_text) in
13062                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13063            {
13064                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13065                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13066                edits.push((edit_start..edit_end, new_text));
13067            }
13068
13069            rewrapped_row_ranges.push(start_row..=end_row);
13070        }
13071
13072        self.buffer
13073            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13074    }
13075
13076    pub fn cut_common(
13077        &mut self,
13078        cut_no_selection_line: bool,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) -> ClipboardItem {
13082        let mut text = String::new();
13083        let buffer = self.buffer.read(cx).snapshot(cx);
13084        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13085        let mut clipboard_selections = Vec::with_capacity(selections.len());
13086        {
13087            let max_point = buffer.max_point();
13088            let mut is_first = true;
13089            let mut prev_selection_was_entire_line = false;
13090            for selection in &mut selections {
13091                let is_entire_line =
13092                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13093                if is_entire_line {
13094                    selection.start = Point::new(selection.start.row, 0);
13095                    if !selection.is_empty() && selection.end.column == 0 {
13096                        selection.end = cmp::min(max_point, selection.end);
13097                    } else {
13098                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13099                    }
13100                    selection.goal = SelectionGoal::None;
13101                }
13102                if is_first {
13103                    is_first = false;
13104                } else if !prev_selection_was_entire_line {
13105                    text += "\n";
13106                }
13107                prev_selection_was_entire_line = is_entire_line;
13108                let mut len = 0;
13109                for chunk in buffer.text_for_range(selection.start..selection.end) {
13110                    text.push_str(chunk);
13111                    len += chunk.len();
13112                }
13113
13114                clipboard_selections.push(ClipboardSelection::for_buffer(
13115                    len,
13116                    is_entire_line,
13117                    selection.range(),
13118                    &buffer,
13119                    self.project.as_ref(),
13120                    cx,
13121                ));
13122            }
13123        }
13124
13125        self.transact(window, cx, |this, window, cx| {
13126            this.change_selections(Default::default(), window, cx, |s| {
13127                s.select(selections);
13128            });
13129            this.insert("", window, cx);
13130        });
13131        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13132    }
13133
13134    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13136        let item = self.cut_common(true, window, cx);
13137        cx.write_to_clipboard(item);
13138    }
13139
13140    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13142        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13143            s.move_with(|snapshot, sel| {
13144                if sel.is_empty() {
13145                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13146                }
13147                if sel.is_empty() {
13148                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13149                }
13150            });
13151        });
13152        let item = self.cut_common(false, window, cx);
13153        cx.set_global(KillRing(item))
13154    }
13155
13156    pub fn kill_ring_yank(
13157        &mut self,
13158        _: &KillRingYank,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13163        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13164            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13165                (kill_ring.text().to_string(), kill_ring.metadata_json())
13166            } else {
13167                return;
13168            }
13169        } else {
13170            return;
13171        };
13172        self.do_paste(&text, metadata, false, window, cx);
13173    }
13174
13175    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13176        self.do_copy(true, cx);
13177    }
13178
13179    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13180        self.do_copy(false, cx);
13181    }
13182
13183    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13184        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13185        let buffer = self.buffer.read(cx).read(cx);
13186        let mut text = String::new();
13187
13188        let mut clipboard_selections = Vec::with_capacity(selections.len());
13189        {
13190            let max_point = buffer.max_point();
13191            let mut is_first = true;
13192            let mut prev_selection_was_entire_line = false;
13193            for selection in &selections {
13194                let mut start = selection.start;
13195                let mut end = selection.end;
13196                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13197                let mut add_trailing_newline = false;
13198                if is_entire_line {
13199                    start = Point::new(start.row, 0);
13200                    let next_line_start = Point::new(end.row + 1, 0);
13201                    if next_line_start <= max_point {
13202                        end = next_line_start;
13203                    } else {
13204                        // We're on the last line without a trailing newline.
13205                        // Copy to the end of the line and add a newline afterwards.
13206                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13207                        add_trailing_newline = true;
13208                    }
13209                }
13210
13211                let mut trimmed_selections = Vec::new();
13212                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13213                    let row = MultiBufferRow(start.row);
13214                    let first_indent = buffer.indent_size_for_line(row);
13215                    if first_indent.len == 0 || start.column > first_indent.len {
13216                        trimmed_selections.push(start..end);
13217                    } else {
13218                        trimmed_selections.push(
13219                            Point::new(row.0, first_indent.len)
13220                                ..Point::new(row.0, buffer.line_len(row)),
13221                        );
13222                        for row in start.row + 1..=end.row {
13223                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13224                            if row == end.row {
13225                                line_len = end.column;
13226                            }
13227                            if line_len == 0 {
13228                                trimmed_selections
13229                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13230                                continue;
13231                            }
13232                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13233                            if row_indent_size.len >= first_indent.len {
13234                                trimmed_selections.push(
13235                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13236                                );
13237                            } else {
13238                                trimmed_selections.clear();
13239                                trimmed_selections.push(start..end);
13240                                break;
13241                            }
13242                        }
13243                    }
13244                } else {
13245                    trimmed_selections.push(start..end);
13246                }
13247
13248                for trimmed_range in trimmed_selections {
13249                    if is_first {
13250                        is_first = false;
13251                    } else if !prev_selection_was_entire_line {
13252                        text += "\n";
13253                    }
13254                    prev_selection_was_entire_line = is_entire_line;
13255                    let mut len = 0;
13256                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13257                        text.push_str(chunk);
13258                        len += chunk.len();
13259                    }
13260                    if add_trailing_newline {
13261                        text.push('\n');
13262                        len += 1;
13263                    }
13264                    clipboard_selections.push(ClipboardSelection::for_buffer(
13265                        len,
13266                        is_entire_line,
13267                        trimmed_range,
13268                        &buffer,
13269                        self.project.as_ref(),
13270                        cx,
13271                    ));
13272                }
13273            }
13274        }
13275
13276        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13277            text,
13278            clipboard_selections,
13279        ));
13280    }
13281
13282    pub fn do_paste(
13283        &mut self,
13284        text: &String,
13285        clipboard_selections: Option<Vec<ClipboardSelection>>,
13286        handle_entire_lines: bool,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if self.read_only(cx) {
13291            return;
13292        }
13293
13294        let clipboard_text = Cow::Borrowed(text.as_str());
13295
13296        self.transact(window, cx, |this, window, cx| {
13297            let had_active_edit_prediction = this.has_active_edit_prediction();
13298            let display_map = this.display_snapshot(cx);
13299            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13300            let cursor_offset = this
13301                .selections
13302                .last::<MultiBufferOffset>(&display_map)
13303                .head();
13304
13305            if let Some(mut clipboard_selections) = clipboard_selections {
13306                let all_selections_were_entire_line =
13307                    clipboard_selections.iter().all(|s| s.is_entire_line);
13308                let first_selection_indent_column =
13309                    clipboard_selections.first().map(|s| s.first_line_indent);
13310                if clipboard_selections.len() != old_selections.len() {
13311                    clipboard_selections.drain(..);
13312                }
13313                let mut auto_indent_on_paste = true;
13314
13315                this.buffer.update(cx, |buffer, cx| {
13316                    let snapshot = buffer.read(cx);
13317                    auto_indent_on_paste = snapshot
13318                        .language_settings_at(cursor_offset, cx)
13319                        .auto_indent_on_paste;
13320
13321                    let mut start_offset = 0;
13322                    let mut edits = Vec::new();
13323                    let mut original_indent_columns = Vec::new();
13324                    for (ix, selection) in old_selections.iter().enumerate() {
13325                        let to_insert;
13326                        let entire_line;
13327                        let original_indent_column;
13328                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13329                            let end_offset = start_offset + clipboard_selection.len;
13330                            to_insert = &clipboard_text[start_offset..end_offset];
13331                            entire_line = clipboard_selection.is_entire_line;
13332                            start_offset = if entire_line {
13333                                end_offset
13334                            } else {
13335                                end_offset + 1
13336                            };
13337                            original_indent_column = Some(clipboard_selection.first_line_indent);
13338                        } else {
13339                            to_insert = &*clipboard_text;
13340                            entire_line = all_selections_were_entire_line;
13341                            original_indent_column = first_selection_indent_column
13342                        }
13343
13344                        let (range, to_insert) =
13345                            if selection.is_empty() && handle_entire_lines && entire_line {
13346                                // If the corresponding selection was empty when this slice of the
13347                                // clipboard text was written, then the entire line containing the
13348                                // selection was copied. If this selection is also currently empty,
13349                                // then paste the line before the current line of the buffer.
13350                                let column = selection.start.to_point(&snapshot).column as usize;
13351                                let line_start = selection.start - column;
13352                                (line_start..line_start, Cow::Borrowed(to_insert))
13353                            } else {
13354                                let language = snapshot.language_at(selection.head());
13355                                let range = selection.range();
13356                                if let Some(language) = language
13357                                    && language.name() == "Markdown".into()
13358                                {
13359                                    edit_for_markdown_paste(
13360                                        &snapshot,
13361                                        range,
13362                                        to_insert,
13363                                        url::Url::parse(to_insert).ok(),
13364                                    )
13365                                } else {
13366                                    (range, Cow::Borrowed(to_insert))
13367                                }
13368                            };
13369
13370                        edits.push((range, to_insert));
13371                        original_indent_columns.push(original_indent_column);
13372                    }
13373                    drop(snapshot);
13374
13375                    buffer.edit(
13376                        edits,
13377                        if auto_indent_on_paste {
13378                            Some(AutoindentMode::Block {
13379                                original_indent_columns,
13380                            })
13381                        } else {
13382                            None
13383                        },
13384                        cx,
13385                    );
13386                });
13387
13388                let selections = this
13389                    .selections
13390                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13391                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13392            } else {
13393                let url = url::Url::parse(&clipboard_text).ok();
13394
13395                let auto_indent_mode = if !clipboard_text.is_empty() {
13396                    Some(AutoindentMode::Block {
13397                        original_indent_columns: Vec::new(),
13398                    })
13399                } else {
13400                    None
13401                };
13402
13403                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13404                    let snapshot = buffer.snapshot(cx);
13405
13406                    let anchors = old_selections
13407                        .iter()
13408                        .map(|s| {
13409                            let anchor = snapshot.anchor_after(s.head());
13410                            s.map(|_| anchor)
13411                        })
13412                        .collect::<Vec<_>>();
13413
13414                    let mut edits = Vec::new();
13415
13416                    for selection in old_selections.iter() {
13417                        let language = snapshot.language_at(selection.head());
13418                        let range = selection.range();
13419
13420                        let (edit_range, edit_text) = if let Some(language) = language
13421                            && language.name() == "Markdown".into()
13422                        {
13423                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13424                        } else {
13425                            (range, clipboard_text.clone())
13426                        };
13427
13428                        edits.push((edit_range, edit_text));
13429                    }
13430
13431                    drop(snapshot);
13432                    buffer.edit(edits, auto_indent_mode, cx);
13433
13434                    anchors
13435                });
13436
13437                this.change_selections(Default::default(), window, cx, |s| {
13438                    s.select_anchors(selection_anchors);
13439                });
13440            }
13441
13442            //   🤔                 |    ..     | show_in_menu |
13443            // | ..                  |   true        true
13444            // | had_edit_prediction |   false       true
13445
13446            let trigger_in_words =
13447                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13448
13449            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13450        });
13451    }
13452
13453    pub fn diff_clipboard_with_selection(
13454        &mut self,
13455        _: &DiffClipboardWithSelection,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        let selections = self
13460            .selections
13461            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13462
13463        if selections.is_empty() {
13464            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13465            return;
13466        };
13467
13468        let clipboard_text = match cx.read_from_clipboard() {
13469            Some(item) => match item.entries().first() {
13470                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13471                _ => None,
13472            },
13473            None => None,
13474        };
13475
13476        let Some(clipboard_text) = clipboard_text else {
13477            log::warn!("Clipboard doesn't contain text.");
13478            return;
13479        };
13480
13481        window.dispatch_action(
13482            Box::new(DiffClipboardWithSelectionData {
13483                clipboard_text,
13484                editor: cx.entity(),
13485            }),
13486            cx,
13487        );
13488    }
13489
13490    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13492        if let Some(item) = cx.read_from_clipboard() {
13493            let entries = item.entries();
13494
13495            match entries.first() {
13496                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13497                // of all the pasted entries.
13498                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13499                    .do_paste(
13500                        clipboard_string.text(),
13501                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13502                        true,
13503                        window,
13504                        cx,
13505                    ),
13506                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13507            }
13508        }
13509    }
13510
13511    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13512        if self.read_only(cx) {
13513            return;
13514        }
13515
13516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13517
13518        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13519            if let Some((selections, _)) =
13520                self.selection_history.transaction(transaction_id).cloned()
13521            {
13522                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13523                    s.select_anchors(selections.to_vec());
13524                });
13525            } else {
13526                log::error!(
13527                    "No entry in selection_history found for undo. \
13528                     This may correspond to a bug where undo does not update the selection. \
13529                     If this is occurring, please add details to \
13530                     https://github.com/zed-industries/zed/issues/22692"
13531                );
13532            }
13533            self.request_autoscroll(Autoscroll::fit(), cx);
13534            self.unmark_text(window, cx);
13535            self.refresh_edit_prediction(true, false, window, cx);
13536            cx.emit(EditorEvent::Edited { transaction_id });
13537            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13538        }
13539    }
13540
13541    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13542        if self.read_only(cx) {
13543            return;
13544        }
13545
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13547
13548        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13549            if let Some((_, Some(selections))) =
13550                self.selection_history.transaction(transaction_id).cloned()
13551            {
13552                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13553                    s.select_anchors(selections.to_vec());
13554                });
13555            } else {
13556                log::error!(
13557                    "No entry in selection_history found for redo. \
13558                     This may correspond to a bug where undo does not update the selection. \
13559                     If this is occurring, please add details to \
13560                     https://github.com/zed-industries/zed/issues/22692"
13561                );
13562            }
13563            self.request_autoscroll(Autoscroll::fit(), cx);
13564            self.unmark_text(window, cx);
13565            self.refresh_edit_prediction(true, false, window, cx);
13566            cx.emit(EditorEvent::Edited { transaction_id });
13567        }
13568    }
13569
13570    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13571        self.buffer
13572            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13573    }
13574
13575    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13576        self.buffer
13577            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13578    }
13579
13580    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13581        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13582        self.change_selections(Default::default(), window, cx, |s| {
13583            s.move_with(|map, selection| {
13584                let cursor = if selection.is_empty() {
13585                    movement::left(map, selection.start)
13586                } else {
13587                    selection.start
13588                };
13589                selection.collapse_to(cursor, SelectionGoal::None);
13590            });
13591        })
13592    }
13593
13594    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13596        self.change_selections(Default::default(), window, cx, |s| {
13597            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13598        })
13599    }
13600
13601    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13603        self.change_selections(Default::default(), window, cx, |s| {
13604            s.move_with(|map, selection| {
13605                let cursor = if selection.is_empty() {
13606                    movement::right(map, selection.end)
13607                } else {
13608                    selection.end
13609                };
13610                selection.collapse_to(cursor, SelectionGoal::None)
13611            });
13612        })
13613    }
13614
13615    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13617        self.change_selections(Default::default(), window, cx, |s| {
13618            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13619        });
13620    }
13621
13622    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13623        if self.take_rename(true, window, cx).is_some() {
13624            return;
13625        }
13626
13627        if self.mode.is_single_line() {
13628            cx.propagate();
13629            return;
13630        }
13631
13632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13633
13634        let text_layout_details = &self.text_layout_details(window);
13635        let selection_count = self.selections.count();
13636        let first_selection = self.selections.first_anchor();
13637
13638        self.change_selections(Default::default(), window, cx, |s| {
13639            s.move_with(|map, selection| {
13640                if !selection.is_empty() {
13641                    selection.goal = SelectionGoal::None;
13642                }
13643                let (cursor, goal) = movement::up(
13644                    map,
13645                    selection.start,
13646                    selection.goal,
13647                    false,
13648                    text_layout_details,
13649                );
13650                selection.collapse_to(cursor, goal);
13651            });
13652        });
13653
13654        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13655        {
13656            cx.propagate();
13657        }
13658    }
13659
13660    pub fn move_up_by_lines(
13661        &mut self,
13662        action: &MoveUpByLines,
13663        window: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        if self.take_rename(true, window, cx).is_some() {
13667            return;
13668        }
13669
13670        if self.mode.is_single_line() {
13671            cx.propagate();
13672            return;
13673        }
13674
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13676
13677        let text_layout_details = &self.text_layout_details(window);
13678
13679        self.change_selections(Default::default(), window, cx, |s| {
13680            s.move_with(|map, selection| {
13681                if !selection.is_empty() {
13682                    selection.goal = SelectionGoal::None;
13683                }
13684                let (cursor, goal) = movement::up_by_rows(
13685                    map,
13686                    selection.start,
13687                    action.lines,
13688                    selection.goal,
13689                    false,
13690                    text_layout_details,
13691                );
13692                selection.collapse_to(cursor, goal);
13693            });
13694        })
13695    }
13696
13697    pub fn move_down_by_lines(
13698        &mut self,
13699        action: &MoveDownByLines,
13700        window: &mut Window,
13701        cx: &mut Context<Self>,
13702    ) {
13703        if self.take_rename(true, window, cx).is_some() {
13704            return;
13705        }
13706
13707        if self.mode.is_single_line() {
13708            cx.propagate();
13709            return;
13710        }
13711
13712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13713
13714        let text_layout_details = &self.text_layout_details(window);
13715
13716        self.change_selections(Default::default(), window, cx, |s| {
13717            s.move_with(|map, selection| {
13718                if !selection.is_empty() {
13719                    selection.goal = SelectionGoal::None;
13720                }
13721                let (cursor, goal) = movement::down_by_rows(
13722                    map,
13723                    selection.start,
13724                    action.lines,
13725                    selection.goal,
13726                    false,
13727                    text_layout_details,
13728                );
13729                selection.collapse_to(cursor, goal);
13730            });
13731        })
13732    }
13733
13734    pub fn select_down_by_lines(
13735        &mut self,
13736        action: &SelectDownByLines,
13737        window: &mut Window,
13738        cx: &mut Context<Self>,
13739    ) {
13740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13741        let text_layout_details = &self.text_layout_details(window);
13742        self.change_selections(Default::default(), window, cx, |s| {
13743            s.move_heads_with(|map, head, goal| {
13744                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13745            })
13746        })
13747    }
13748
13749    pub fn select_up_by_lines(
13750        &mut self,
13751        action: &SelectUpByLines,
13752        window: &mut Window,
13753        cx: &mut Context<Self>,
13754    ) {
13755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13756        let text_layout_details = &self.text_layout_details(window);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_heads_with(|map, head, goal| {
13759                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13760            })
13761        })
13762    }
13763
13764    pub fn select_page_up(
13765        &mut self,
13766        _: &SelectPageUp,
13767        window: &mut Window,
13768        cx: &mut Context<Self>,
13769    ) {
13770        let Some(row_count) = self.visible_row_count() else {
13771            return;
13772        };
13773
13774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13775
13776        let text_layout_details = &self.text_layout_details(window);
13777
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_heads_with(|map, head, goal| {
13780                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13781            })
13782        })
13783    }
13784
13785    pub fn move_page_up(
13786        &mut self,
13787        action: &MovePageUp,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        if self.take_rename(true, window, cx).is_some() {
13792            return;
13793        }
13794
13795        if self
13796            .context_menu
13797            .borrow_mut()
13798            .as_mut()
13799            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13800            .unwrap_or(false)
13801        {
13802            return;
13803        }
13804
13805        if matches!(self.mode, EditorMode::SingleLine) {
13806            cx.propagate();
13807            return;
13808        }
13809
13810        let Some(row_count) = self.visible_row_count() else {
13811            return;
13812        };
13813
13814        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13815
13816        let effects = if action.center_cursor {
13817            SelectionEffects::scroll(Autoscroll::center())
13818        } else {
13819            SelectionEffects::default()
13820        };
13821
13822        let text_layout_details = &self.text_layout_details(window);
13823
13824        self.change_selections(effects, window, cx, |s| {
13825            s.move_with(|map, selection| {
13826                if !selection.is_empty() {
13827                    selection.goal = SelectionGoal::None;
13828                }
13829                let (cursor, goal) = movement::up_by_rows(
13830                    map,
13831                    selection.end,
13832                    row_count,
13833                    selection.goal,
13834                    false,
13835                    text_layout_details,
13836                );
13837                selection.collapse_to(cursor, goal);
13838            });
13839        });
13840    }
13841
13842    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        let text_layout_details = &self.text_layout_details(window);
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.move_heads_with(|map, head, goal| {
13847                movement::up(map, head, goal, false, text_layout_details)
13848            })
13849        })
13850    }
13851
13852    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13853        self.take_rename(true, window, cx);
13854
13855        if self.mode.is_single_line() {
13856            cx.propagate();
13857            return;
13858        }
13859
13860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13861
13862        let text_layout_details = &self.text_layout_details(window);
13863        let selection_count = self.selections.count();
13864        let first_selection = self.selections.first_anchor();
13865
13866        self.change_selections(Default::default(), window, cx, |s| {
13867            s.move_with(|map, selection| {
13868                if !selection.is_empty() {
13869                    selection.goal = SelectionGoal::None;
13870                }
13871                let (cursor, goal) = movement::down(
13872                    map,
13873                    selection.end,
13874                    selection.goal,
13875                    false,
13876                    text_layout_details,
13877                );
13878                selection.collapse_to(cursor, goal);
13879            });
13880        });
13881
13882        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13883        {
13884            cx.propagate();
13885        }
13886    }
13887
13888    pub fn select_page_down(
13889        &mut self,
13890        _: &SelectPageDown,
13891        window: &mut Window,
13892        cx: &mut Context<Self>,
13893    ) {
13894        let Some(row_count) = self.visible_row_count() else {
13895            return;
13896        };
13897
13898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13899
13900        let text_layout_details = &self.text_layout_details(window);
13901
13902        self.change_selections(Default::default(), window, cx, |s| {
13903            s.move_heads_with(|map, head, goal| {
13904                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13905            })
13906        })
13907    }
13908
13909    pub fn move_page_down(
13910        &mut self,
13911        action: &MovePageDown,
13912        window: &mut Window,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if self.take_rename(true, window, cx).is_some() {
13916            return;
13917        }
13918
13919        if self
13920            .context_menu
13921            .borrow_mut()
13922            .as_mut()
13923            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13924            .unwrap_or(false)
13925        {
13926            return;
13927        }
13928
13929        if matches!(self.mode, EditorMode::SingleLine) {
13930            cx.propagate();
13931            return;
13932        }
13933
13934        let Some(row_count) = self.visible_row_count() else {
13935            return;
13936        };
13937
13938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13939
13940        let effects = if action.center_cursor {
13941            SelectionEffects::scroll(Autoscroll::center())
13942        } else {
13943            SelectionEffects::default()
13944        };
13945
13946        let text_layout_details = &self.text_layout_details(window);
13947        self.change_selections(effects, window, cx, |s| {
13948            s.move_with(|map, selection| {
13949                if !selection.is_empty() {
13950                    selection.goal = SelectionGoal::None;
13951                }
13952                let (cursor, goal) = movement::down_by_rows(
13953                    map,
13954                    selection.end,
13955                    row_count,
13956                    selection.goal,
13957                    false,
13958                    text_layout_details,
13959                );
13960                selection.collapse_to(cursor, goal);
13961            });
13962        });
13963    }
13964
13965    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13967        let text_layout_details = &self.text_layout_details(window);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.move_heads_with(|map, head, goal| {
13970                movement::down(map, head, goal, false, text_layout_details)
13971            })
13972        });
13973    }
13974
13975    pub fn context_menu_first(
13976        &mut self,
13977        _: &ContextMenuFirst,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13982            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13983        }
13984    }
13985
13986    pub fn context_menu_prev(
13987        &mut self,
13988        _: &ContextMenuPrevious,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13993            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13994        }
13995    }
13996
13997    pub fn context_menu_next(
13998        &mut self,
13999        _: &ContextMenuNext,
14000        window: &mut Window,
14001        cx: &mut Context<Self>,
14002    ) {
14003        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14004            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14005        }
14006    }
14007
14008    pub fn context_menu_last(
14009        &mut self,
14010        _: &ContextMenuLast,
14011        window: &mut Window,
14012        cx: &mut Context<Self>,
14013    ) {
14014        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14015            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14016        }
14017    }
14018
14019    pub fn signature_help_prev(
14020        &mut self,
14021        _: &SignatureHelpPrevious,
14022        _: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        if let Some(popover) = self.signature_help_state.popover_mut() {
14026            if popover.current_signature == 0 {
14027                popover.current_signature = popover.signatures.len() - 1;
14028            } else {
14029                popover.current_signature -= 1;
14030            }
14031            cx.notify();
14032        }
14033    }
14034
14035    pub fn signature_help_next(
14036        &mut self,
14037        _: &SignatureHelpNext,
14038        _: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) {
14041        if let Some(popover) = self.signature_help_state.popover_mut() {
14042            if popover.current_signature + 1 == popover.signatures.len() {
14043                popover.current_signature = 0;
14044            } else {
14045                popover.current_signature += 1;
14046            }
14047            cx.notify();
14048        }
14049    }
14050
14051    pub fn move_to_previous_word_start(
14052        &mut self,
14053        _: &MoveToPreviousWordStart,
14054        window: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) {
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058        self.change_selections(Default::default(), window, cx, |s| {
14059            s.move_cursors_with(|map, head, _| {
14060                (
14061                    movement::previous_word_start(map, head),
14062                    SelectionGoal::None,
14063                )
14064            });
14065        })
14066    }
14067
14068    pub fn move_to_previous_subword_start(
14069        &mut self,
14070        _: &MoveToPreviousSubwordStart,
14071        window: &mut Window,
14072        cx: &mut Context<Self>,
14073    ) {
14074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14075        self.change_selections(Default::default(), window, cx, |s| {
14076            s.move_cursors_with(|map, head, _| {
14077                (
14078                    movement::previous_subword_start(map, head),
14079                    SelectionGoal::None,
14080                )
14081            });
14082        })
14083    }
14084
14085    pub fn select_to_previous_word_start(
14086        &mut self,
14087        _: &SelectToPreviousWordStart,
14088        window: &mut Window,
14089        cx: &mut Context<Self>,
14090    ) {
14091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14092        self.change_selections(Default::default(), window, cx, |s| {
14093            s.move_heads_with(|map, head, _| {
14094                (
14095                    movement::previous_word_start(map, head),
14096                    SelectionGoal::None,
14097                )
14098            });
14099        })
14100    }
14101
14102    pub fn select_to_previous_subword_start(
14103        &mut self,
14104        _: &SelectToPreviousSubwordStart,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) {
14108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14109        self.change_selections(Default::default(), window, cx, |s| {
14110            s.move_heads_with(|map, head, _| {
14111                (
14112                    movement::previous_subword_start(map, head),
14113                    SelectionGoal::None,
14114                )
14115            });
14116        })
14117    }
14118
14119    pub fn delete_to_previous_word_start(
14120        &mut self,
14121        action: &DeleteToPreviousWordStart,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14126        self.transact(window, cx, |this, window, cx| {
14127            this.select_autoclose_pair(window, cx);
14128            this.change_selections(Default::default(), window, cx, |s| {
14129                s.move_with(|map, selection| {
14130                    if selection.is_empty() {
14131                        let mut cursor = if action.ignore_newlines {
14132                            movement::previous_word_start(map, selection.head())
14133                        } else {
14134                            movement::previous_word_start_or_newline(map, selection.head())
14135                        };
14136                        cursor = movement::adjust_greedy_deletion(
14137                            map,
14138                            selection.head(),
14139                            cursor,
14140                            action.ignore_brackets,
14141                        );
14142                        selection.set_head(cursor, SelectionGoal::None);
14143                    }
14144                });
14145            });
14146            this.insert("", window, cx);
14147        });
14148    }
14149
14150    pub fn delete_to_previous_subword_start(
14151        &mut self,
14152        _: &DeleteToPreviousSubwordStart,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14157        self.transact(window, cx, |this, window, cx| {
14158            this.select_autoclose_pair(window, cx);
14159            this.change_selections(Default::default(), window, cx, |s| {
14160                s.move_with(|map, selection| {
14161                    if selection.is_empty() {
14162                        let mut cursor = movement::previous_subword_start(map, selection.head());
14163                        cursor =
14164                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14165                        selection.set_head(cursor, SelectionGoal::None);
14166                    }
14167                });
14168            });
14169            this.insert("", window, cx);
14170        });
14171    }
14172
14173    pub fn move_to_next_word_end(
14174        &mut self,
14175        _: &MoveToNextWordEnd,
14176        window: &mut Window,
14177        cx: &mut Context<Self>,
14178    ) {
14179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14180        self.change_selections(Default::default(), window, cx, |s| {
14181            s.move_cursors_with(|map, head, _| {
14182                (movement::next_word_end(map, head), SelectionGoal::None)
14183            });
14184        })
14185    }
14186
14187    pub fn move_to_next_subword_end(
14188        &mut self,
14189        _: &MoveToNextSubwordEnd,
14190        window: &mut Window,
14191        cx: &mut Context<Self>,
14192    ) {
14193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14194        self.change_selections(Default::default(), window, cx, |s| {
14195            s.move_cursors_with(|map, head, _| {
14196                (movement::next_subword_end(map, head), SelectionGoal::None)
14197            });
14198        })
14199    }
14200
14201    pub fn select_to_next_word_end(
14202        &mut self,
14203        _: &SelectToNextWordEnd,
14204        window: &mut Window,
14205        cx: &mut Context<Self>,
14206    ) {
14207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14208        self.change_selections(Default::default(), window, cx, |s| {
14209            s.move_heads_with(|map, head, _| {
14210                (movement::next_word_end(map, head), SelectionGoal::None)
14211            });
14212        })
14213    }
14214
14215    pub fn select_to_next_subword_end(
14216        &mut self,
14217        _: &SelectToNextSubwordEnd,
14218        window: &mut Window,
14219        cx: &mut Context<Self>,
14220    ) {
14221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14222        self.change_selections(Default::default(), window, cx, |s| {
14223            s.move_heads_with(|map, head, _| {
14224                (movement::next_subword_end(map, head), SelectionGoal::None)
14225            });
14226        })
14227    }
14228
14229    pub fn delete_to_next_word_end(
14230        &mut self,
14231        action: &DeleteToNextWordEnd,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14236        self.transact(window, cx, |this, window, cx| {
14237            this.change_selections(Default::default(), window, cx, |s| {
14238                s.move_with(|map, selection| {
14239                    if selection.is_empty() {
14240                        let mut cursor = if action.ignore_newlines {
14241                            movement::next_word_end(map, selection.head())
14242                        } else {
14243                            movement::next_word_end_or_newline(map, selection.head())
14244                        };
14245                        cursor = movement::adjust_greedy_deletion(
14246                            map,
14247                            selection.head(),
14248                            cursor,
14249                            action.ignore_brackets,
14250                        );
14251                        selection.set_head(cursor, SelectionGoal::None);
14252                    }
14253                });
14254            });
14255            this.insert("", window, cx);
14256        });
14257    }
14258
14259    pub fn delete_to_next_subword_end(
14260        &mut self,
14261        _: &DeleteToNextSubwordEnd,
14262        window: &mut Window,
14263        cx: &mut Context<Self>,
14264    ) {
14265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14266        self.transact(window, cx, |this, window, cx| {
14267            this.change_selections(Default::default(), window, cx, |s| {
14268                s.move_with(|map, selection| {
14269                    if selection.is_empty() {
14270                        let mut cursor = movement::next_subword_end(map, selection.head());
14271                        cursor =
14272                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14273                        selection.set_head(cursor, SelectionGoal::None);
14274                    }
14275                });
14276            });
14277            this.insert("", window, cx);
14278        });
14279    }
14280
14281    pub fn move_to_beginning_of_line(
14282        &mut self,
14283        action: &MoveToBeginningOfLine,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288        self.change_selections(Default::default(), window, cx, |s| {
14289            s.move_cursors_with(|map, head, _| {
14290                (
14291                    movement::indented_line_beginning(
14292                        map,
14293                        head,
14294                        action.stop_at_soft_wraps,
14295                        action.stop_at_indent,
14296                    ),
14297                    SelectionGoal::None,
14298                )
14299            });
14300        })
14301    }
14302
14303    pub fn select_to_beginning_of_line(
14304        &mut self,
14305        action: &SelectToBeginningOfLine,
14306        window: &mut Window,
14307        cx: &mut Context<Self>,
14308    ) {
14309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14310        self.change_selections(Default::default(), window, cx, |s| {
14311            s.move_heads_with(|map, head, _| {
14312                (
14313                    movement::indented_line_beginning(
14314                        map,
14315                        head,
14316                        action.stop_at_soft_wraps,
14317                        action.stop_at_indent,
14318                    ),
14319                    SelectionGoal::None,
14320                )
14321            });
14322        });
14323    }
14324
14325    pub fn delete_to_beginning_of_line(
14326        &mut self,
14327        action: &DeleteToBeginningOfLine,
14328        window: &mut Window,
14329        cx: &mut Context<Self>,
14330    ) {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14332        self.transact(window, cx, |this, window, cx| {
14333            this.change_selections(Default::default(), window, cx, |s| {
14334                s.move_with(|_, selection| {
14335                    selection.reversed = true;
14336                });
14337            });
14338
14339            this.select_to_beginning_of_line(
14340                &SelectToBeginningOfLine {
14341                    stop_at_soft_wraps: false,
14342                    stop_at_indent: action.stop_at_indent,
14343                },
14344                window,
14345                cx,
14346            );
14347            this.backspace(&Backspace, window, cx);
14348        });
14349    }
14350
14351    pub fn move_to_end_of_line(
14352        &mut self,
14353        action: &MoveToEndOfLine,
14354        window: &mut Window,
14355        cx: &mut Context<Self>,
14356    ) {
14357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14358        self.change_selections(Default::default(), window, cx, |s| {
14359            s.move_cursors_with(|map, head, _| {
14360                (
14361                    movement::line_end(map, head, action.stop_at_soft_wraps),
14362                    SelectionGoal::None,
14363                )
14364            });
14365        })
14366    }
14367
14368    pub fn select_to_end_of_line(
14369        &mut self,
14370        action: &SelectToEndOfLine,
14371        window: &mut Window,
14372        cx: &mut Context<Self>,
14373    ) {
14374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14375        self.change_selections(Default::default(), window, cx, |s| {
14376            s.move_heads_with(|map, head, _| {
14377                (
14378                    movement::line_end(map, head, action.stop_at_soft_wraps),
14379                    SelectionGoal::None,
14380                )
14381            });
14382        })
14383    }
14384
14385    pub fn delete_to_end_of_line(
14386        &mut self,
14387        _: &DeleteToEndOfLine,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) {
14391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14392        self.transact(window, cx, |this, window, cx| {
14393            this.select_to_end_of_line(
14394                &SelectToEndOfLine {
14395                    stop_at_soft_wraps: false,
14396                },
14397                window,
14398                cx,
14399            );
14400            this.delete(&Delete, window, cx);
14401        });
14402    }
14403
14404    pub fn cut_to_end_of_line(
14405        &mut self,
14406        action: &CutToEndOfLine,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) {
14410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14411        self.transact(window, cx, |this, window, cx| {
14412            this.select_to_end_of_line(
14413                &SelectToEndOfLine {
14414                    stop_at_soft_wraps: false,
14415                },
14416                window,
14417                cx,
14418            );
14419            if !action.stop_at_newlines {
14420                this.change_selections(Default::default(), window, cx, |s| {
14421                    s.move_with(|_, sel| {
14422                        if sel.is_empty() {
14423                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14424                        }
14425                    });
14426                });
14427            }
14428            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14429            let item = this.cut_common(false, window, cx);
14430            cx.write_to_clipboard(item);
14431        });
14432    }
14433
14434    pub fn move_to_start_of_paragraph(
14435        &mut self,
14436        _: &MoveToStartOfParagraph,
14437        window: &mut Window,
14438        cx: &mut Context<Self>,
14439    ) {
14440        if matches!(self.mode, EditorMode::SingleLine) {
14441            cx.propagate();
14442            return;
14443        }
14444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14445        self.change_selections(Default::default(), window, cx, |s| {
14446            s.move_with(|map, selection| {
14447                selection.collapse_to(
14448                    movement::start_of_paragraph(map, selection.head(), 1),
14449                    SelectionGoal::None,
14450                )
14451            });
14452        })
14453    }
14454
14455    pub fn move_to_end_of_paragraph(
14456        &mut self,
14457        _: &MoveToEndOfParagraph,
14458        window: &mut Window,
14459        cx: &mut Context<Self>,
14460    ) {
14461        if matches!(self.mode, EditorMode::SingleLine) {
14462            cx.propagate();
14463            return;
14464        }
14465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14466        self.change_selections(Default::default(), window, cx, |s| {
14467            s.move_with(|map, selection| {
14468                selection.collapse_to(
14469                    movement::end_of_paragraph(map, selection.head(), 1),
14470                    SelectionGoal::None,
14471                )
14472            });
14473        })
14474    }
14475
14476    pub fn select_to_start_of_paragraph(
14477        &mut self,
14478        _: &SelectToStartOfParagraph,
14479        window: &mut Window,
14480        cx: &mut Context<Self>,
14481    ) {
14482        if matches!(self.mode, EditorMode::SingleLine) {
14483            cx.propagate();
14484            return;
14485        }
14486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14487        self.change_selections(Default::default(), window, cx, |s| {
14488            s.move_heads_with(|map, head, _| {
14489                (
14490                    movement::start_of_paragraph(map, head, 1),
14491                    SelectionGoal::None,
14492                )
14493            });
14494        })
14495    }
14496
14497    pub fn select_to_end_of_paragraph(
14498        &mut self,
14499        _: &SelectToEndOfParagraph,
14500        window: &mut Window,
14501        cx: &mut Context<Self>,
14502    ) {
14503        if matches!(self.mode, EditorMode::SingleLine) {
14504            cx.propagate();
14505            return;
14506        }
14507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14508        self.change_selections(Default::default(), window, cx, |s| {
14509            s.move_heads_with(|map, head, _| {
14510                (
14511                    movement::end_of_paragraph(map, head, 1),
14512                    SelectionGoal::None,
14513                )
14514            });
14515        })
14516    }
14517
14518    pub fn move_to_start_of_excerpt(
14519        &mut self,
14520        _: &MoveToStartOfExcerpt,
14521        window: &mut Window,
14522        cx: &mut Context<Self>,
14523    ) {
14524        if matches!(self.mode, EditorMode::SingleLine) {
14525            cx.propagate();
14526            return;
14527        }
14528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14529        self.change_selections(Default::default(), window, cx, |s| {
14530            s.move_with(|map, selection| {
14531                selection.collapse_to(
14532                    movement::start_of_excerpt(
14533                        map,
14534                        selection.head(),
14535                        workspace::searchable::Direction::Prev,
14536                    ),
14537                    SelectionGoal::None,
14538                )
14539            });
14540        })
14541    }
14542
14543    pub fn move_to_start_of_next_excerpt(
14544        &mut self,
14545        _: &MoveToStartOfNextExcerpt,
14546        window: &mut Window,
14547        cx: &mut Context<Self>,
14548    ) {
14549        if matches!(self.mode, EditorMode::SingleLine) {
14550            cx.propagate();
14551            return;
14552        }
14553
14554        self.change_selections(Default::default(), window, cx, |s| {
14555            s.move_with(|map, selection| {
14556                selection.collapse_to(
14557                    movement::start_of_excerpt(
14558                        map,
14559                        selection.head(),
14560                        workspace::searchable::Direction::Next,
14561                    ),
14562                    SelectionGoal::None,
14563                )
14564            });
14565        })
14566    }
14567
14568    pub fn move_to_end_of_excerpt(
14569        &mut self,
14570        _: &MoveToEndOfExcerpt,
14571        window: &mut Window,
14572        cx: &mut Context<Self>,
14573    ) {
14574        if matches!(self.mode, EditorMode::SingleLine) {
14575            cx.propagate();
14576            return;
14577        }
14578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14579        self.change_selections(Default::default(), window, cx, |s| {
14580            s.move_with(|map, selection| {
14581                selection.collapse_to(
14582                    movement::end_of_excerpt(
14583                        map,
14584                        selection.head(),
14585                        workspace::searchable::Direction::Next,
14586                    ),
14587                    SelectionGoal::None,
14588                )
14589            });
14590        })
14591    }
14592
14593    pub fn move_to_end_of_previous_excerpt(
14594        &mut self,
14595        _: &MoveToEndOfPreviousExcerpt,
14596        window: &mut Window,
14597        cx: &mut Context<Self>,
14598    ) {
14599        if matches!(self.mode, EditorMode::SingleLine) {
14600            cx.propagate();
14601            return;
14602        }
14603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14604        self.change_selections(Default::default(), window, cx, |s| {
14605            s.move_with(|map, selection| {
14606                selection.collapse_to(
14607                    movement::end_of_excerpt(
14608                        map,
14609                        selection.head(),
14610                        workspace::searchable::Direction::Prev,
14611                    ),
14612                    SelectionGoal::None,
14613                )
14614            });
14615        })
14616    }
14617
14618    pub fn select_to_start_of_excerpt(
14619        &mut self,
14620        _: &SelectToStartOfExcerpt,
14621        window: &mut Window,
14622        cx: &mut Context<Self>,
14623    ) {
14624        if matches!(self.mode, EditorMode::SingleLine) {
14625            cx.propagate();
14626            return;
14627        }
14628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14629        self.change_selections(Default::default(), window, cx, |s| {
14630            s.move_heads_with(|map, head, _| {
14631                (
14632                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14633                    SelectionGoal::None,
14634                )
14635            });
14636        })
14637    }
14638
14639    pub fn select_to_start_of_next_excerpt(
14640        &mut self,
14641        _: &SelectToStartOfNextExcerpt,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) {
14645        if matches!(self.mode, EditorMode::SingleLine) {
14646            cx.propagate();
14647            return;
14648        }
14649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14650        self.change_selections(Default::default(), window, cx, |s| {
14651            s.move_heads_with(|map, head, _| {
14652                (
14653                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14654                    SelectionGoal::None,
14655                )
14656            });
14657        })
14658    }
14659
14660    pub fn select_to_end_of_excerpt(
14661        &mut self,
14662        _: &SelectToEndOfExcerpt,
14663        window: &mut Window,
14664        cx: &mut Context<Self>,
14665    ) {
14666        if matches!(self.mode, EditorMode::SingleLine) {
14667            cx.propagate();
14668            return;
14669        }
14670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14671        self.change_selections(Default::default(), window, cx, |s| {
14672            s.move_heads_with(|map, head, _| {
14673                (
14674                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14675                    SelectionGoal::None,
14676                )
14677            });
14678        })
14679    }
14680
14681    pub fn select_to_end_of_previous_excerpt(
14682        &mut self,
14683        _: &SelectToEndOfPreviousExcerpt,
14684        window: &mut Window,
14685        cx: &mut Context<Self>,
14686    ) {
14687        if matches!(self.mode, EditorMode::SingleLine) {
14688            cx.propagate();
14689            return;
14690        }
14691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14692        self.change_selections(Default::default(), window, cx, |s| {
14693            s.move_heads_with(|map, head, _| {
14694                (
14695                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14696                    SelectionGoal::None,
14697                )
14698            });
14699        })
14700    }
14701
14702    pub fn move_to_beginning(
14703        &mut self,
14704        _: &MoveToBeginning,
14705        window: &mut Window,
14706        cx: &mut Context<Self>,
14707    ) {
14708        if matches!(self.mode, EditorMode::SingleLine) {
14709            cx.propagate();
14710            return;
14711        }
14712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14713        self.change_selections(Default::default(), window, cx, |s| {
14714            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14715        });
14716    }
14717
14718    pub fn select_to_beginning(
14719        &mut self,
14720        _: &SelectToBeginning,
14721        window: &mut Window,
14722        cx: &mut Context<Self>,
14723    ) {
14724        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14725        selection.set_head(Point::zero(), SelectionGoal::None);
14726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14727        self.change_selections(Default::default(), window, cx, |s| {
14728            s.select(vec![selection]);
14729        });
14730    }
14731
14732    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14733        if matches!(self.mode, EditorMode::SingleLine) {
14734            cx.propagate();
14735            return;
14736        }
14737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14738        let cursor = self.buffer.read(cx).read(cx).len();
14739        self.change_selections(Default::default(), window, cx, |s| {
14740            s.select_ranges(vec![cursor..cursor])
14741        });
14742    }
14743
14744    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14745        self.nav_history = nav_history;
14746    }
14747
14748    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14749        self.nav_history.as_ref()
14750    }
14751
14752    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14753        self.push_to_nav_history(
14754            self.selections.newest_anchor().head(),
14755            None,
14756            false,
14757            true,
14758            cx,
14759        );
14760    }
14761
14762    fn push_to_nav_history(
14763        &mut self,
14764        cursor_anchor: Anchor,
14765        new_position: Option<Point>,
14766        is_deactivate: bool,
14767        always: bool,
14768        cx: &mut Context<Self>,
14769    ) {
14770        if let Some(nav_history) = self.nav_history.as_mut() {
14771            let buffer = self.buffer.read(cx).read(cx);
14772            let cursor_position = cursor_anchor.to_point(&buffer);
14773            let scroll_state = self.scroll_manager.anchor();
14774            let scroll_top_row = scroll_state.top_row(&buffer);
14775            drop(buffer);
14776
14777            if let Some(new_position) = new_position {
14778                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14779                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14780                    return;
14781                }
14782            }
14783
14784            nav_history.push(
14785                Some(NavigationData {
14786                    cursor_anchor,
14787                    cursor_position,
14788                    scroll_anchor: scroll_state,
14789                    scroll_top_row,
14790                }),
14791                cx,
14792            );
14793            cx.emit(EditorEvent::PushedToNavHistory {
14794                anchor: cursor_anchor,
14795                is_deactivate,
14796            })
14797        }
14798    }
14799
14800    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14802        let buffer = self.buffer.read(cx).snapshot(cx);
14803        let mut selection = self
14804            .selections
14805            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14806        selection.set_head(buffer.len(), SelectionGoal::None);
14807        self.change_selections(Default::default(), window, cx, |s| {
14808            s.select(vec![selection]);
14809        });
14810    }
14811
14812    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14814        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14815            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14816        });
14817    }
14818
14819    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14822        let mut selections = self.selections.all::<Point>(&display_map);
14823        let max_point = display_map.buffer_snapshot().max_point();
14824        for selection in &mut selections {
14825            let rows = selection.spanned_rows(true, &display_map);
14826            selection.start = Point::new(rows.start.0, 0);
14827            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14828            selection.reversed = false;
14829        }
14830        self.change_selections(Default::default(), window, cx, |s| {
14831            s.select(selections);
14832        });
14833    }
14834
14835    pub fn split_selection_into_lines(
14836        &mut self,
14837        action: &SplitSelectionIntoLines,
14838        window: &mut Window,
14839        cx: &mut Context<Self>,
14840    ) {
14841        let selections = self
14842            .selections
14843            .all::<Point>(&self.display_snapshot(cx))
14844            .into_iter()
14845            .map(|selection| selection.start..selection.end)
14846            .collect::<Vec<_>>();
14847        self.unfold_ranges(&selections, true, true, cx);
14848
14849        let mut new_selection_ranges = Vec::new();
14850        {
14851            let buffer = self.buffer.read(cx).read(cx);
14852            for selection in selections {
14853                for row in selection.start.row..selection.end.row {
14854                    let line_start = Point::new(row, 0);
14855                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14856
14857                    if action.keep_selections {
14858                        // Keep the selection range for each line
14859                        let selection_start = if row == selection.start.row {
14860                            selection.start
14861                        } else {
14862                            line_start
14863                        };
14864                        new_selection_ranges.push(selection_start..line_end);
14865                    } else {
14866                        // Collapse to cursor at end of line
14867                        new_selection_ranges.push(line_end..line_end);
14868                    }
14869                }
14870
14871                let is_multiline_selection = selection.start.row != selection.end.row;
14872                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14873                // so this action feels more ergonomic when paired with other selection operations
14874                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14875                if !should_skip_last {
14876                    if action.keep_selections {
14877                        if is_multiline_selection {
14878                            let line_start = Point::new(selection.end.row, 0);
14879                            new_selection_ranges.push(line_start..selection.end);
14880                        } else {
14881                            new_selection_ranges.push(selection.start..selection.end);
14882                        }
14883                    } else {
14884                        new_selection_ranges.push(selection.end..selection.end);
14885                    }
14886                }
14887            }
14888        }
14889        self.change_selections(Default::default(), window, cx, |s| {
14890            s.select_ranges(new_selection_ranges);
14891        });
14892    }
14893
14894    pub fn add_selection_above(
14895        &mut self,
14896        action: &AddSelectionAbove,
14897        window: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) {
14900        self.add_selection(true, action.skip_soft_wrap, window, cx);
14901    }
14902
14903    pub fn add_selection_below(
14904        &mut self,
14905        action: &AddSelectionBelow,
14906        window: &mut Window,
14907        cx: &mut Context<Self>,
14908    ) {
14909        self.add_selection(false, action.skip_soft_wrap, window, cx);
14910    }
14911
14912    fn add_selection(
14913        &mut self,
14914        above: bool,
14915        skip_soft_wrap: bool,
14916        window: &mut Window,
14917        cx: &mut Context<Self>,
14918    ) {
14919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14920
14921        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14922        let all_selections = self.selections.all::<Point>(&display_map);
14923        let text_layout_details = self.text_layout_details(window);
14924
14925        let (mut columnar_selections, new_selections_to_columnarize) = {
14926            if let Some(state) = self.add_selections_state.as_ref() {
14927                let columnar_selection_ids: HashSet<_> = state
14928                    .groups
14929                    .iter()
14930                    .flat_map(|group| group.stack.iter())
14931                    .copied()
14932                    .collect();
14933
14934                all_selections
14935                    .into_iter()
14936                    .partition(|s| columnar_selection_ids.contains(&s.id))
14937            } else {
14938                (Vec::new(), all_selections)
14939            }
14940        };
14941
14942        let mut state = self
14943            .add_selections_state
14944            .take()
14945            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14946
14947        for selection in new_selections_to_columnarize {
14948            let range = selection.display_range(&display_map).sorted();
14949            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14950            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14951            let positions = start_x.min(end_x)..start_x.max(end_x);
14952            let mut stack = Vec::new();
14953            for row in range.start.row().0..=range.end.row().0 {
14954                if let Some(selection) = self.selections.build_columnar_selection(
14955                    &display_map,
14956                    DisplayRow(row),
14957                    &positions,
14958                    selection.reversed,
14959                    &text_layout_details,
14960                ) {
14961                    stack.push(selection.id);
14962                    columnar_selections.push(selection);
14963                }
14964            }
14965            if !stack.is_empty() {
14966                if above {
14967                    stack.reverse();
14968                }
14969                state.groups.push(AddSelectionsGroup { above, stack });
14970            }
14971        }
14972
14973        let mut final_selections = Vec::new();
14974        let end_row = if above {
14975            DisplayRow(0)
14976        } else {
14977            display_map.max_point().row()
14978        };
14979
14980        let mut last_added_item_per_group = HashMap::default();
14981        for group in state.groups.iter_mut() {
14982            if let Some(last_id) = group.stack.last() {
14983                last_added_item_per_group.insert(*last_id, group);
14984            }
14985        }
14986
14987        for selection in columnar_selections {
14988            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14989                if above == group.above {
14990                    let range = selection.display_range(&display_map).sorted();
14991                    debug_assert_eq!(range.start.row(), range.end.row());
14992                    let mut row = range.start.row();
14993                    let positions =
14994                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14995                            Pixels::from(start)..Pixels::from(end)
14996                        } else {
14997                            let start_x =
14998                                display_map.x_for_display_point(range.start, &text_layout_details);
14999                            let end_x =
15000                                display_map.x_for_display_point(range.end, &text_layout_details);
15001                            start_x.min(end_x)..start_x.max(end_x)
15002                        };
15003
15004                    let mut maybe_new_selection = None;
15005                    let direction = if above { -1 } else { 1 };
15006
15007                    while row != end_row {
15008                        let new_buffer_row = if skip_soft_wrap {
15009                            let new_row = display_map
15010                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15011                            row = new_row.row();
15012                            Some(new_row.to_point(&display_map).row)
15013                        } else {
15014                            if above {
15015                                row.0 -= 1;
15016                            } else {
15017                                row.0 += 1;
15018                            }
15019                            None
15020                        };
15021
15022                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15023                            let start_col = selection.start.column;
15024                            let end_col = selection.end.column;
15025                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15026
15027                            self.selections
15028                                .build_columnar_selection_from_buffer_columns(
15029                                    &display_map,
15030                                    buffer_row,
15031                                    &buffer_columns,
15032                                    selection.reversed,
15033                                    &text_layout_details,
15034                                )
15035                        } else {
15036                            self.selections.build_columnar_selection(
15037                                &display_map,
15038                                row,
15039                                &positions,
15040                                selection.reversed,
15041                                &text_layout_details,
15042                            )
15043                        };
15044
15045                        if let Some(new_selection) = new_selection {
15046                            maybe_new_selection = Some(new_selection);
15047                            break;
15048                        }
15049                    }
15050
15051                    if let Some(new_selection) = maybe_new_selection {
15052                        group.stack.push(new_selection.id);
15053                        if above {
15054                            final_selections.push(new_selection);
15055                            final_selections.push(selection);
15056                        } else {
15057                            final_selections.push(selection);
15058                            final_selections.push(new_selection);
15059                        }
15060                    } else {
15061                        final_selections.push(selection);
15062                    }
15063                } else {
15064                    group.stack.pop();
15065                }
15066            } else {
15067                final_selections.push(selection);
15068            }
15069        }
15070
15071        self.change_selections(Default::default(), window, cx, |s| {
15072            s.select(final_selections);
15073        });
15074
15075        let final_selection_ids: HashSet<_> = self
15076            .selections
15077            .all::<Point>(&display_map)
15078            .iter()
15079            .map(|s| s.id)
15080            .collect();
15081        state.groups.retain_mut(|group| {
15082            // selections might get merged above so we remove invalid items from stacks
15083            group.stack.retain(|id| final_selection_ids.contains(id));
15084
15085            // single selection in stack can be treated as initial state
15086            group.stack.len() > 1
15087        });
15088
15089        if !state.groups.is_empty() {
15090            self.add_selections_state = Some(state);
15091        }
15092    }
15093
15094    pub fn insert_snippet_at_selections(
15095        &mut self,
15096        action: &InsertSnippet,
15097        window: &mut Window,
15098        cx: &mut Context<Self>,
15099    ) {
15100        self.try_insert_snippet_at_selections(action, window, cx)
15101            .log_err();
15102    }
15103
15104    fn try_insert_snippet_at_selections(
15105        &mut self,
15106        action: &InsertSnippet,
15107        window: &mut Window,
15108        cx: &mut Context<Self>,
15109    ) -> Result<()> {
15110        let insertion_ranges = self
15111            .selections
15112            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15113            .into_iter()
15114            .map(|selection| selection.range())
15115            .collect_vec();
15116
15117        let snippet = if let Some(snippet_body) = &action.snippet {
15118            if action.language.is_none() && action.name.is_none() {
15119                Snippet::parse(snippet_body)?
15120            } else {
15121                bail!("`snippet` is mutually exclusive with `language` and `name`")
15122            }
15123        } else if let Some(name) = &action.name {
15124            let project = self.project().context("no project")?;
15125            let snippet_store = project.read(cx).snippets().read(cx);
15126            let snippet = snippet_store
15127                .snippets_for(action.language.clone(), cx)
15128                .into_iter()
15129                .find(|snippet| snippet.name == *name)
15130                .context("snippet not found")?;
15131            Snippet::parse(&snippet.body)?
15132        } else {
15133            // todo(andrew): open modal to select snippet
15134            bail!("`name` or `snippet` is required")
15135        };
15136
15137        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15138    }
15139
15140    fn select_match_ranges(
15141        &mut self,
15142        range: Range<MultiBufferOffset>,
15143        reversed: bool,
15144        replace_newest: bool,
15145        auto_scroll: Option<Autoscroll>,
15146        window: &mut Window,
15147        cx: &mut Context<Editor>,
15148    ) {
15149        self.unfold_ranges(
15150            std::slice::from_ref(&range),
15151            false,
15152            auto_scroll.is_some(),
15153            cx,
15154        );
15155        let effects = if let Some(scroll) = auto_scroll {
15156            SelectionEffects::scroll(scroll)
15157        } else {
15158            SelectionEffects::no_scroll()
15159        };
15160        self.change_selections(effects, window, cx, |s| {
15161            if replace_newest {
15162                s.delete(s.newest_anchor().id);
15163            }
15164            if reversed {
15165                s.insert_range(range.end..range.start);
15166            } else {
15167                s.insert_range(range);
15168            }
15169        });
15170    }
15171
15172    pub fn select_next_match_internal(
15173        &mut self,
15174        display_map: &DisplaySnapshot,
15175        replace_newest: bool,
15176        autoscroll: Option<Autoscroll>,
15177        window: &mut Window,
15178        cx: &mut Context<Self>,
15179    ) -> Result<()> {
15180        let buffer = display_map.buffer_snapshot();
15181        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15182        if let Some(mut select_next_state) = self.select_next_state.take() {
15183            let query = &select_next_state.query;
15184            if !select_next_state.done {
15185                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15186                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15187                let mut next_selected_range = None;
15188
15189                let bytes_after_last_selection =
15190                    buffer.bytes_in_range(last_selection.end..buffer.len());
15191                let bytes_before_first_selection =
15192                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15193                let query_matches = query
15194                    .stream_find_iter(bytes_after_last_selection)
15195                    .map(|result| (last_selection.end, result))
15196                    .chain(
15197                        query
15198                            .stream_find_iter(bytes_before_first_selection)
15199                            .map(|result| (MultiBufferOffset(0), result)),
15200                    );
15201
15202                for (start_offset, query_match) in query_matches {
15203                    let query_match = query_match.unwrap(); // can only fail due to I/O
15204                    let offset_range =
15205                        start_offset + query_match.start()..start_offset + query_match.end();
15206
15207                    if !select_next_state.wordwise
15208                        || (!buffer.is_inside_word(offset_range.start, None)
15209                            && !buffer.is_inside_word(offset_range.end, None))
15210                    {
15211                        let idx = selections
15212                            .partition_point(|selection| selection.end <= offset_range.start);
15213                        let overlaps = selections
15214                            .get(idx)
15215                            .map_or(false, |selection| selection.start < offset_range.end);
15216
15217                        if !overlaps {
15218                            next_selected_range = Some(offset_range);
15219                            break;
15220                        }
15221                    }
15222                }
15223
15224                if let Some(next_selected_range) = next_selected_range {
15225                    self.select_match_ranges(
15226                        next_selected_range,
15227                        last_selection.reversed,
15228                        replace_newest,
15229                        autoscroll,
15230                        window,
15231                        cx,
15232                    );
15233                } else {
15234                    select_next_state.done = true;
15235                }
15236            }
15237
15238            self.select_next_state = Some(select_next_state);
15239        } else {
15240            let mut only_carets = true;
15241            let mut same_text_selected = true;
15242            let mut selected_text = None;
15243
15244            let mut selections_iter = selections.iter().peekable();
15245            while let Some(selection) = selections_iter.next() {
15246                if selection.start != selection.end {
15247                    only_carets = false;
15248                }
15249
15250                if same_text_selected {
15251                    if selected_text.is_none() {
15252                        selected_text =
15253                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15254                    }
15255
15256                    if let Some(next_selection) = selections_iter.peek() {
15257                        if next_selection.len() == selection.len() {
15258                            let next_selected_text = buffer
15259                                .text_for_range(next_selection.range())
15260                                .collect::<String>();
15261                            if Some(next_selected_text) != selected_text {
15262                                same_text_selected = false;
15263                                selected_text = None;
15264                            }
15265                        } else {
15266                            same_text_selected = false;
15267                            selected_text = None;
15268                        }
15269                    }
15270                }
15271            }
15272
15273            if only_carets {
15274                for selection in &mut selections {
15275                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15276                    selection.start = word_range.start;
15277                    selection.end = word_range.end;
15278                    selection.goal = SelectionGoal::None;
15279                    selection.reversed = false;
15280                    self.select_match_ranges(
15281                        selection.start..selection.end,
15282                        selection.reversed,
15283                        replace_newest,
15284                        autoscroll,
15285                        window,
15286                        cx,
15287                    );
15288                }
15289
15290                if selections.len() == 1 {
15291                    let selection = selections
15292                        .last()
15293                        .expect("ensured that there's only one selection");
15294                    let query = buffer
15295                        .text_for_range(selection.start..selection.end)
15296                        .collect::<String>();
15297                    let is_empty = query.is_empty();
15298                    let select_state = SelectNextState {
15299                        query: self.build_query(&[query], cx)?,
15300                        wordwise: true,
15301                        done: is_empty,
15302                    };
15303                    self.select_next_state = Some(select_state);
15304                } else {
15305                    self.select_next_state = None;
15306                }
15307            } else if let Some(selected_text) = selected_text {
15308                self.select_next_state = Some(SelectNextState {
15309                    query: self.build_query(&[selected_text], cx)?,
15310                    wordwise: false,
15311                    done: false,
15312                });
15313                self.select_next_match_internal(
15314                    display_map,
15315                    replace_newest,
15316                    autoscroll,
15317                    window,
15318                    cx,
15319                )?;
15320            }
15321        }
15322        Ok(())
15323    }
15324
15325    pub fn select_all_matches(
15326        &mut self,
15327        _action: &SelectAllMatches,
15328        window: &mut Window,
15329        cx: &mut Context<Self>,
15330    ) -> Result<()> {
15331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15332
15333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15334
15335        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15336        let Some(select_next_state) = self.select_next_state.as_mut() else {
15337            return Ok(());
15338        };
15339        if select_next_state.done {
15340            return Ok(());
15341        }
15342
15343        let mut new_selections = Vec::new();
15344
15345        let reversed = self
15346            .selections
15347            .oldest::<MultiBufferOffset>(&display_map)
15348            .reversed;
15349        let buffer = display_map.buffer_snapshot();
15350        let query_matches = select_next_state
15351            .query
15352            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15353
15354        for query_match in query_matches.into_iter() {
15355            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15356            let offset_range = if reversed {
15357                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15358            } else {
15359                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15360            };
15361
15362            if !select_next_state.wordwise
15363                || (!buffer.is_inside_word(offset_range.start, None)
15364                    && !buffer.is_inside_word(offset_range.end, None))
15365            {
15366                new_selections.push(offset_range.start..offset_range.end);
15367            }
15368        }
15369
15370        select_next_state.done = true;
15371
15372        if new_selections.is_empty() {
15373            log::error!("bug: new_selections is empty in select_all_matches");
15374            return Ok(());
15375        }
15376
15377        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15378        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15379            selections.select_ranges(new_selections)
15380        });
15381
15382        Ok(())
15383    }
15384
15385    pub fn select_next(
15386        &mut self,
15387        action: &SelectNext,
15388        window: &mut Window,
15389        cx: &mut Context<Self>,
15390    ) -> Result<()> {
15391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15393        self.select_next_match_internal(
15394            &display_map,
15395            action.replace_newest,
15396            Some(Autoscroll::newest()),
15397            window,
15398            cx,
15399        )?;
15400        Ok(())
15401    }
15402
15403    pub fn select_previous(
15404        &mut self,
15405        action: &SelectPrevious,
15406        window: &mut Window,
15407        cx: &mut Context<Self>,
15408    ) -> Result<()> {
15409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15410        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15411        let buffer = display_map.buffer_snapshot();
15412        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15413        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15414            let query = &select_prev_state.query;
15415            if !select_prev_state.done {
15416                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15417                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15418                let mut next_selected_range = None;
15419                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15420                let bytes_before_last_selection =
15421                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15422                let bytes_after_first_selection =
15423                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15424                let query_matches = query
15425                    .stream_find_iter(bytes_before_last_selection)
15426                    .map(|result| (last_selection.start, result))
15427                    .chain(
15428                        query
15429                            .stream_find_iter(bytes_after_first_selection)
15430                            .map(|result| (buffer.len(), result)),
15431                    );
15432                for (end_offset, query_match) in query_matches {
15433                    let query_match = query_match.unwrap(); // can only fail due to I/O
15434                    let offset_range =
15435                        end_offset - query_match.end()..end_offset - query_match.start();
15436
15437                    if !select_prev_state.wordwise
15438                        || (!buffer.is_inside_word(offset_range.start, None)
15439                            && !buffer.is_inside_word(offset_range.end, None))
15440                    {
15441                        next_selected_range = Some(offset_range);
15442                        break;
15443                    }
15444                }
15445
15446                if let Some(next_selected_range) = next_selected_range {
15447                    self.select_match_ranges(
15448                        next_selected_range,
15449                        last_selection.reversed,
15450                        action.replace_newest,
15451                        Some(Autoscroll::newest()),
15452                        window,
15453                        cx,
15454                    );
15455                } else {
15456                    select_prev_state.done = true;
15457                }
15458            }
15459
15460            self.select_prev_state = Some(select_prev_state);
15461        } else {
15462            let mut only_carets = true;
15463            let mut same_text_selected = true;
15464            let mut selected_text = None;
15465
15466            let mut selections_iter = selections.iter().peekable();
15467            while let Some(selection) = selections_iter.next() {
15468                if selection.start != selection.end {
15469                    only_carets = false;
15470                }
15471
15472                if same_text_selected {
15473                    if selected_text.is_none() {
15474                        selected_text =
15475                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15476                    }
15477
15478                    if let Some(next_selection) = selections_iter.peek() {
15479                        if next_selection.len() == selection.len() {
15480                            let next_selected_text = buffer
15481                                .text_for_range(next_selection.range())
15482                                .collect::<String>();
15483                            if Some(next_selected_text) != selected_text {
15484                                same_text_selected = false;
15485                                selected_text = None;
15486                            }
15487                        } else {
15488                            same_text_selected = false;
15489                            selected_text = None;
15490                        }
15491                    }
15492                }
15493            }
15494
15495            if only_carets {
15496                for selection in &mut selections {
15497                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15498                    selection.start = word_range.start;
15499                    selection.end = word_range.end;
15500                    selection.goal = SelectionGoal::None;
15501                    selection.reversed = false;
15502                    self.select_match_ranges(
15503                        selection.start..selection.end,
15504                        selection.reversed,
15505                        action.replace_newest,
15506                        Some(Autoscroll::newest()),
15507                        window,
15508                        cx,
15509                    );
15510                }
15511                if selections.len() == 1 {
15512                    let selection = selections
15513                        .last()
15514                        .expect("ensured that there's only one selection");
15515                    let query = buffer
15516                        .text_for_range(selection.start..selection.end)
15517                        .collect::<String>();
15518                    let is_empty = query.is_empty();
15519                    let select_state = SelectNextState {
15520                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15521                        wordwise: true,
15522                        done: is_empty,
15523                    };
15524                    self.select_prev_state = Some(select_state);
15525                } else {
15526                    self.select_prev_state = None;
15527                }
15528            } else if let Some(selected_text) = selected_text {
15529                self.select_prev_state = Some(SelectNextState {
15530                    query: self
15531                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15532                    wordwise: false,
15533                    done: false,
15534                });
15535                self.select_previous(action, window, cx)?;
15536            }
15537        }
15538        Ok(())
15539    }
15540
15541    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15542    /// setting the case sensitivity based on the global
15543    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15544    /// editor's settings.
15545    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15546    where
15547        I: IntoIterator<Item = P>,
15548        P: AsRef<[u8]>,
15549    {
15550        let case_sensitive = self
15551            .select_next_is_case_sensitive
15552            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15553
15554        let mut builder = AhoCorasickBuilder::new();
15555        builder.ascii_case_insensitive(!case_sensitive);
15556        builder.build(patterns)
15557    }
15558
15559    pub fn find_next_match(
15560        &mut self,
15561        _: &FindNextMatch,
15562        window: &mut Window,
15563        cx: &mut Context<Self>,
15564    ) -> Result<()> {
15565        let selections = self.selections.disjoint_anchors_arc();
15566        match selections.first() {
15567            Some(first) if selections.len() >= 2 => {
15568                self.change_selections(Default::default(), window, cx, |s| {
15569                    s.select_ranges([first.range()]);
15570                });
15571            }
15572            _ => self.select_next(
15573                &SelectNext {
15574                    replace_newest: true,
15575                },
15576                window,
15577                cx,
15578            )?,
15579        }
15580        Ok(())
15581    }
15582
15583    pub fn find_previous_match(
15584        &mut self,
15585        _: &FindPreviousMatch,
15586        window: &mut Window,
15587        cx: &mut Context<Self>,
15588    ) -> Result<()> {
15589        let selections = self.selections.disjoint_anchors_arc();
15590        match selections.last() {
15591            Some(last) if selections.len() >= 2 => {
15592                self.change_selections(Default::default(), window, cx, |s| {
15593                    s.select_ranges([last.range()]);
15594                });
15595            }
15596            _ => self.select_previous(
15597                &SelectPrevious {
15598                    replace_newest: true,
15599                },
15600                window,
15601                cx,
15602            )?,
15603        }
15604        Ok(())
15605    }
15606
15607    pub fn toggle_comments(
15608        &mut self,
15609        action: &ToggleComments,
15610        window: &mut Window,
15611        cx: &mut Context<Self>,
15612    ) {
15613        if self.read_only(cx) {
15614            return;
15615        }
15616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15617        let text_layout_details = &self.text_layout_details(window);
15618        self.transact(window, cx, |this, window, cx| {
15619            let mut selections = this
15620                .selections
15621                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15622            let mut edits = Vec::new();
15623            let mut selection_edit_ranges = Vec::new();
15624            let mut last_toggled_row = None;
15625            let snapshot = this.buffer.read(cx).read(cx);
15626            let empty_str: Arc<str> = Arc::default();
15627            let mut suffixes_inserted = Vec::new();
15628            let ignore_indent = action.ignore_indent;
15629
15630            fn comment_prefix_range(
15631                snapshot: &MultiBufferSnapshot,
15632                row: MultiBufferRow,
15633                comment_prefix: &str,
15634                comment_prefix_whitespace: &str,
15635                ignore_indent: bool,
15636            ) -> Range<Point> {
15637                let indent_size = if ignore_indent {
15638                    0
15639                } else {
15640                    snapshot.indent_size_for_line(row).len
15641                };
15642
15643                let start = Point::new(row.0, indent_size);
15644
15645                let mut line_bytes = snapshot
15646                    .bytes_in_range(start..snapshot.max_point())
15647                    .flatten()
15648                    .copied();
15649
15650                // If this line currently begins with the line comment prefix, then record
15651                // the range containing the prefix.
15652                if line_bytes
15653                    .by_ref()
15654                    .take(comment_prefix.len())
15655                    .eq(comment_prefix.bytes())
15656                {
15657                    // Include any whitespace that matches the comment prefix.
15658                    let matching_whitespace_len = line_bytes
15659                        .zip(comment_prefix_whitespace.bytes())
15660                        .take_while(|(a, b)| a == b)
15661                        .count() as u32;
15662                    let end = Point::new(
15663                        start.row,
15664                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15665                    );
15666                    start..end
15667                } else {
15668                    start..start
15669                }
15670            }
15671
15672            fn comment_suffix_range(
15673                snapshot: &MultiBufferSnapshot,
15674                row: MultiBufferRow,
15675                comment_suffix: &str,
15676                comment_suffix_has_leading_space: bool,
15677            ) -> Range<Point> {
15678                let end = Point::new(row.0, snapshot.line_len(row));
15679                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15680
15681                let mut line_end_bytes = snapshot
15682                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15683                    .flatten()
15684                    .copied();
15685
15686                let leading_space_len = if suffix_start_column > 0
15687                    && line_end_bytes.next() == Some(b' ')
15688                    && comment_suffix_has_leading_space
15689                {
15690                    1
15691                } else {
15692                    0
15693                };
15694
15695                // If this line currently begins with the line comment prefix, then record
15696                // the range containing the prefix.
15697                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15698                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15699                    start..end
15700                } else {
15701                    end..end
15702                }
15703            }
15704
15705            // TODO: Handle selections that cross excerpts
15706            for selection in &mut selections {
15707                let start_column = snapshot
15708                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15709                    .len;
15710                let language = if let Some(language) =
15711                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15712                {
15713                    language
15714                } else {
15715                    continue;
15716                };
15717
15718                selection_edit_ranges.clear();
15719
15720                // If multiple selections contain a given row, avoid processing that
15721                // row more than once.
15722                let mut start_row = MultiBufferRow(selection.start.row);
15723                if last_toggled_row == Some(start_row) {
15724                    start_row = start_row.next_row();
15725                }
15726                let end_row =
15727                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15728                        MultiBufferRow(selection.end.row - 1)
15729                    } else {
15730                        MultiBufferRow(selection.end.row)
15731                    };
15732                last_toggled_row = Some(end_row);
15733
15734                if start_row > end_row {
15735                    continue;
15736                }
15737
15738                // If the language has line comments, toggle those.
15739                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15740
15741                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15742                if ignore_indent {
15743                    full_comment_prefixes = full_comment_prefixes
15744                        .into_iter()
15745                        .map(|s| Arc::from(s.trim_end()))
15746                        .collect();
15747                }
15748
15749                if !full_comment_prefixes.is_empty() {
15750                    let first_prefix = full_comment_prefixes
15751                        .first()
15752                        .expect("prefixes is non-empty");
15753                    let prefix_trimmed_lengths = full_comment_prefixes
15754                        .iter()
15755                        .map(|p| p.trim_end_matches(' ').len())
15756                        .collect::<SmallVec<[usize; 4]>>();
15757
15758                    let mut all_selection_lines_are_comments = true;
15759
15760                    for row in start_row.0..=end_row.0 {
15761                        let row = MultiBufferRow(row);
15762                        if start_row < end_row && snapshot.is_line_blank(row) {
15763                            continue;
15764                        }
15765
15766                        let prefix_range = full_comment_prefixes
15767                            .iter()
15768                            .zip(prefix_trimmed_lengths.iter().copied())
15769                            .map(|(prefix, trimmed_prefix_len)| {
15770                                comment_prefix_range(
15771                                    snapshot.deref(),
15772                                    row,
15773                                    &prefix[..trimmed_prefix_len],
15774                                    &prefix[trimmed_prefix_len..],
15775                                    ignore_indent,
15776                                )
15777                            })
15778                            .max_by_key(|range| range.end.column - range.start.column)
15779                            .expect("prefixes is non-empty");
15780
15781                        if prefix_range.is_empty() {
15782                            all_selection_lines_are_comments = false;
15783                        }
15784
15785                        selection_edit_ranges.push(prefix_range);
15786                    }
15787
15788                    if all_selection_lines_are_comments {
15789                        edits.extend(
15790                            selection_edit_ranges
15791                                .iter()
15792                                .cloned()
15793                                .map(|range| (range, empty_str.clone())),
15794                        );
15795                    } else {
15796                        let min_column = selection_edit_ranges
15797                            .iter()
15798                            .map(|range| range.start.column)
15799                            .min()
15800                            .unwrap_or(0);
15801                        edits.extend(selection_edit_ranges.iter().map(|range| {
15802                            let position = Point::new(range.start.row, min_column);
15803                            (position..position, first_prefix.clone())
15804                        }));
15805                    }
15806                } else if let Some(BlockCommentConfig {
15807                    start: full_comment_prefix,
15808                    end: comment_suffix,
15809                    ..
15810                }) = language.block_comment()
15811                {
15812                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15813                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15814                    let prefix_range = comment_prefix_range(
15815                        snapshot.deref(),
15816                        start_row,
15817                        comment_prefix,
15818                        comment_prefix_whitespace,
15819                        ignore_indent,
15820                    );
15821                    let suffix_range = comment_suffix_range(
15822                        snapshot.deref(),
15823                        end_row,
15824                        comment_suffix.trim_start_matches(' '),
15825                        comment_suffix.starts_with(' '),
15826                    );
15827
15828                    if prefix_range.is_empty() || suffix_range.is_empty() {
15829                        edits.push((
15830                            prefix_range.start..prefix_range.start,
15831                            full_comment_prefix.clone(),
15832                        ));
15833                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15834                        suffixes_inserted.push((end_row, comment_suffix.len()));
15835                    } else {
15836                        edits.push((prefix_range, empty_str.clone()));
15837                        edits.push((suffix_range, empty_str.clone()));
15838                    }
15839                } else {
15840                    continue;
15841                }
15842            }
15843
15844            drop(snapshot);
15845            this.buffer.update(cx, |buffer, cx| {
15846                buffer.edit(edits, None, cx);
15847            });
15848
15849            // Adjust selections so that they end before any comment suffixes that
15850            // were inserted.
15851            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15852            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15853            let snapshot = this.buffer.read(cx).read(cx);
15854            for selection in &mut selections {
15855                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15856                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15857                        Ordering::Less => {
15858                            suffixes_inserted.next();
15859                            continue;
15860                        }
15861                        Ordering::Greater => break,
15862                        Ordering::Equal => {
15863                            if selection.end.column == snapshot.line_len(row) {
15864                                if selection.is_empty() {
15865                                    selection.start.column -= suffix_len as u32;
15866                                }
15867                                selection.end.column -= suffix_len as u32;
15868                            }
15869                            break;
15870                        }
15871                    }
15872                }
15873            }
15874
15875            drop(snapshot);
15876            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15877
15878            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15879            let selections_on_single_row = selections.windows(2).all(|selections| {
15880                selections[0].start.row == selections[1].start.row
15881                    && selections[0].end.row == selections[1].end.row
15882                    && selections[0].start.row == selections[0].end.row
15883            });
15884            let selections_selecting = selections
15885                .iter()
15886                .any(|selection| selection.start != selection.end);
15887            let advance_downwards = action.advance_downwards
15888                && selections_on_single_row
15889                && !selections_selecting
15890                && !matches!(this.mode, EditorMode::SingleLine);
15891
15892            if advance_downwards {
15893                let snapshot = this.buffer.read(cx).snapshot(cx);
15894
15895                this.change_selections(Default::default(), window, cx, |s| {
15896                    s.move_cursors_with(|display_snapshot, display_point, _| {
15897                        let mut point = display_point.to_point(display_snapshot);
15898                        point.row += 1;
15899                        point = snapshot.clip_point(point, Bias::Left);
15900                        let display_point = point.to_display_point(display_snapshot);
15901                        let goal = SelectionGoal::HorizontalPosition(
15902                            display_snapshot
15903                                .x_for_display_point(display_point, text_layout_details)
15904                                .into(),
15905                        );
15906                        (display_point, goal)
15907                    })
15908                });
15909            }
15910        });
15911    }
15912
15913    pub fn select_enclosing_symbol(
15914        &mut self,
15915        _: &SelectEnclosingSymbol,
15916        window: &mut Window,
15917        cx: &mut Context<Self>,
15918    ) {
15919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15920
15921        let buffer = self.buffer.read(cx).snapshot(cx);
15922        let old_selections = self
15923            .selections
15924            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15925            .into_boxed_slice();
15926
15927        fn update_selection(
15928            selection: &Selection<MultiBufferOffset>,
15929            buffer_snap: &MultiBufferSnapshot,
15930        ) -> Option<Selection<MultiBufferOffset>> {
15931            let cursor = selection.head();
15932            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15933            for symbol in symbols.iter().rev() {
15934                let start = symbol.range.start.to_offset(buffer_snap);
15935                let end = symbol.range.end.to_offset(buffer_snap);
15936                let new_range = start..end;
15937                if start < selection.start || end > selection.end {
15938                    return Some(Selection {
15939                        id: selection.id,
15940                        start: new_range.start,
15941                        end: new_range.end,
15942                        goal: SelectionGoal::None,
15943                        reversed: selection.reversed,
15944                    });
15945                }
15946            }
15947            None
15948        }
15949
15950        let mut selected_larger_symbol = false;
15951        let new_selections = old_selections
15952            .iter()
15953            .map(|selection| match update_selection(selection, &buffer) {
15954                Some(new_selection) => {
15955                    if new_selection.range() != selection.range() {
15956                        selected_larger_symbol = true;
15957                    }
15958                    new_selection
15959                }
15960                None => selection.clone(),
15961            })
15962            .collect::<Vec<_>>();
15963
15964        if selected_larger_symbol {
15965            self.change_selections(Default::default(), window, cx, |s| {
15966                s.select(new_selections);
15967            });
15968        }
15969    }
15970
15971    pub fn select_larger_syntax_node(
15972        &mut self,
15973        _: &SelectLargerSyntaxNode,
15974        window: &mut Window,
15975        cx: &mut Context<Self>,
15976    ) {
15977        let Some(visible_row_count) = self.visible_row_count() else {
15978            return;
15979        };
15980        let old_selections: Box<[_]> = self
15981            .selections
15982            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15983            .into();
15984        if old_selections.is_empty() {
15985            return;
15986        }
15987
15988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15989
15990        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15991        let buffer = self.buffer.read(cx).snapshot(cx);
15992
15993        let mut selected_larger_node = false;
15994        let mut new_selections = old_selections
15995            .iter()
15996            .map(|selection| {
15997                let old_range = selection.start..selection.end;
15998
15999                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16000                    // manually select word at selection
16001                    if ["string_content", "inline"].contains(&node.kind()) {
16002                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16003                        // ignore if word is already selected
16004                        if !word_range.is_empty() && old_range != word_range {
16005                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16006                            // only select word if start and end point belongs to same word
16007                            if word_range == last_word_range {
16008                                selected_larger_node = true;
16009                                return Selection {
16010                                    id: selection.id,
16011                                    start: word_range.start,
16012                                    end: word_range.end,
16013                                    goal: SelectionGoal::None,
16014                                    reversed: selection.reversed,
16015                                };
16016                            }
16017                        }
16018                    }
16019                }
16020
16021                let mut new_range = old_range.clone();
16022                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16023                    new_range = range;
16024                    if !node.is_named() {
16025                        continue;
16026                    }
16027                    if !display_map.intersects_fold(new_range.start)
16028                        && !display_map.intersects_fold(new_range.end)
16029                    {
16030                        break;
16031                    }
16032                }
16033
16034                selected_larger_node |= new_range != old_range;
16035                Selection {
16036                    id: selection.id,
16037                    start: new_range.start,
16038                    end: new_range.end,
16039                    goal: SelectionGoal::None,
16040                    reversed: selection.reversed,
16041                }
16042            })
16043            .collect::<Vec<_>>();
16044
16045        if !selected_larger_node {
16046            return; // don't put this call in the history
16047        }
16048
16049        // scroll based on transformation done to the last selection created by the user
16050        let (last_old, last_new) = old_selections
16051            .last()
16052            .zip(new_selections.last().cloned())
16053            .expect("old_selections isn't empty");
16054
16055        // revert selection
16056        let is_selection_reversed = {
16057            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16058            new_selections.last_mut().expect("checked above").reversed =
16059                should_newest_selection_be_reversed;
16060            should_newest_selection_be_reversed
16061        };
16062
16063        if selected_larger_node {
16064            self.select_syntax_node_history.disable_clearing = true;
16065            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16066                s.select(new_selections.clone());
16067            });
16068            self.select_syntax_node_history.disable_clearing = false;
16069        }
16070
16071        let start_row = last_new.start.to_display_point(&display_map).row().0;
16072        let end_row = last_new.end.to_display_point(&display_map).row().0;
16073        let selection_height = end_row - start_row + 1;
16074        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16075
16076        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16077        let scroll_behavior = if fits_on_the_screen {
16078            self.request_autoscroll(Autoscroll::fit(), cx);
16079            SelectSyntaxNodeScrollBehavior::FitSelection
16080        } else if is_selection_reversed {
16081            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16082            SelectSyntaxNodeScrollBehavior::CursorTop
16083        } else {
16084            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16085            SelectSyntaxNodeScrollBehavior::CursorBottom
16086        };
16087
16088        self.select_syntax_node_history.push((
16089            old_selections,
16090            scroll_behavior,
16091            is_selection_reversed,
16092        ));
16093    }
16094
16095    pub fn select_smaller_syntax_node(
16096        &mut self,
16097        _: &SelectSmallerSyntaxNode,
16098        window: &mut Window,
16099        cx: &mut Context<Self>,
16100    ) {
16101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16102
16103        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16104            self.select_syntax_node_history.pop()
16105        {
16106            if let Some(selection) = selections.last_mut() {
16107                selection.reversed = is_selection_reversed;
16108            }
16109
16110            self.select_syntax_node_history.disable_clearing = true;
16111            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16112                s.select(selections.to_vec());
16113            });
16114            self.select_syntax_node_history.disable_clearing = false;
16115
16116            match scroll_behavior {
16117                SelectSyntaxNodeScrollBehavior::CursorTop => {
16118                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16119                }
16120                SelectSyntaxNodeScrollBehavior::FitSelection => {
16121                    self.request_autoscroll(Autoscroll::fit(), cx);
16122                }
16123                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16124                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16125                }
16126            }
16127        }
16128    }
16129
16130    pub fn unwrap_syntax_node(
16131        &mut self,
16132        _: &UnwrapSyntaxNode,
16133        window: &mut Window,
16134        cx: &mut Context<Self>,
16135    ) {
16136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16137
16138        let buffer = self.buffer.read(cx).snapshot(cx);
16139        let selections = self
16140            .selections
16141            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16142            .into_iter()
16143            // subtracting the offset requires sorting
16144            .sorted_by_key(|i| i.start);
16145
16146        let full_edits = selections
16147            .into_iter()
16148            .filter_map(|selection| {
16149                let child = if selection.is_empty()
16150                    && let Some((_, ancestor_range)) =
16151                        buffer.syntax_ancestor(selection.start..selection.end)
16152                {
16153                    ancestor_range
16154                } else {
16155                    selection.range()
16156                };
16157
16158                let mut parent = child.clone();
16159                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16160                    parent = ancestor_range;
16161                    if parent.start < child.start || parent.end > child.end {
16162                        break;
16163                    }
16164                }
16165
16166                if parent == child {
16167                    return None;
16168                }
16169                let text = buffer.text_for_range(child).collect::<String>();
16170                Some((selection.id, parent, text))
16171            })
16172            .collect::<Vec<_>>();
16173        if full_edits.is_empty() {
16174            return;
16175        }
16176
16177        self.transact(window, cx, |this, window, cx| {
16178            this.buffer.update(cx, |buffer, cx| {
16179                buffer.edit(
16180                    full_edits
16181                        .iter()
16182                        .map(|(_, p, t)| (p.clone(), t.clone()))
16183                        .collect::<Vec<_>>(),
16184                    None,
16185                    cx,
16186                );
16187            });
16188            this.change_selections(Default::default(), window, cx, |s| {
16189                let mut offset = 0;
16190                let mut selections = vec![];
16191                for (id, parent, text) in full_edits {
16192                    let start = parent.start - offset;
16193                    offset += (parent.end - parent.start) - text.len();
16194                    selections.push(Selection {
16195                        id,
16196                        start,
16197                        end: start + text.len(),
16198                        reversed: false,
16199                        goal: Default::default(),
16200                    });
16201                }
16202                s.select(selections);
16203            });
16204        });
16205    }
16206
16207    pub fn select_next_syntax_node(
16208        &mut self,
16209        _: &SelectNextSyntaxNode,
16210        window: &mut Window,
16211        cx: &mut Context<Self>,
16212    ) {
16213        let old_selections: Box<[_]> = self
16214            .selections
16215            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16216            .into();
16217        if old_selections.is_empty() {
16218            return;
16219        }
16220
16221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16222
16223        let buffer = self.buffer.read(cx).snapshot(cx);
16224        let mut selected_sibling = false;
16225
16226        let new_selections = old_selections
16227            .iter()
16228            .map(|selection| {
16229                let old_range = selection.start..selection.end;
16230
16231                let old_range =
16232                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16233                let excerpt = buffer.excerpt_containing(old_range.clone());
16234
16235                if let Some(mut excerpt) = excerpt
16236                    && let Some(node) = excerpt
16237                        .buffer()
16238                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16239                {
16240                    let new_range = excerpt.map_range_from_buffer(
16241                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16242                    );
16243                    selected_sibling = true;
16244                    Selection {
16245                        id: selection.id,
16246                        start: new_range.start,
16247                        end: new_range.end,
16248                        goal: SelectionGoal::None,
16249                        reversed: selection.reversed,
16250                    }
16251                } else {
16252                    selection.clone()
16253                }
16254            })
16255            .collect::<Vec<_>>();
16256
16257        if selected_sibling {
16258            self.change_selections(
16259                SelectionEffects::scroll(Autoscroll::fit()),
16260                window,
16261                cx,
16262                |s| {
16263                    s.select(new_selections);
16264                },
16265            );
16266        }
16267    }
16268
16269    pub fn select_prev_syntax_node(
16270        &mut self,
16271        _: &SelectPreviousSyntaxNode,
16272        window: &mut Window,
16273        cx: &mut Context<Self>,
16274    ) {
16275        let old_selections: Box<[_]> = self
16276            .selections
16277            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16278            .into();
16279        if old_selections.is_empty() {
16280            return;
16281        }
16282
16283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16284
16285        let buffer = self.buffer.read(cx).snapshot(cx);
16286        let mut selected_sibling = false;
16287
16288        let new_selections = old_selections
16289            .iter()
16290            .map(|selection| {
16291                let old_range = selection.start..selection.end;
16292                let old_range =
16293                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16294                let excerpt = buffer.excerpt_containing(old_range.clone());
16295
16296                if let Some(mut excerpt) = excerpt
16297                    && let Some(node) = excerpt
16298                        .buffer()
16299                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16300                {
16301                    let new_range = excerpt.map_range_from_buffer(
16302                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16303                    );
16304                    selected_sibling = true;
16305                    Selection {
16306                        id: selection.id,
16307                        start: new_range.start,
16308                        end: new_range.end,
16309                        goal: SelectionGoal::None,
16310                        reversed: selection.reversed,
16311                    }
16312                } else {
16313                    selection.clone()
16314                }
16315            })
16316            .collect::<Vec<_>>();
16317
16318        if selected_sibling {
16319            self.change_selections(
16320                SelectionEffects::scroll(Autoscroll::fit()),
16321                window,
16322                cx,
16323                |s| {
16324                    s.select(new_selections);
16325                },
16326            );
16327        }
16328    }
16329
16330    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16331        if !EditorSettings::get_global(cx).gutter.runnables {
16332            self.clear_tasks();
16333            return Task::ready(());
16334        }
16335        let project = self.project().map(Entity::downgrade);
16336        let task_sources = self.lsp_task_sources(cx);
16337        let multi_buffer = self.buffer.downgrade();
16338        cx.spawn_in(window, async move |editor, cx| {
16339            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16340            let Some(project) = project.and_then(|p| p.upgrade()) else {
16341                return;
16342            };
16343            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16344                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16345            }) else {
16346                return;
16347            };
16348
16349            let hide_runnables = project
16350                .update(cx, |project, _| project.is_via_collab())
16351                .unwrap_or(true);
16352            if hide_runnables {
16353                return;
16354            }
16355            let new_rows =
16356                cx.background_spawn({
16357                    let snapshot = display_snapshot.clone();
16358                    async move {
16359                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16360                    }
16361                })
16362                    .await;
16363            let Ok(lsp_tasks) =
16364                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16365            else {
16366                return;
16367            };
16368            let lsp_tasks = lsp_tasks.await;
16369
16370            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16371                lsp_tasks
16372                    .into_iter()
16373                    .flat_map(|(kind, tasks)| {
16374                        tasks.into_iter().filter_map(move |(location, task)| {
16375                            Some((kind.clone(), location?, task))
16376                        })
16377                    })
16378                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16379                        let buffer = location.target.buffer;
16380                        let buffer_snapshot = buffer.read(cx).snapshot();
16381                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16382                            |(excerpt_id, snapshot, _)| {
16383                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16384                                    display_snapshot
16385                                        .buffer_snapshot()
16386                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16387                                } else {
16388                                    None
16389                                }
16390                            },
16391                        );
16392                        if let Some(offset) = offset {
16393                            let task_buffer_range =
16394                                location.target.range.to_point(&buffer_snapshot);
16395                            let context_buffer_range =
16396                                task_buffer_range.to_offset(&buffer_snapshot);
16397                            let context_range = BufferOffset(context_buffer_range.start)
16398                                ..BufferOffset(context_buffer_range.end);
16399
16400                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16401                                .or_insert_with(|| RunnableTasks {
16402                                    templates: Vec::new(),
16403                                    offset,
16404                                    column: task_buffer_range.start.column,
16405                                    extra_variables: HashMap::default(),
16406                                    context_range,
16407                                })
16408                                .templates
16409                                .push((kind, task.original_task().clone()));
16410                        }
16411
16412                        acc
16413                    })
16414            }) else {
16415                return;
16416            };
16417
16418            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16419                buffer.language_settings(cx).tasks.prefer_lsp
16420            }) else {
16421                return;
16422            };
16423
16424            let rows = Self::runnable_rows(
16425                project,
16426                display_snapshot,
16427                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16428                new_rows,
16429                cx.clone(),
16430            )
16431            .await;
16432            editor
16433                .update(cx, |editor, _| {
16434                    editor.clear_tasks();
16435                    for (key, mut value) in rows {
16436                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16437                            value.templates.extend(lsp_tasks.templates);
16438                        }
16439
16440                        editor.insert_tasks(key, value);
16441                    }
16442                    for (key, value) in lsp_tasks_by_rows {
16443                        editor.insert_tasks(key, value);
16444                    }
16445                })
16446                .ok();
16447        })
16448    }
16449    fn fetch_runnable_ranges(
16450        snapshot: &DisplaySnapshot,
16451        range: Range<Anchor>,
16452    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16453        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16454    }
16455
16456    fn runnable_rows(
16457        project: Entity<Project>,
16458        snapshot: DisplaySnapshot,
16459        prefer_lsp: bool,
16460        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16461        cx: AsyncWindowContext,
16462    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16463        cx.spawn(async move |cx| {
16464            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16465            for (run_range, mut runnable) in runnable_ranges {
16466                let Some(tasks) = cx
16467                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16468                    .ok()
16469                else {
16470                    continue;
16471                };
16472                let mut tasks = tasks.await;
16473
16474                if prefer_lsp {
16475                    tasks.retain(|(task_kind, _)| {
16476                        !matches!(task_kind, TaskSourceKind::Language { .. })
16477                    });
16478                }
16479                if tasks.is_empty() {
16480                    continue;
16481                }
16482
16483                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16484                let Some(row) = snapshot
16485                    .buffer_snapshot()
16486                    .buffer_line_for_row(MultiBufferRow(point.row))
16487                    .map(|(_, range)| range.start.row)
16488                else {
16489                    continue;
16490                };
16491
16492                let context_range =
16493                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16494                runnable_rows.push((
16495                    (runnable.buffer_id, row),
16496                    RunnableTasks {
16497                        templates: tasks,
16498                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16499                        context_range,
16500                        column: point.column,
16501                        extra_variables: runnable.extra_captures,
16502                    },
16503                ));
16504            }
16505            runnable_rows
16506        })
16507    }
16508
16509    fn templates_with_tags(
16510        project: &Entity<Project>,
16511        runnable: &mut Runnable,
16512        cx: &mut App,
16513    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16514        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16515            let (worktree_id, file) = project
16516                .buffer_for_id(runnable.buffer, cx)
16517                .and_then(|buffer| buffer.read(cx).file())
16518                .map(|file| (file.worktree_id(cx), file.clone()))
16519                .unzip();
16520
16521            (
16522                project.task_store().read(cx).task_inventory().cloned(),
16523                worktree_id,
16524                file,
16525            )
16526        });
16527
16528        let tags = mem::take(&mut runnable.tags);
16529        let language = runnable.language.clone();
16530        cx.spawn(async move |cx| {
16531            let mut templates_with_tags = Vec::new();
16532            if let Some(inventory) = inventory {
16533                for RunnableTag(tag) in tags {
16534                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16535                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16536                    }) else {
16537                        return templates_with_tags;
16538                    };
16539                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16540                        move |(_, template)| {
16541                            template.tags.iter().any(|source_tag| source_tag == &tag)
16542                        },
16543                    ));
16544                }
16545            }
16546            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16547
16548            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16549                // Strongest source wins; if we have worktree tag binding, prefer that to
16550                // global and language bindings;
16551                // if we have a global binding, prefer that to language binding.
16552                let first_mismatch = templates_with_tags
16553                    .iter()
16554                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16555                if let Some(index) = first_mismatch {
16556                    templates_with_tags.truncate(index);
16557                }
16558            }
16559
16560            templates_with_tags
16561        })
16562    }
16563
16564    pub fn move_to_enclosing_bracket(
16565        &mut self,
16566        _: &MoveToEnclosingBracket,
16567        window: &mut Window,
16568        cx: &mut Context<Self>,
16569    ) {
16570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16571        self.change_selections(Default::default(), window, cx, |s| {
16572            s.move_offsets_with(|snapshot, selection| {
16573                let Some(enclosing_bracket_ranges) =
16574                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16575                else {
16576                    return;
16577                };
16578
16579                let mut best_length = usize::MAX;
16580                let mut best_inside = false;
16581                let mut best_in_bracket_range = false;
16582                let mut best_destination = None;
16583                for (open, close) in enclosing_bracket_ranges {
16584                    let close = close.to_inclusive();
16585                    let length = *close.end() - open.start;
16586                    let inside = selection.start >= open.end && selection.end <= *close.start();
16587                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16588                        || close.contains(&selection.head());
16589
16590                    // If best is next to a bracket and current isn't, skip
16591                    if !in_bracket_range && best_in_bracket_range {
16592                        continue;
16593                    }
16594
16595                    // Prefer smaller lengths unless best is inside and current isn't
16596                    if length > best_length && (best_inside || !inside) {
16597                        continue;
16598                    }
16599
16600                    best_length = length;
16601                    best_inside = inside;
16602                    best_in_bracket_range = in_bracket_range;
16603                    best_destination = Some(
16604                        if close.contains(&selection.start) && close.contains(&selection.end) {
16605                            if inside { open.end } else { open.start }
16606                        } else if inside {
16607                            *close.start()
16608                        } else {
16609                            *close.end()
16610                        },
16611                    );
16612                }
16613
16614                if let Some(destination) = best_destination {
16615                    selection.collapse_to(destination, SelectionGoal::None);
16616                }
16617            })
16618        });
16619    }
16620
16621    pub fn undo_selection(
16622        &mut self,
16623        _: &UndoSelection,
16624        window: &mut Window,
16625        cx: &mut Context<Self>,
16626    ) {
16627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16628        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16629            self.selection_history.mode = SelectionHistoryMode::Undoing;
16630            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16631                this.end_selection(window, cx);
16632                this.change_selections(
16633                    SelectionEffects::scroll(Autoscroll::newest()),
16634                    window,
16635                    cx,
16636                    |s| s.select_anchors(entry.selections.to_vec()),
16637                );
16638            });
16639            self.selection_history.mode = SelectionHistoryMode::Normal;
16640
16641            self.select_next_state = entry.select_next_state;
16642            self.select_prev_state = entry.select_prev_state;
16643            self.add_selections_state = entry.add_selections_state;
16644        }
16645    }
16646
16647    pub fn redo_selection(
16648        &mut self,
16649        _: &RedoSelection,
16650        window: &mut Window,
16651        cx: &mut Context<Self>,
16652    ) {
16653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16654        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16655            self.selection_history.mode = SelectionHistoryMode::Redoing;
16656            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16657                this.end_selection(window, cx);
16658                this.change_selections(
16659                    SelectionEffects::scroll(Autoscroll::newest()),
16660                    window,
16661                    cx,
16662                    |s| s.select_anchors(entry.selections.to_vec()),
16663                );
16664            });
16665            self.selection_history.mode = SelectionHistoryMode::Normal;
16666
16667            self.select_next_state = entry.select_next_state;
16668            self.select_prev_state = entry.select_prev_state;
16669            self.add_selections_state = entry.add_selections_state;
16670        }
16671    }
16672
16673    pub fn expand_excerpts(
16674        &mut self,
16675        action: &ExpandExcerpts,
16676        _: &mut Window,
16677        cx: &mut Context<Self>,
16678    ) {
16679        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16680    }
16681
16682    pub fn expand_excerpts_down(
16683        &mut self,
16684        action: &ExpandExcerptsDown,
16685        _: &mut Window,
16686        cx: &mut Context<Self>,
16687    ) {
16688        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16689    }
16690
16691    pub fn expand_excerpts_up(
16692        &mut self,
16693        action: &ExpandExcerptsUp,
16694        _: &mut Window,
16695        cx: &mut Context<Self>,
16696    ) {
16697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16698    }
16699
16700    pub fn expand_excerpts_for_direction(
16701        &mut self,
16702        lines: u32,
16703        direction: ExpandExcerptDirection,
16704        cx: &mut Context<Self>,
16705    ) {
16706        let selections = self.selections.disjoint_anchors_arc();
16707
16708        let lines = if lines == 0 {
16709            EditorSettings::get_global(cx).expand_excerpt_lines
16710        } else {
16711            lines
16712        };
16713
16714        let snapshot = self.buffer.read(cx).snapshot(cx);
16715        let mut excerpt_ids = selections
16716            .iter()
16717            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16718            .collect::<Vec<_>>();
16719        excerpt_ids.sort();
16720        excerpt_ids.dedup();
16721
16722        if self.delegate_expand_excerpts {
16723            cx.emit(EditorEvent::ExpandExcerptsRequested {
16724                excerpt_ids,
16725                lines,
16726                direction,
16727            });
16728            return;
16729        }
16730
16731        self.buffer.update(cx, |buffer, cx| {
16732            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16733        })
16734    }
16735
16736    pub fn expand_excerpt(
16737        &mut self,
16738        excerpt: ExcerptId,
16739        direction: ExpandExcerptDirection,
16740        window: &mut Window,
16741        cx: &mut Context<Self>,
16742    ) {
16743        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16744
16745        if self.delegate_expand_excerpts {
16746            cx.emit(EditorEvent::ExpandExcerptsRequested {
16747                excerpt_ids: vec![excerpt],
16748                lines: lines_to_expand,
16749                direction,
16750            });
16751            return;
16752        }
16753
16754        let current_scroll_position = self.scroll_position(cx);
16755        let mut scroll = None;
16756
16757        if direction == ExpandExcerptDirection::Down {
16758            let multi_buffer = self.buffer.read(cx);
16759            let snapshot = multi_buffer.snapshot(cx);
16760            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16761                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16762                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16763            {
16764                let buffer_snapshot = buffer.read(cx).snapshot();
16765                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16766                let last_row = buffer_snapshot.max_point().row;
16767                let lines_below = last_row.saturating_sub(excerpt_end_row);
16768                if lines_below >= lines_to_expand {
16769                    scroll = Some(
16770                        current_scroll_position
16771                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16772                    );
16773                }
16774            }
16775        }
16776        if direction == ExpandExcerptDirection::Up
16777            && self
16778                .buffer
16779                .read(cx)
16780                .snapshot(cx)
16781                .excerpt_before(excerpt)
16782                .is_none()
16783        {
16784            scroll = Some(current_scroll_position);
16785        }
16786
16787        self.buffer.update(cx, |buffer, cx| {
16788            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16789        });
16790
16791        if let Some(new_scroll_position) = scroll {
16792            self.set_scroll_position(new_scroll_position, window, cx);
16793        }
16794    }
16795
16796    pub fn go_to_singleton_buffer_point(
16797        &mut self,
16798        point: Point,
16799        window: &mut Window,
16800        cx: &mut Context<Self>,
16801    ) {
16802        self.go_to_singleton_buffer_range(point..point, window, cx);
16803    }
16804
16805    pub fn go_to_singleton_buffer_range(
16806        &mut self,
16807        range: Range<Point>,
16808        window: &mut Window,
16809        cx: &mut Context<Self>,
16810    ) {
16811        let multibuffer = self.buffer().read(cx);
16812        let Some(buffer) = multibuffer.as_singleton() else {
16813            return;
16814        };
16815        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16816            return;
16817        };
16818        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16819            return;
16820        };
16821        self.change_selections(
16822            SelectionEffects::default().nav_history(true),
16823            window,
16824            cx,
16825            |s| s.select_anchor_ranges([start..end]),
16826        );
16827    }
16828
16829    pub fn go_to_diagnostic(
16830        &mut self,
16831        action: &GoToDiagnostic,
16832        window: &mut Window,
16833        cx: &mut Context<Self>,
16834    ) {
16835        if !self.diagnostics_enabled() {
16836            return;
16837        }
16838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16839        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16840    }
16841
16842    pub fn go_to_prev_diagnostic(
16843        &mut self,
16844        action: &GoToPreviousDiagnostic,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) {
16848        if !self.diagnostics_enabled() {
16849            return;
16850        }
16851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16852        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16853    }
16854
16855    pub fn go_to_diagnostic_impl(
16856        &mut self,
16857        direction: Direction,
16858        severity: GoToDiagnosticSeverityFilter,
16859        window: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let buffer = self.buffer.read(cx).snapshot(cx);
16863        let selection = self
16864            .selections
16865            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16866
16867        let mut active_group_id = None;
16868        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16869            && active_group.active_range.start.to_offset(&buffer) == selection.start
16870        {
16871            active_group_id = Some(active_group.group_id);
16872        }
16873
16874        fn filtered<'a>(
16875            severity: GoToDiagnosticSeverityFilter,
16876            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16877        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16878            diagnostics
16879                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16880                .filter(|entry| entry.range.start != entry.range.end)
16881                .filter(|entry| !entry.diagnostic.is_unnecessary)
16882        }
16883
16884        let before = filtered(
16885            severity,
16886            buffer
16887                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16888                .filter(|entry| entry.range.start <= selection.start),
16889        );
16890        let after = filtered(
16891            severity,
16892            buffer
16893                .diagnostics_in_range(selection.start..buffer.len())
16894                .filter(|entry| entry.range.start >= selection.start),
16895        );
16896
16897        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16898        if direction == Direction::Prev {
16899            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16900            {
16901                for diagnostic in prev_diagnostics.into_iter().rev() {
16902                    if diagnostic.range.start != selection.start
16903                        || active_group_id
16904                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16905                    {
16906                        found = Some(diagnostic);
16907                        break 'outer;
16908                    }
16909                }
16910            }
16911        } else {
16912            for diagnostic in after.chain(before) {
16913                if diagnostic.range.start != selection.start
16914                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16915                {
16916                    found = Some(diagnostic);
16917                    break;
16918                }
16919            }
16920        }
16921        let Some(next_diagnostic) = found else {
16922            return;
16923        };
16924
16925        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16926        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16927            return;
16928        };
16929        let snapshot = self.snapshot(window, cx);
16930        if snapshot.intersects_fold(next_diagnostic.range.start) {
16931            self.unfold_ranges(
16932                std::slice::from_ref(&next_diagnostic.range),
16933                true,
16934                false,
16935                cx,
16936            );
16937        }
16938        self.change_selections(Default::default(), window, cx, |s| {
16939            s.select_ranges(vec![
16940                next_diagnostic.range.start..next_diagnostic.range.start,
16941            ])
16942        });
16943        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16944        self.refresh_edit_prediction(false, true, window, cx);
16945    }
16946
16947    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16949        let snapshot = self.snapshot(window, cx);
16950        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16951        self.go_to_hunk_before_or_after_position(
16952            &snapshot,
16953            selection.head(),
16954            Direction::Next,
16955            window,
16956            cx,
16957        );
16958    }
16959
16960    pub fn go_to_hunk_before_or_after_position(
16961        &mut self,
16962        snapshot: &EditorSnapshot,
16963        position: Point,
16964        direction: Direction,
16965        window: &mut Window,
16966        cx: &mut Context<Editor>,
16967    ) {
16968        let row = if direction == Direction::Next {
16969            self.hunk_after_position(snapshot, position)
16970                .map(|hunk| hunk.row_range.start)
16971        } else {
16972            self.hunk_before_position(snapshot, position)
16973        };
16974
16975        if let Some(row) = row {
16976            let destination = Point::new(row.0, 0);
16977            let autoscroll = Autoscroll::center();
16978
16979            self.unfold_ranges(&[destination..destination], false, false, cx);
16980            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16981                s.select_ranges([destination..destination]);
16982            });
16983        }
16984    }
16985
16986    fn hunk_after_position(
16987        &mut self,
16988        snapshot: &EditorSnapshot,
16989        position: Point,
16990    ) -> Option<MultiBufferDiffHunk> {
16991        snapshot
16992            .buffer_snapshot()
16993            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16994            .find(|hunk| hunk.row_range.start.0 > position.row)
16995            .or_else(|| {
16996                snapshot
16997                    .buffer_snapshot()
16998                    .diff_hunks_in_range(Point::zero()..position)
16999                    .find(|hunk| hunk.row_range.end.0 < position.row)
17000            })
17001    }
17002
17003    fn go_to_prev_hunk(
17004        &mut self,
17005        _: &GoToPreviousHunk,
17006        window: &mut Window,
17007        cx: &mut Context<Self>,
17008    ) {
17009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17010        let snapshot = self.snapshot(window, cx);
17011        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17012        self.go_to_hunk_before_or_after_position(
17013            &snapshot,
17014            selection.head(),
17015            Direction::Prev,
17016            window,
17017            cx,
17018        );
17019    }
17020
17021    fn hunk_before_position(
17022        &mut self,
17023        snapshot: &EditorSnapshot,
17024        position: Point,
17025    ) -> Option<MultiBufferRow> {
17026        snapshot
17027            .buffer_snapshot()
17028            .diff_hunk_before(position)
17029            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17030    }
17031
17032    fn go_to_next_change(
17033        &mut self,
17034        _: &GoToNextChange,
17035        window: &mut Window,
17036        cx: &mut Context<Self>,
17037    ) {
17038        if let Some(selections) = self
17039            .change_list
17040            .next_change(1, Direction::Next)
17041            .map(|s| s.to_vec())
17042        {
17043            self.change_selections(Default::default(), window, cx, |s| {
17044                let map = s.display_snapshot();
17045                s.select_display_ranges(selections.iter().map(|a| {
17046                    let point = a.to_display_point(&map);
17047                    point..point
17048                }))
17049            })
17050        }
17051    }
17052
17053    fn go_to_previous_change(
17054        &mut self,
17055        _: &GoToPreviousChange,
17056        window: &mut Window,
17057        cx: &mut Context<Self>,
17058    ) {
17059        if let Some(selections) = self
17060            .change_list
17061            .next_change(1, Direction::Prev)
17062            .map(|s| s.to_vec())
17063        {
17064            self.change_selections(Default::default(), window, cx, |s| {
17065                let map = s.display_snapshot();
17066                s.select_display_ranges(selections.iter().map(|a| {
17067                    let point = a.to_display_point(&map);
17068                    point..point
17069                }))
17070            })
17071        }
17072    }
17073
17074    pub fn go_to_next_document_highlight(
17075        &mut self,
17076        _: &GoToNextDocumentHighlight,
17077        window: &mut Window,
17078        cx: &mut Context<Self>,
17079    ) {
17080        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17081    }
17082
17083    pub fn go_to_prev_document_highlight(
17084        &mut self,
17085        _: &GoToPreviousDocumentHighlight,
17086        window: &mut Window,
17087        cx: &mut Context<Self>,
17088    ) {
17089        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17090    }
17091
17092    pub fn go_to_document_highlight_before_or_after_position(
17093        &mut self,
17094        direction: Direction,
17095        window: &mut Window,
17096        cx: &mut Context<Editor>,
17097    ) {
17098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17099        let snapshot = self.snapshot(window, cx);
17100        let buffer = &snapshot.buffer_snapshot();
17101        let position = self
17102            .selections
17103            .newest::<Point>(&snapshot.display_snapshot)
17104            .head();
17105        let anchor_position = buffer.anchor_after(position);
17106
17107        // Get all document highlights (both read and write)
17108        let mut all_highlights = Vec::new();
17109
17110        if let Some((_, read_highlights)) = self
17111            .background_highlights
17112            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17113        {
17114            all_highlights.extend(read_highlights.iter());
17115        }
17116
17117        if let Some((_, write_highlights)) = self
17118            .background_highlights
17119            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17120        {
17121            all_highlights.extend(write_highlights.iter());
17122        }
17123
17124        if all_highlights.is_empty() {
17125            return;
17126        }
17127
17128        // Sort highlights by position
17129        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17130
17131        let target_highlight = match direction {
17132            Direction::Next => {
17133                // Find the first highlight after the current position
17134                all_highlights
17135                    .iter()
17136                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17137            }
17138            Direction::Prev => {
17139                // Find the last highlight before the current position
17140                all_highlights
17141                    .iter()
17142                    .rev()
17143                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17144            }
17145        };
17146
17147        if let Some(highlight) = target_highlight {
17148            let destination = highlight.start.to_point(buffer);
17149            let autoscroll = Autoscroll::center();
17150
17151            self.unfold_ranges(&[destination..destination], false, false, cx);
17152            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17153                s.select_ranges([destination..destination]);
17154            });
17155        }
17156    }
17157
17158    fn go_to_line<T: 'static>(
17159        &mut self,
17160        position: Anchor,
17161        highlight_color: Option<Hsla>,
17162        window: &mut Window,
17163        cx: &mut Context<Self>,
17164    ) {
17165        let snapshot = self.snapshot(window, cx).display_snapshot;
17166        let position = position.to_point(&snapshot.buffer_snapshot());
17167        let start = snapshot
17168            .buffer_snapshot()
17169            .clip_point(Point::new(position.row, 0), Bias::Left);
17170        let end = start + Point::new(1, 0);
17171        let start = snapshot.buffer_snapshot().anchor_before(start);
17172        let end = snapshot.buffer_snapshot().anchor_before(end);
17173
17174        self.highlight_rows::<T>(
17175            start..end,
17176            highlight_color
17177                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17178            Default::default(),
17179            cx,
17180        );
17181
17182        if self.buffer.read(cx).is_singleton() {
17183            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17184        }
17185    }
17186
17187    pub fn go_to_definition(
17188        &mut self,
17189        _: &GoToDefinition,
17190        window: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) -> Task<Result<Navigated>> {
17193        let definition =
17194            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17195        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17196        cx.spawn_in(window, async move |editor, cx| {
17197            if definition.await? == Navigated::Yes {
17198                return Ok(Navigated::Yes);
17199            }
17200            match fallback_strategy {
17201                GoToDefinitionFallback::None => Ok(Navigated::No),
17202                GoToDefinitionFallback::FindAllReferences => {
17203                    match editor.update_in(cx, |editor, window, cx| {
17204                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17205                    })? {
17206                        Some(references) => references.await,
17207                        None => Ok(Navigated::No),
17208                    }
17209                }
17210            }
17211        })
17212    }
17213
17214    pub fn go_to_declaration(
17215        &mut self,
17216        _: &GoToDeclaration,
17217        window: &mut Window,
17218        cx: &mut Context<Self>,
17219    ) -> Task<Result<Navigated>> {
17220        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17221    }
17222
17223    pub fn go_to_declaration_split(
17224        &mut self,
17225        _: &GoToDeclaration,
17226        window: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) -> Task<Result<Navigated>> {
17229        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17230    }
17231
17232    pub fn go_to_implementation(
17233        &mut self,
17234        _: &GoToImplementation,
17235        window: &mut Window,
17236        cx: &mut Context<Self>,
17237    ) -> Task<Result<Navigated>> {
17238        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17239    }
17240
17241    pub fn go_to_implementation_split(
17242        &mut self,
17243        _: &GoToImplementationSplit,
17244        window: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) -> Task<Result<Navigated>> {
17247        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17248    }
17249
17250    pub fn go_to_type_definition(
17251        &mut self,
17252        _: &GoToTypeDefinition,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) -> Task<Result<Navigated>> {
17256        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17257    }
17258
17259    pub fn go_to_definition_split(
17260        &mut self,
17261        _: &GoToDefinitionSplit,
17262        window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) -> Task<Result<Navigated>> {
17265        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17266    }
17267
17268    pub fn go_to_type_definition_split(
17269        &mut self,
17270        _: &GoToTypeDefinitionSplit,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) -> Task<Result<Navigated>> {
17274        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17275    }
17276
17277    fn go_to_definition_of_kind(
17278        &mut self,
17279        kind: GotoDefinitionKind,
17280        split: bool,
17281        window: &mut Window,
17282        cx: &mut Context<Self>,
17283    ) -> Task<Result<Navigated>> {
17284        let Some(provider) = self.semantics_provider.clone() else {
17285            return Task::ready(Ok(Navigated::No));
17286        };
17287        let head = self
17288            .selections
17289            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17290            .head();
17291        let buffer = self.buffer.read(cx);
17292        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17293            return Task::ready(Ok(Navigated::No));
17294        };
17295        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17296            return Task::ready(Ok(Navigated::No));
17297        };
17298
17299        cx.spawn_in(window, async move |editor, cx| {
17300            let Some(definitions) = definitions.await? else {
17301                return Ok(Navigated::No);
17302            };
17303            let navigated = editor
17304                .update_in(cx, |editor, window, cx| {
17305                    editor.navigate_to_hover_links(
17306                        Some(kind),
17307                        definitions
17308                            .into_iter()
17309                            .filter(|location| {
17310                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17311                            })
17312                            .map(HoverLink::Text)
17313                            .collect::<Vec<_>>(),
17314                        split,
17315                        window,
17316                        cx,
17317                    )
17318                })?
17319                .await?;
17320            anyhow::Ok(navigated)
17321        })
17322    }
17323
17324    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17325        let selection = self.selections.newest_anchor();
17326        let head = selection.head();
17327        let tail = selection.tail();
17328
17329        let Some((buffer, start_position)) =
17330            self.buffer.read(cx).text_anchor_for_position(head, cx)
17331        else {
17332            return;
17333        };
17334
17335        let end_position = if head != tail {
17336            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17337                return;
17338            };
17339            Some(pos)
17340        } else {
17341            None
17342        };
17343
17344        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17345            let url = if let Some(end_pos) = end_position {
17346                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17347            } else {
17348                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17349            };
17350
17351            if let Some(url) = url {
17352                cx.update(|window, cx| {
17353                    if parse_zed_link(&url, cx).is_some() {
17354                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17355                    } else {
17356                        cx.open_url(&url);
17357                    }
17358                })?;
17359            }
17360
17361            anyhow::Ok(())
17362        });
17363
17364        url_finder.detach();
17365    }
17366
17367    pub fn open_selected_filename(
17368        &mut self,
17369        _: &OpenSelectedFilename,
17370        window: &mut Window,
17371        cx: &mut Context<Self>,
17372    ) {
17373        let Some(workspace) = self.workspace() else {
17374            return;
17375        };
17376
17377        let position = self.selections.newest_anchor().head();
17378
17379        let Some((buffer, buffer_position)) =
17380            self.buffer.read(cx).text_anchor_for_position(position, cx)
17381        else {
17382            return;
17383        };
17384
17385        let project = self.project.clone();
17386
17387        cx.spawn_in(window, async move |_, cx| {
17388            let result = find_file(&buffer, project, buffer_position, cx).await;
17389
17390            if let Some((_, path)) = result {
17391                workspace
17392                    .update_in(cx, |workspace, window, cx| {
17393                        workspace.open_resolved_path(path, window, cx)
17394                    })?
17395                    .await?;
17396            }
17397            anyhow::Ok(())
17398        })
17399        .detach();
17400    }
17401
17402    pub(crate) fn navigate_to_hover_links(
17403        &mut self,
17404        kind: Option<GotoDefinitionKind>,
17405        definitions: Vec<HoverLink>,
17406        split: bool,
17407        window: &mut Window,
17408        cx: &mut Context<Editor>,
17409    ) -> Task<Result<Navigated>> {
17410        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17411        let mut first_url_or_file = None;
17412        let definitions: Vec<_> = definitions
17413            .into_iter()
17414            .filter_map(|def| match def {
17415                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17416                HoverLink::InlayHint(lsp_location, server_id) => {
17417                    let computation =
17418                        self.compute_target_location(lsp_location, server_id, window, cx);
17419                    Some(cx.background_spawn(computation))
17420                }
17421                HoverLink::Url(url) => {
17422                    first_url_or_file = Some(Either::Left(url));
17423                    None
17424                }
17425                HoverLink::File(path) => {
17426                    first_url_or_file = Some(Either::Right(path));
17427                    None
17428                }
17429            })
17430            .collect();
17431
17432        let workspace = self.workspace();
17433
17434        cx.spawn_in(window, async move |editor, cx| {
17435            let locations: Vec<Location> = future::join_all(definitions)
17436                .await
17437                .into_iter()
17438                .filter_map(|location| location.transpose())
17439                .collect::<Result<_>>()
17440                .context("location tasks")?;
17441            let mut locations = cx.update(|_, cx| {
17442                locations
17443                    .into_iter()
17444                    .map(|location| {
17445                        let buffer = location.buffer.read(cx);
17446                        (location.buffer, location.range.to_point(buffer))
17447                    })
17448                    .into_group_map()
17449            })?;
17450            let mut num_locations = 0;
17451            for ranges in locations.values_mut() {
17452                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17453                ranges.dedup();
17454                num_locations += ranges.len();
17455            }
17456
17457            if num_locations > 1 {
17458                let tab_kind = match kind {
17459                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17460                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17461                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17462                    Some(GotoDefinitionKind::Type) => "Types",
17463                };
17464                let title = editor
17465                    .update_in(cx, |_, _, cx| {
17466                        let target = locations
17467                            .iter()
17468                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17469                            .map(|(buffer, location)| {
17470                                buffer
17471                                    .read(cx)
17472                                    .text_for_range(location.clone())
17473                                    .collect::<String>()
17474                            })
17475                            .filter(|text| !text.contains('\n'))
17476                            .unique()
17477                            .take(3)
17478                            .join(", ");
17479                        if target.is_empty() {
17480                            tab_kind.to_owned()
17481                        } else {
17482                            format!("{tab_kind} for {target}")
17483                        }
17484                    })
17485                    .context("buffer title")?;
17486
17487                let Some(workspace) = workspace else {
17488                    return Ok(Navigated::No);
17489                };
17490
17491                let opened = workspace
17492                    .update_in(cx, |workspace, window, cx| {
17493                        let allow_preview = PreviewTabsSettings::get_global(cx)
17494                            .enable_preview_multibuffer_from_code_navigation;
17495                        Self::open_locations_in_multibuffer(
17496                            workspace,
17497                            locations,
17498                            title,
17499                            split,
17500                            allow_preview,
17501                            MultibufferSelectionMode::First,
17502                            window,
17503                            cx,
17504                        )
17505                    })
17506                    .is_ok();
17507
17508                anyhow::Ok(Navigated::from_bool(opened))
17509            } else if num_locations == 0 {
17510                // If there is one url or file, open it directly
17511                match first_url_or_file {
17512                    Some(Either::Left(url)) => {
17513                        cx.update(|window, cx| {
17514                            if parse_zed_link(&url, cx).is_some() {
17515                                window
17516                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17517                            } else {
17518                                cx.open_url(&url);
17519                            }
17520                        })?;
17521                        Ok(Navigated::Yes)
17522                    }
17523                    Some(Either::Right(path)) => {
17524                        // TODO(andrew): respect preview tab settings
17525                        //               `enable_keep_preview_on_code_navigation` and
17526                        //               `enable_preview_file_from_code_navigation`
17527                        let Some(workspace) = workspace else {
17528                            return Ok(Navigated::No);
17529                        };
17530                        workspace
17531                            .update_in(cx, |workspace, window, cx| {
17532                                workspace.open_resolved_path(path, window, cx)
17533                            })?
17534                            .await?;
17535                        Ok(Navigated::Yes)
17536                    }
17537                    None => Ok(Navigated::No),
17538                }
17539            } else {
17540                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17541                let target_range = target_ranges.first().unwrap().clone();
17542
17543                editor.update_in(cx, |editor, window, cx| {
17544                    let range = target_range.to_point(target_buffer.read(cx));
17545                    let range = editor.range_for_match(&range);
17546                    let range = collapse_multiline_range(range);
17547
17548                    if !split
17549                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17550                    {
17551                        editor.go_to_singleton_buffer_range(range, window, cx);
17552                    } else {
17553                        let Some(workspace) = workspace else {
17554                            return Navigated::No;
17555                        };
17556                        let pane = workspace.read(cx).active_pane().clone();
17557                        window.defer(cx, move |window, cx| {
17558                            let target_editor: Entity<Self> =
17559                                workspace.update(cx, |workspace, cx| {
17560                                    let pane = if split {
17561                                        workspace.adjacent_pane(window, cx)
17562                                    } else {
17563                                        workspace.active_pane().clone()
17564                                    };
17565
17566                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17567                                    let keep_old_preview = preview_tabs_settings
17568                                        .enable_keep_preview_on_code_navigation;
17569                                    let allow_new_preview = preview_tabs_settings
17570                                        .enable_preview_file_from_code_navigation;
17571
17572                                    workspace.open_project_item(
17573                                        pane,
17574                                        target_buffer.clone(),
17575                                        true,
17576                                        true,
17577                                        keep_old_preview,
17578                                        allow_new_preview,
17579                                        window,
17580                                        cx,
17581                                    )
17582                                });
17583                            target_editor.update(cx, |target_editor, cx| {
17584                                // When selecting a definition in a different buffer, disable the nav history
17585                                // to avoid creating a history entry at the previous cursor location.
17586                                pane.update(cx, |pane, _| pane.disable_history());
17587                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17588                                pane.update(cx, |pane, _| pane.enable_history());
17589                            });
17590                        });
17591                    }
17592                    Navigated::Yes
17593                })
17594            }
17595        })
17596    }
17597
17598    fn compute_target_location(
17599        &self,
17600        lsp_location: lsp::Location,
17601        server_id: LanguageServerId,
17602        window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) -> Task<anyhow::Result<Option<Location>>> {
17605        let Some(project) = self.project.clone() else {
17606            return Task::ready(Ok(None));
17607        };
17608
17609        cx.spawn_in(window, async move |editor, cx| {
17610            let location_task = editor.update(cx, |_, cx| {
17611                project.update(cx, |project, cx| {
17612                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17613                })
17614            })?;
17615            let location = Some({
17616                let target_buffer_handle = location_task.await.context("open local buffer")?;
17617                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17618                    let target_start = target_buffer
17619                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17620                    let target_end = target_buffer
17621                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17622                    target_buffer.anchor_after(target_start)
17623                        ..target_buffer.anchor_before(target_end)
17624                })?;
17625                Location {
17626                    buffer: target_buffer_handle,
17627                    range,
17628                }
17629            });
17630            Ok(location)
17631        })
17632    }
17633
17634    fn go_to_next_reference(
17635        &mut self,
17636        _: &GoToNextReference,
17637        window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) {
17640        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17641        if let Some(task) = task {
17642            task.detach();
17643        };
17644    }
17645
17646    fn go_to_prev_reference(
17647        &mut self,
17648        _: &GoToPreviousReference,
17649        window: &mut Window,
17650        cx: &mut Context<Self>,
17651    ) {
17652        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17653        if let Some(task) = task {
17654            task.detach();
17655        };
17656    }
17657
17658    pub fn go_to_reference_before_or_after_position(
17659        &mut self,
17660        direction: Direction,
17661        count: usize,
17662        window: &mut Window,
17663        cx: &mut Context<Self>,
17664    ) -> Option<Task<Result<()>>> {
17665        let selection = self.selections.newest_anchor();
17666        let head = selection.head();
17667
17668        let multi_buffer = self.buffer.read(cx);
17669
17670        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17671        let workspace = self.workspace()?;
17672        let project = workspace.read(cx).project().clone();
17673        let references =
17674            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17675        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17676            let Some(locations) = references.await? else {
17677                return Ok(());
17678            };
17679
17680            if locations.is_empty() {
17681                // totally normal - the cursor may be on something which is not
17682                // a symbol (e.g. a keyword)
17683                log::info!("no references found under cursor");
17684                return Ok(());
17685            }
17686
17687            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17688
17689            let (locations, current_location_index) =
17690                multi_buffer.update(cx, |multi_buffer, cx| {
17691                    let mut locations = locations
17692                        .into_iter()
17693                        .filter_map(|loc| {
17694                            let start = multi_buffer.buffer_anchor_to_anchor(
17695                                &loc.buffer,
17696                                loc.range.start,
17697                                cx,
17698                            )?;
17699                            let end = multi_buffer.buffer_anchor_to_anchor(
17700                                &loc.buffer,
17701                                loc.range.end,
17702                                cx,
17703                            )?;
17704                            Some(start..end)
17705                        })
17706                        .collect::<Vec<_>>();
17707
17708                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17709                    // There is an O(n) implementation, but given this list will be
17710                    // small (usually <100 items), the extra O(log(n)) factor isn't
17711                    // worth the (surprisingly large amount of) extra complexity.
17712                    locations
17713                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17714
17715                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17716
17717                    let current_location_index = locations.iter().position(|loc| {
17718                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17719                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17720                    });
17721
17722                    (locations, current_location_index)
17723                })?;
17724
17725            let Some(current_location_index) = current_location_index else {
17726                // This indicates something has gone wrong, because we already
17727                // handle the "no references" case above
17728                log::error!(
17729                    "failed to find current reference under cursor. Total references: {}",
17730                    locations.len()
17731                );
17732                return Ok(());
17733            };
17734
17735            let destination_location_index = match direction {
17736                Direction::Next => (current_location_index + count) % locations.len(),
17737                Direction::Prev => {
17738                    (current_location_index + locations.len() - count % locations.len())
17739                        % locations.len()
17740                }
17741            };
17742
17743            // TODO(cameron): is this needed?
17744            // the thinking is to avoid "jumping to the current location" (avoid
17745            // polluting "jumplist" in vim terms)
17746            if current_location_index == destination_location_index {
17747                return Ok(());
17748            }
17749
17750            let Range { start, end } = locations[destination_location_index];
17751
17752            editor.update_in(cx, |editor, window, cx| {
17753                let effects = SelectionEffects::default();
17754
17755                editor.unfold_ranges(&[start..end], false, false, cx);
17756                editor.change_selections(effects, window, cx, |s| {
17757                    s.select_ranges([start..start]);
17758                });
17759            })?;
17760
17761            Ok(())
17762        }))
17763    }
17764
17765    pub fn find_all_references(
17766        &mut self,
17767        action: &FindAllReferences,
17768        window: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) -> Option<Task<Result<Navigated>>> {
17771        let always_open_multibuffer = action.always_open_multibuffer;
17772        let selection = self.selections.newest_anchor();
17773        let multi_buffer = self.buffer.read(cx);
17774        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17775        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17776        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17777        let head = selection_offset.head();
17778
17779        let head_anchor = multi_buffer_snapshot.anchor_at(
17780            head,
17781            if head < selection_offset.tail() {
17782                Bias::Right
17783            } else {
17784                Bias::Left
17785            },
17786        );
17787
17788        match self
17789            .find_all_references_task_sources
17790            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17791        {
17792            Ok(_) => {
17793                log::info!(
17794                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17795                );
17796                return None;
17797            }
17798            Err(i) => {
17799                self.find_all_references_task_sources.insert(i, head_anchor);
17800            }
17801        }
17802
17803        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17804        let workspace = self.workspace()?;
17805        let project = workspace.read(cx).project().clone();
17806        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17807        Some(cx.spawn_in(window, async move |editor, cx| {
17808            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17809                if let Ok(i) = editor
17810                    .find_all_references_task_sources
17811                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17812                {
17813                    editor.find_all_references_task_sources.remove(i);
17814                }
17815            });
17816
17817            let Some(locations) = references.await? else {
17818                return anyhow::Ok(Navigated::No);
17819            };
17820            let mut locations = cx.update(|_, cx| {
17821                locations
17822                    .into_iter()
17823                    .map(|location| {
17824                        let buffer = location.buffer.read(cx);
17825                        (location.buffer, location.range.to_point(buffer))
17826                    })
17827                    // if special-casing the single-match case, remove ranges
17828                    // that intersect current selection
17829                    .filter(|(location_buffer, location)| {
17830                        if always_open_multibuffer || &buffer != location_buffer {
17831                            return true;
17832                        }
17833
17834                        !location.contains_inclusive(&selection_point.range())
17835                    })
17836                    .into_group_map()
17837            })?;
17838            if locations.is_empty() {
17839                return anyhow::Ok(Navigated::No);
17840            }
17841            for ranges in locations.values_mut() {
17842                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17843                ranges.dedup();
17844            }
17845            let mut num_locations = 0;
17846            for ranges in locations.values_mut() {
17847                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17848                ranges.dedup();
17849                num_locations += ranges.len();
17850            }
17851
17852            if num_locations == 1 && !always_open_multibuffer {
17853                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17854                let target_range = target_ranges.first().unwrap().clone();
17855
17856                return editor.update_in(cx, |editor, window, cx| {
17857                    let range = target_range.to_point(target_buffer.read(cx));
17858                    let range = editor.range_for_match(&range);
17859                    let range = range.start..range.start;
17860
17861                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17862                        editor.go_to_singleton_buffer_range(range, window, cx);
17863                    } else {
17864                        let pane = workspace.read(cx).active_pane().clone();
17865                        window.defer(cx, move |window, cx| {
17866                            let target_editor: Entity<Self> =
17867                                workspace.update(cx, |workspace, cx| {
17868                                    let pane = workspace.active_pane().clone();
17869
17870                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17871                                    let keep_old_preview = preview_tabs_settings
17872                                        .enable_keep_preview_on_code_navigation;
17873                                    let allow_new_preview = preview_tabs_settings
17874                                        .enable_preview_file_from_code_navigation;
17875
17876                                    workspace.open_project_item(
17877                                        pane,
17878                                        target_buffer.clone(),
17879                                        true,
17880                                        true,
17881                                        keep_old_preview,
17882                                        allow_new_preview,
17883                                        window,
17884                                        cx,
17885                                    )
17886                                });
17887                            target_editor.update(cx, |target_editor, cx| {
17888                                // When selecting a definition in a different buffer, disable the nav history
17889                                // to avoid creating a history entry at the previous cursor location.
17890                                pane.update(cx, |pane, _| pane.disable_history());
17891                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17892                                pane.update(cx, |pane, _| pane.enable_history());
17893                            });
17894                        });
17895                    }
17896                    Navigated::No
17897                });
17898            }
17899
17900            workspace.update_in(cx, |workspace, window, cx| {
17901                let target = locations
17902                    .iter()
17903                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17904                    .map(|(buffer, location)| {
17905                        buffer
17906                            .read(cx)
17907                            .text_for_range(location.clone())
17908                            .collect::<String>()
17909                    })
17910                    .filter(|text| !text.contains('\n'))
17911                    .unique()
17912                    .take(3)
17913                    .join(", ");
17914                let title = if target.is_empty() {
17915                    "References".to_owned()
17916                } else {
17917                    format!("References to {target}")
17918                };
17919                let allow_preview = PreviewTabsSettings::get_global(cx)
17920                    .enable_preview_multibuffer_from_code_navigation;
17921                Self::open_locations_in_multibuffer(
17922                    workspace,
17923                    locations,
17924                    title,
17925                    false,
17926                    allow_preview,
17927                    MultibufferSelectionMode::First,
17928                    window,
17929                    cx,
17930                );
17931                Navigated::Yes
17932            })
17933        }))
17934    }
17935
17936    /// Opens a multibuffer with the given project locations in it.
17937    pub fn open_locations_in_multibuffer(
17938        workspace: &mut Workspace,
17939        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17940        title: String,
17941        split: bool,
17942        allow_preview: bool,
17943        multibuffer_selection_mode: MultibufferSelectionMode,
17944        window: &mut Window,
17945        cx: &mut Context<Workspace>,
17946    ) {
17947        if locations.is_empty() {
17948            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17949            return;
17950        }
17951
17952        let capability = workspace.project().read(cx).capability();
17953        let mut ranges = <Vec<Range<Anchor>>>::new();
17954
17955        // a key to find existing multibuffer editors with the same set of locations
17956        // to prevent us from opening more and more multibuffer tabs for searches and the like
17957        let mut key = (title.clone(), vec![]);
17958        let excerpt_buffer = cx.new(|cx| {
17959            let key = &mut key.1;
17960            let mut multibuffer = MultiBuffer::new(capability);
17961            for (buffer, mut ranges_for_buffer) in locations {
17962                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17963                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17964                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17965                    PathKey::for_buffer(&buffer, cx),
17966                    buffer.clone(),
17967                    ranges_for_buffer,
17968                    multibuffer_context_lines(cx),
17969                    cx,
17970                );
17971                ranges.extend(new_ranges)
17972            }
17973
17974            multibuffer.with_title(title)
17975        });
17976        let existing = workspace.active_pane().update(cx, |pane, cx| {
17977            pane.items()
17978                .filter_map(|item| item.downcast::<Editor>())
17979                .find(|editor| {
17980                    editor
17981                        .read(cx)
17982                        .lookup_key
17983                        .as_ref()
17984                        .and_then(|it| {
17985                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17986                        })
17987                        .is_some_and(|it| *it == key)
17988                })
17989        });
17990        let was_existing = existing.is_some();
17991        let editor = existing.unwrap_or_else(|| {
17992            cx.new(|cx| {
17993                let mut editor = Editor::for_multibuffer(
17994                    excerpt_buffer,
17995                    Some(workspace.project().clone()),
17996                    window,
17997                    cx,
17998                );
17999                editor.lookup_key = Some(Box::new(key));
18000                editor
18001            })
18002        });
18003        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18004            MultibufferSelectionMode::First => {
18005                if let Some(first_range) = ranges.first() {
18006                    editor.change_selections(
18007                        SelectionEffects::no_scroll(),
18008                        window,
18009                        cx,
18010                        |selections| {
18011                            selections.clear_disjoint();
18012                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18013                        },
18014                    );
18015                }
18016                editor.highlight_background::<Self>(
18017                    &ranges,
18018                    |_, theme| theme.colors().editor_highlighted_line_background,
18019                    cx,
18020                );
18021            }
18022            MultibufferSelectionMode::All => {
18023                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18024                    selections.clear_disjoint();
18025                    selections.select_anchor_ranges(ranges);
18026                });
18027            }
18028        });
18029
18030        let item = Box::new(editor);
18031
18032        let pane = if split {
18033            workspace.adjacent_pane(window, cx)
18034        } else {
18035            workspace.active_pane().clone()
18036        };
18037        let activate_pane = split;
18038
18039        let mut destination_index = None;
18040        pane.update(cx, |pane, cx| {
18041            if allow_preview && !was_existing {
18042                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18043            }
18044            if was_existing && !allow_preview {
18045                pane.unpreview_item_if_preview(item.item_id());
18046            }
18047            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18048        });
18049    }
18050
18051    pub fn rename(
18052        &mut self,
18053        _: &Rename,
18054        window: &mut Window,
18055        cx: &mut Context<Self>,
18056    ) -> Option<Task<Result<()>>> {
18057        use language::ToOffset as _;
18058
18059        let provider = self.semantics_provider.clone()?;
18060        let selection = self.selections.newest_anchor().clone();
18061        let (cursor_buffer, cursor_buffer_position) = self
18062            .buffer
18063            .read(cx)
18064            .text_anchor_for_position(selection.head(), cx)?;
18065        let (tail_buffer, cursor_buffer_position_end) = self
18066            .buffer
18067            .read(cx)
18068            .text_anchor_for_position(selection.tail(), cx)?;
18069        if tail_buffer != cursor_buffer {
18070            return None;
18071        }
18072
18073        let snapshot = cursor_buffer.read(cx).snapshot();
18074        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18075        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18076        let prepare_rename = provider
18077            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18078            .unwrap_or_else(|| Task::ready(Ok(None)));
18079        drop(snapshot);
18080
18081        Some(cx.spawn_in(window, async move |this, cx| {
18082            let rename_range = if let Some(range) = prepare_rename.await? {
18083                Some(range)
18084            } else {
18085                this.update(cx, |this, cx| {
18086                    let buffer = this.buffer.read(cx).snapshot(cx);
18087                    let mut buffer_highlights = this
18088                        .document_highlights_for_position(selection.head(), &buffer)
18089                        .filter(|highlight| {
18090                            highlight.start.excerpt_id == selection.head().excerpt_id
18091                                && highlight.end.excerpt_id == selection.head().excerpt_id
18092                        });
18093                    buffer_highlights
18094                        .next()
18095                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18096                })?
18097            };
18098            if let Some(rename_range) = rename_range {
18099                this.update_in(cx, |this, window, cx| {
18100                    let snapshot = cursor_buffer.read(cx).snapshot();
18101                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18102                    let cursor_offset_in_rename_range =
18103                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18104                    let cursor_offset_in_rename_range_end =
18105                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18106
18107                    this.take_rename(false, window, cx);
18108                    let buffer = this.buffer.read(cx).read(cx);
18109                    let cursor_offset = selection.head().to_offset(&buffer);
18110                    let rename_start =
18111                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18112                    let rename_end = rename_start + rename_buffer_range.len();
18113                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18114                    let mut old_highlight_id = None;
18115                    let old_name: Arc<str> = buffer
18116                        .chunks(rename_start..rename_end, true)
18117                        .map(|chunk| {
18118                            if old_highlight_id.is_none() {
18119                                old_highlight_id = chunk.syntax_highlight_id;
18120                            }
18121                            chunk.text
18122                        })
18123                        .collect::<String>()
18124                        .into();
18125
18126                    drop(buffer);
18127
18128                    // Position the selection in the rename editor so that it matches the current selection.
18129                    this.show_local_selections = false;
18130                    let rename_editor = cx.new(|cx| {
18131                        let mut editor = Editor::single_line(window, cx);
18132                        editor.buffer.update(cx, |buffer, cx| {
18133                            buffer.edit(
18134                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18135                                None,
18136                                cx,
18137                            )
18138                        });
18139                        let cursor_offset_in_rename_range =
18140                            MultiBufferOffset(cursor_offset_in_rename_range);
18141                        let cursor_offset_in_rename_range_end =
18142                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18143                        let rename_selection_range = match cursor_offset_in_rename_range
18144                            .cmp(&cursor_offset_in_rename_range_end)
18145                        {
18146                            Ordering::Equal => {
18147                                editor.select_all(&SelectAll, window, cx);
18148                                return editor;
18149                            }
18150                            Ordering::Less => {
18151                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18152                            }
18153                            Ordering::Greater => {
18154                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18155                            }
18156                        };
18157                        if rename_selection_range.end.0 > old_name.len() {
18158                            editor.select_all(&SelectAll, window, cx);
18159                        } else {
18160                            editor.change_selections(Default::default(), window, cx, |s| {
18161                                s.select_ranges([rename_selection_range]);
18162                            });
18163                        }
18164                        editor
18165                    });
18166                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18167                        if e == &EditorEvent::Focused {
18168                            cx.emit(EditorEvent::FocusedIn)
18169                        }
18170                    })
18171                    .detach();
18172
18173                    let write_highlights =
18174                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18175                    let read_highlights =
18176                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18177                    let ranges = write_highlights
18178                        .iter()
18179                        .flat_map(|(_, ranges)| ranges.iter())
18180                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18181                        .cloned()
18182                        .collect();
18183
18184                    this.highlight_text::<Rename>(
18185                        ranges,
18186                        HighlightStyle {
18187                            fade_out: Some(0.6),
18188                            ..Default::default()
18189                        },
18190                        cx,
18191                    );
18192                    let rename_focus_handle = rename_editor.focus_handle(cx);
18193                    window.focus(&rename_focus_handle, cx);
18194                    let block_id = this.insert_blocks(
18195                        [BlockProperties {
18196                            style: BlockStyle::Flex,
18197                            placement: BlockPlacement::Below(range.start),
18198                            height: Some(1),
18199                            render: Arc::new({
18200                                let rename_editor = rename_editor.clone();
18201                                move |cx: &mut BlockContext| {
18202                                    let mut text_style = cx.editor_style.text.clone();
18203                                    if let Some(highlight_style) = old_highlight_id
18204                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18205                                    {
18206                                        text_style = text_style.highlight(highlight_style);
18207                                    }
18208                                    div()
18209                                        .block_mouse_except_scroll()
18210                                        .pl(cx.anchor_x)
18211                                        .child(EditorElement::new(
18212                                            &rename_editor,
18213                                            EditorStyle {
18214                                                background: cx.theme().system().transparent,
18215                                                local_player: cx.editor_style.local_player,
18216                                                text: text_style,
18217                                                scrollbar_width: cx.editor_style.scrollbar_width,
18218                                                syntax: cx.editor_style.syntax.clone(),
18219                                                status: cx.editor_style.status.clone(),
18220                                                inlay_hints_style: HighlightStyle {
18221                                                    font_weight: Some(FontWeight::BOLD),
18222                                                    ..make_inlay_hints_style(cx.app)
18223                                                },
18224                                                edit_prediction_styles: make_suggestion_styles(
18225                                                    cx.app,
18226                                                ),
18227                                                ..EditorStyle::default()
18228                                            },
18229                                        ))
18230                                        .into_any_element()
18231                                }
18232                            }),
18233                            priority: 0,
18234                        }],
18235                        Some(Autoscroll::fit()),
18236                        cx,
18237                    )[0];
18238                    this.pending_rename = Some(RenameState {
18239                        range,
18240                        old_name,
18241                        editor: rename_editor,
18242                        block_id,
18243                    });
18244                })?;
18245            }
18246
18247            Ok(())
18248        }))
18249    }
18250
18251    pub fn confirm_rename(
18252        &mut self,
18253        _: &ConfirmRename,
18254        window: &mut Window,
18255        cx: &mut Context<Self>,
18256    ) -> Option<Task<Result<()>>> {
18257        let rename = self.take_rename(false, window, cx)?;
18258        let workspace = self.workspace()?.downgrade();
18259        let (buffer, start) = self
18260            .buffer
18261            .read(cx)
18262            .text_anchor_for_position(rename.range.start, cx)?;
18263        let (end_buffer, _) = self
18264            .buffer
18265            .read(cx)
18266            .text_anchor_for_position(rename.range.end, cx)?;
18267        if buffer != end_buffer {
18268            return None;
18269        }
18270
18271        let old_name = rename.old_name;
18272        let new_name = rename.editor.read(cx).text(cx);
18273
18274        let rename = self.semantics_provider.as_ref()?.perform_rename(
18275            &buffer,
18276            start,
18277            new_name.clone(),
18278            cx,
18279        )?;
18280
18281        Some(cx.spawn_in(window, async move |editor, cx| {
18282            let project_transaction = rename.await?;
18283            Self::open_project_transaction(
18284                &editor,
18285                workspace,
18286                project_transaction,
18287                format!("Rename: {}{}", old_name, new_name),
18288                cx,
18289            )
18290            .await?;
18291
18292            editor.update(cx, |editor, cx| {
18293                editor.refresh_document_highlights(cx);
18294            })?;
18295            Ok(())
18296        }))
18297    }
18298
18299    fn take_rename(
18300        &mut self,
18301        moving_cursor: bool,
18302        window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) -> Option<RenameState> {
18305        let rename = self.pending_rename.take()?;
18306        if rename.editor.focus_handle(cx).is_focused(window) {
18307            window.focus(&self.focus_handle, cx);
18308        }
18309
18310        self.remove_blocks(
18311            [rename.block_id].into_iter().collect(),
18312            Some(Autoscroll::fit()),
18313            cx,
18314        );
18315        self.clear_highlights::<Rename>(cx);
18316        self.show_local_selections = true;
18317
18318        if moving_cursor {
18319            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18320                editor
18321                    .selections
18322                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18323                    .head()
18324            });
18325
18326            // Update the selection to match the position of the selection inside
18327            // the rename editor.
18328            let snapshot = self.buffer.read(cx).read(cx);
18329            let rename_range = rename.range.to_offset(&snapshot);
18330            let cursor_in_editor = snapshot
18331                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18332                .min(rename_range.end);
18333            drop(snapshot);
18334
18335            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18336                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18337            });
18338        } else {
18339            self.refresh_document_highlights(cx);
18340        }
18341
18342        Some(rename)
18343    }
18344
18345    pub fn pending_rename(&self) -> Option<&RenameState> {
18346        self.pending_rename.as_ref()
18347    }
18348
18349    fn format(
18350        &mut self,
18351        _: &Format,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) -> Option<Task<Result<()>>> {
18355        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18356
18357        let project = match &self.project {
18358            Some(project) => project.clone(),
18359            None => return None,
18360        };
18361
18362        Some(self.perform_format(
18363            project,
18364            FormatTrigger::Manual,
18365            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18366            window,
18367            cx,
18368        ))
18369    }
18370
18371    fn format_selections(
18372        &mut self,
18373        _: &FormatSelections,
18374        window: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) -> Option<Task<Result<()>>> {
18377        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18378
18379        let project = match &self.project {
18380            Some(project) => project.clone(),
18381            None => return None,
18382        };
18383
18384        let ranges = self
18385            .selections
18386            .all_adjusted(&self.display_snapshot(cx))
18387            .into_iter()
18388            .map(|selection| selection.range())
18389            .collect_vec();
18390
18391        Some(self.perform_format(
18392            project,
18393            FormatTrigger::Manual,
18394            FormatTarget::Ranges(ranges),
18395            window,
18396            cx,
18397        ))
18398    }
18399
18400    fn perform_format(
18401        &mut self,
18402        project: Entity<Project>,
18403        trigger: FormatTrigger,
18404        target: FormatTarget,
18405        window: &mut Window,
18406        cx: &mut Context<Self>,
18407    ) -> Task<Result<()>> {
18408        let buffer = self.buffer.clone();
18409        let (buffers, target) = match target {
18410            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18411            FormatTarget::Ranges(selection_ranges) => {
18412                let multi_buffer = buffer.read(cx);
18413                let snapshot = multi_buffer.read(cx);
18414                let mut buffers = HashSet::default();
18415                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18416                    BTreeMap::new();
18417                for selection_range in selection_ranges {
18418                    for (buffer, buffer_range, _) in
18419                        snapshot.range_to_buffer_ranges(selection_range)
18420                    {
18421                        let buffer_id = buffer.remote_id();
18422                        let start = buffer.anchor_before(buffer_range.start);
18423                        let end = buffer.anchor_after(buffer_range.end);
18424                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18425                        buffer_id_to_ranges
18426                            .entry(buffer_id)
18427                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18428                            .or_insert_with(|| vec![start..end]);
18429                    }
18430                }
18431                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18432            }
18433        };
18434
18435        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18436        let selections_prev = transaction_id_prev
18437            .and_then(|transaction_id_prev| {
18438                // default to selections as they were after the last edit, if we have them,
18439                // instead of how they are now.
18440                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18441                // will take you back to where you made the last edit, instead of staying where you scrolled
18442                self.selection_history
18443                    .transaction(transaction_id_prev)
18444                    .map(|t| t.0.clone())
18445            })
18446            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18447
18448        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18449        let format = project.update(cx, |project, cx| {
18450            project.format(buffers, target, true, trigger, cx)
18451        });
18452
18453        cx.spawn_in(window, async move |editor, cx| {
18454            let transaction = futures::select_biased! {
18455                transaction = format.log_err().fuse() => transaction,
18456                () = timeout => {
18457                    log::warn!("timed out waiting for formatting");
18458                    None
18459                }
18460            };
18461
18462            buffer
18463                .update(cx, |buffer, cx| {
18464                    if let Some(transaction) = transaction
18465                        && !buffer.is_singleton()
18466                    {
18467                        buffer.push_transaction(&transaction.0, cx);
18468                    }
18469                    cx.notify();
18470                })
18471                .ok();
18472
18473            if let Some(transaction_id_now) =
18474                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18475            {
18476                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18477                if has_new_transaction {
18478                    _ = editor.update(cx, |editor, _| {
18479                        editor
18480                            .selection_history
18481                            .insert_transaction(transaction_id_now, selections_prev);
18482                    });
18483                }
18484            }
18485
18486            Ok(())
18487        })
18488    }
18489
18490    fn organize_imports(
18491        &mut self,
18492        _: &OrganizeImports,
18493        window: &mut Window,
18494        cx: &mut Context<Self>,
18495    ) -> Option<Task<Result<()>>> {
18496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18497        let project = match &self.project {
18498            Some(project) => project.clone(),
18499            None => return None,
18500        };
18501        Some(self.perform_code_action_kind(
18502            project,
18503            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18504            window,
18505            cx,
18506        ))
18507    }
18508
18509    fn perform_code_action_kind(
18510        &mut self,
18511        project: Entity<Project>,
18512        kind: CodeActionKind,
18513        window: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) -> Task<Result<()>> {
18516        let buffer = self.buffer.clone();
18517        let buffers = buffer.read(cx).all_buffers();
18518        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18519        let apply_action = project.update(cx, |project, cx| {
18520            project.apply_code_action_kind(buffers, kind, true, cx)
18521        });
18522        cx.spawn_in(window, async move |_, cx| {
18523            let transaction = futures::select_biased! {
18524                () = timeout => {
18525                    log::warn!("timed out waiting for executing code action");
18526                    None
18527                }
18528                transaction = apply_action.log_err().fuse() => transaction,
18529            };
18530            buffer
18531                .update(cx, |buffer, cx| {
18532                    // check if we need this
18533                    if let Some(transaction) = transaction
18534                        && !buffer.is_singleton()
18535                    {
18536                        buffer.push_transaction(&transaction.0, cx);
18537                    }
18538                    cx.notify();
18539                })
18540                .ok();
18541            Ok(())
18542        })
18543    }
18544
18545    pub fn restart_language_server(
18546        &mut self,
18547        _: &RestartLanguageServer,
18548        _: &mut Window,
18549        cx: &mut Context<Self>,
18550    ) {
18551        if let Some(project) = self.project.clone() {
18552            self.buffer.update(cx, |multi_buffer, cx| {
18553                project.update(cx, |project, cx| {
18554                    project.restart_language_servers_for_buffers(
18555                        multi_buffer.all_buffers().into_iter().collect(),
18556                        HashSet::default(),
18557                        cx,
18558                    );
18559                });
18560            })
18561        }
18562    }
18563
18564    pub fn stop_language_server(
18565        &mut self,
18566        _: &StopLanguageServer,
18567        _: &mut Window,
18568        cx: &mut Context<Self>,
18569    ) {
18570        if let Some(project) = self.project.clone() {
18571            self.buffer.update(cx, |multi_buffer, cx| {
18572                project.update(cx, |project, cx| {
18573                    project.stop_language_servers_for_buffers(
18574                        multi_buffer.all_buffers().into_iter().collect(),
18575                        HashSet::default(),
18576                        cx,
18577                    );
18578                });
18579            });
18580            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18581        }
18582    }
18583
18584    fn cancel_language_server_work(
18585        workspace: &mut Workspace,
18586        _: &actions::CancelLanguageServerWork,
18587        _: &mut Window,
18588        cx: &mut Context<Workspace>,
18589    ) {
18590        let project = workspace.project();
18591        let buffers = workspace
18592            .active_item(cx)
18593            .and_then(|item| item.act_as::<Editor>(cx))
18594            .map_or(HashSet::default(), |editor| {
18595                editor.read(cx).buffer.read(cx).all_buffers()
18596            });
18597        project.update(cx, |project, cx| {
18598            project.cancel_language_server_work_for_buffers(buffers, cx);
18599        });
18600    }
18601
18602    fn show_character_palette(
18603        &mut self,
18604        _: &ShowCharacterPalette,
18605        window: &mut Window,
18606        _: &mut Context<Self>,
18607    ) {
18608        window.show_character_palette();
18609    }
18610
18611    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18612        if !self.diagnostics_enabled() {
18613            return;
18614        }
18615
18616        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18617            let buffer = self.buffer.read(cx).snapshot(cx);
18618            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18619            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18620            let is_valid = buffer
18621                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18622                .any(|entry| {
18623                    entry.diagnostic.is_primary
18624                        && !entry.range.is_empty()
18625                        && entry.range.start == primary_range_start
18626                        && entry.diagnostic.message == active_diagnostics.active_message
18627                });
18628
18629            if !is_valid {
18630                self.dismiss_diagnostics(cx);
18631            }
18632        }
18633    }
18634
18635    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18636        match &self.active_diagnostics {
18637            ActiveDiagnostic::Group(group) => Some(group),
18638            _ => None,
18639        }
18640    }
18641
18642    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18643        if !self.diagnostics_enabled() {
18644            return;
18645        }
18646        self.dismiss_diagnostics(cx);
18647        self.active_diagnostics = ActiveDiagnostic::All;
18648    }
18649
18650    fn activate_diagnostics(
18651        &mut self,
18652        buffer_id: BufferId,
18653        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18654        window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18658            return;
18659        }
18660        self.dismiss_diagnostics(cx);
18661        let snapshot = self.snapshot(window, cx);
18662        let buffer = self.buffer.read(cx).snapshot(cx);
18663        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18664            return;
18665        };
18666
18667        let diagnostic_group = buffer
18668            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18669            .collect::<Vec<_>>();
18670
18671        let language_registry = self
18672            .project()
18673            .map(|project| project.read(cx).languages().clone());
18674
18675        let blocks = renderer.render_group(
18676            diagnostic_group,
18677            buffer_id,
18678            snapshot,
18679            cx.weak_entity(),
18680            language_registry,
18681            cx,
18682        );
18683
18684        let blocks = self.display_map.update(cx, |display_map, cx| {
18685            display_map.insert_blocks(blocks, cx).into_iter().collect()
18686        });
18687        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18688            active_range: buffer.anchor_before(diagnostic.range.start)
18689                ..buffer.anchor_after(diagnostic.range.end),
18690            active_message: diagnostic.diagnostic.message.clone(),
18691            group_id: diagnostic.diagnostic.group_id,
18692            blocks,
18693        });
18694        cx.notify();
18695    }
18696
18697    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18698        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18699            return;
18700        };
18701
18702        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18703        if let ActiveDiagnostic::Group(group) = prev {
18704            self.display_map.update(cx, |display_map, cx| {
18705                display_map.remove_blocks(group.blocks, cx);
18706            });
18707            cx.notify();
18708        }
18709    }
18710
18711    /// Disable inline diagnostics rendering for this editor.
18712    pub fn disable_inline_diagnostics(&mut self) {
18713        self.inline_diagnostics_enabled = false;
18714        self.inline_diagnostics_update = Task::ready(());
18715        self.inline_diagnostics.clear();
18716    }
18717
18718    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18719        self.diagnostics_enabled = false;
18720        self.dismiss_diagnostics(cx);
18721        self.inline_diagnostics_update = Task::ready(());
18722        self.inline_diagnostics.clear();
18723    }
18724
18725    pub fn disable_word_completions(&mut self) {
18726        self.word_completions_enabled = false;
18727    }
18728
18729    pub fn diagnostics_enabled(&self) -> bool {
18730        self.diagnostics_enabled && self.mode.is_full()
18731    }
18732
18733    pub fn inline_diagnostics_enabled(&self) -> bool {
18734        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18735    }
18736
18737    pub fn show_inline_diagnostics(&self) -> bool {
18738        self.show_inline_diagnostics
18739    }
18740
18741    pub fn toggle_inline_diagnostics(
18742        &mut self,
18743        _: &ToggleInlineDiagnostics,
18744        window: &mut Window,
18745        cx: &mut Context<Editor>,
18746    ) {
18747        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18748        self.refresh_inline_diagnostics(false, window, cx);
18749    }
18750
18751    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18752        self.diagnostics_max_severity = severity;
18753        self.display_map.update(cx, |display_map, _| {
18754            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18755        });
18756    }
18757
18758    pub fn toggle_diagnostics(
18759        &mut self,
18760        _: &ToggleDiagnostics,
18761        window: &mut Window,
18762        cx: &mut Context<Editor>,
18763    ) {
18764        if !self.diagnostics_enabled() {
18765            return;
18766        }
18767
18768        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18769            EditorSettings::get_global(cx)
18770                .diagnostics_max_severity
18771                .filter(|severity| severity != &DiagnosticSeverity::Off)
18772                .unwrap_or(DiagnosticSeverity::Hint)
18773        } else {
18774            DiagnosticSeverity::Off
18775        };
18776        self.set_max_diagnostics_severity(new_severity, cx);
18777        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18778            self.active_diagnostics = ActiveDiagnostic::None;
18779            self.inline_diagnostics_update = Task::ready(());
18780            self.inline_diagnostics.clear();
18781        } else {
18782            self.refresh_inline_diagnostics(false, window, cx);
18783        }
18784
18785        cx.notify();
18786    }
18787
18788    pub fn toggle_minimap(
18789        &mut self,
18790        _: &ToggleMinimap,
18791        window: &mut Window,
18792        cx: &mut Context<Editor>,
18793    ) {
18794        if self.supports_minimap(cx) {
18795            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18796        }
18797    }
18798
18799    fn refresh_inline_diagnostics(
18800        &mut self,
18801        debounce: bool,
18802        window: &mut Window,
18803        cx: &mut Context<Self>,
18804    ) {
18805        let max_severity = ProjectSettings::get_global(cx)
18806            .diagnostics
18807            .inline
18808            .max_severity
18809            .unwrap_or(self.diagnostics_max_severity);
18810
18811        if !self.inline_diagnostics_enabled()
18812            || !self.diagnostics_enabled()
18813            || !self.show_inline_diagnostics
18814            || max_severity == DiagnosticSeverity::Off
18815        {
18816            self.inline_diagnostics_update = Task::ready(());
18817            self.inline_diagnostics.clear();
18818            return;
18819        }
18820
18821        let debounce_ms = ProjectSettings::get_global(cx)
18822            .diagnostics
18823            .inline
18824            .update_debounce_ms;
18825        let debounce = if debounce && debounce_ms > 0 {
18826            Some(Duration::from_millis(debounce_ms))
18827        } else {
18828            None
18829        };
18830        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18831            if let Some(debounce) = debounce {
18832                cx.background_executor().timer(debounce).await;
18833            }
18834            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18835                editor
18836                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18837                    .ok()
18838            }) else {
18839                return;
18840            };
18841
18842            let new_inline_diagnostics = cx
18843                .background_spawn(async move {
18844                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18845                    for diagnostic_entry in
18846                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18847                    {
18848                        let message = diagnostic_entry
18849                            .diagnostic
18850                            .message
18851                            .split_once('\n')
18852                            .map(|(line, _)| line)
18853                            .map(SharedString::new)
18854                            .unwrap_or_else(|| {
18855                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18856                            });
18857                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18858                        let (Ok(i) | Err(i)) = inline_diagnostics
18859                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18860                        inline_diagnostics.insert(
18861                            i,
18862                            (
18863                                start_anchor,
18864                                InlineDiagnostic {
18865                                    message,
18866                                    group_id: diagnostic_entry.diagnostic.group_id,
18867                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18868                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18869                                    severity: diagnostic_entry.diagnostic.severity,
18870                                },
18871                            ),
18872                        );
18873                    }
18874                    inline_diagnostics
18875                })
18876                .await;
18877
18878            editor
18879                .update(cx, |editor, cx| {
18880                    editor.inline_diagnostics = new_inline_diagnostics;
18881                    cx.notify();
18882                })
18883                .ok();
18884        });
18885    }
18886
18887    fn pull_diagnostics(
18888        &mut self,
18889        buffer_id: Option<BufferId>,
18890        window: &Window,
18891        cx: &mut Context<Self>,
18892    ) -> Option<()> {
18893        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18894            return None;
18895        }
18896        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18897            .diagnostics
18898            .lsp_pull_diagnostics;
18899        if !pull_diagnostics_settings.enabled {
18900            return None;
18901        }
18902        let project = self.project()?.downgrade();
18903
18904        let mut edited_buffer_ids = HashSet::default();
18905        let mut edited_worktree_ids = HashSet::default();
18906        let edited_buffers = match buffer_id {
18907            Some(buffer_id) => {
18908                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18909                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18910                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18911                edited_worktree_ids.insert(worktree_id);
18912                vec![buffer]
18913            }
18914            None => self
18915                .buffer()
18916                .read(cx)
18917                .all_buffers()
18918                .into_iter()
18919                .filter(|buffer| {
18920                    let buffer = buffer.read(cx);
18921                    match buffer.file().map(|f| f.worktree_id(cx)) {
18922                        Some(worktree_id) => {
18923                            edited_buffer_ids.insert(buffer.remote_id());
18924                            edited_worktree_ids.insert(worktree_id);
18925                            true
18926                        }
18927                        None => false,
18928                    }
18929                })
18930                .collect::<Vec<_>>(),
18931        };
18932
18933        if edited_buffers.is_empty() {
18934            self.pull_diagnostics_task = Task::ready(());
18935            self.pull_diagnostics_background_task = Task::ready(());
18936            return None;
18937        }
18938
18939        let mut already_used_buffers = HashSet::default();
18940        let related_open_buffers = self
18941            .workspace
18942            .as_ref()
18943            .and_then(|(workspace, _)| workspace.upgrade())
18944            .into_iter()
18945            .flat_map(|workspace| workspace.read(cx).panes())
18946            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18947            .filter(|editor| editor != &cx.entity())
18948            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18949            .filter(|buffer| {
18950                let buffer = buffer.read(cx);
18951                let buffer_id = buffer.remote_id();
18952                if already_used_buffers.insert(buffer_id) {
18953                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18954                        return !edited_buffer_ids.contains(&buffer_id)
18955                            && edited_worktree_ids.contains(&worktree_id);
18956                    }
18957                }
18958                false
18959            })
18960            .collect::<Vec<_>>();
18961
18962        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18963        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18964            if buffers.is_empty() {
18965                return Task::ready(());
18966            }
18967            let project_weak = project.clone();
18968            cx.spawn_in(window, async move |_, cx| {
18969                cx.background_executor().timer(delay).await;
18970
18971                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18972                    buffers
18973                        .into_iter()
18974                        .filter_map(|buffer| {
18975                            project_weak
18976                                .update(cx, |project, cx| {
18977                                    project.lsp_store().update(cx, |lsp_store, cx| {
18978                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18979                                    })
18980                                })
18981                                .ok()
18982                        })
18983                        .collect::<FuturesUnordered<_>>()
18984                }) else {
18985                    return;
18986                };
18987
18988                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18989                    if let Err(e) = pull_task {
18990                        log::error!("Failed to update project diagnostics: {e:#}");
18991                    }
18992                }
18993            })
18994        };
18995
18996        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18997        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18998
18999        Some(())
19000    }
19001
19002    pub fn set_selections_from_remote(
19003        &mut self,
19004        selections: Vec<Selection<Anchor>>,
19005        pending_selection: Option<Selection<Anchor>>,
19006        window: &mut Window,
19007        cx: &mut Context<Self>,
19008    ) {
19009        let old_cursor_position = self.selections.newest_anchor().head();
19010        self.selections
19011            .change_with(&self.display_snapshot(cx), |s| {
19012                s.select_anchors(selections);
19013                if let Some(pending_selection) = pending_selection {
19014                    s.set_pending(pending_selection, SelectMode::Character);
19015                } else {
19016                    s.clear_pending();
19017                }
19018            });
19019        self.selections_did_change(
19020            false,
19021            &old_cursor_position,
19022            SelectionEffects::default(),
19023            window,
19024            cx,
19025        );
19026    }
19027
19028    pub fn transact(
19029        &mut self,
19030        window: &mut Window,
19031        cx: &mut Context<Self>,
19032        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19033    ) -> Option<TransactionId> {
19034        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19035            this.start_transaction_at(Instant::now(), window, cx);
19036            update(this, window, cx);
19037            this.end_transaction_at(Instant::now(), cx)
19038        })
19039    }
19040
19041    pub fn start_transaction_at(
19042        &mut self,
19043        now: Instant,
19044        window: &mut Window,
19045        cx: &mut Context<Self>,
19046    ) -> Option<TransactionId> {
19047        self.end_selection(window, cx);
19048        if let Some(tx_id) = self
19049            .buffer
19050            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19051        {
19052            self.selection_history
19053                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19054            cx.emit(EditorEvent::TransactionBegun {
19055                transaction_id: tx_id,
19056            });
19057            Some(tx_id)
19058        } else {
19059            None
19060        }
19061    }
19062
19063    pub fn end_transaction_at(
19064        &mut self,
19065        now: Instant,
19066        cx: &mut Context<Self>,
19067    ) -> Option<TransactionId> {
19068        if let Some(transaction_id) = self
19069            .buffer
19070            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19071        {
19072            if let Some((_, end_selections)) =
19073                self.selection_history.transaction_mut(transaction_id)
19074            {
19075                *end_selections = Some(self.selections.disjoint_anchors_arc());
19076            } else {
19077                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19078            }
19079
19080            cx.emit(EditorEvent::Edited { transaction_id });
19081            Some(transaction_id)
19082        } else {
19083            None
19084        }
19085    }
19086
19087    pub fn modify_transaction_selection_history(
19088        &mut self,
19089        transaction_id: TransactionId,
19090        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19091    ) -> bool {
19092        self.selection_history
19093            .transaction_mut(transaction_id)
19094            .map(modify)
19095            .is_some()
19096    }
19097
19098    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19099        if self.selection_mark_mode {
19100            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19101                s.move_with(|_, sel| {
19102                    sel.collapse_to(sel.head(), SelectionGoal::None);
19103                });
19104            })
19105        }
19106        self.selection_mark_mode = true;
19107        cx.notify();
19108    }
19109
19110    pub fn swap_selection_ends(
19111        &mut self,
19112        _: &actions::SwapSelectionEnds,
19113        window: &mut Window,
19114        cx: &mut Context<Self>,
19115    ) {
19116        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19117            s.move_with(|_, sel| {
19118                if sel.start != sel.end {
19119                    sel.reversed = !sel.reversed
19120                }
19121            });
19122        });
19123        self.request_autoscroll(Autoscroll::newest(), cx);
19124        cx.notify();
19125    }
19126
19127    pub fn toggle_focus(
19128        workspace: &mut Workspace,
19129        _: &actions::ToggleFocus,
19130        window: &mut Window,
19131        cx: &mut Context<Workspace>,
19132    ) {
19133        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19134            return;
19135        };
19136        workspace.activate_item(&item, true, true, window, cx);
19137    }
19138
19139    pub fn toggle_fold(
19140        &mut self,
19141        _: &actions::ToggleFold,
19142        window: &mut Window,
19143        cx: &mut Context<Self>,
19144    ) {
19145        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19146            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19147            let selection = self.selections.newest::<Point>(&display_map);
19148
19149            let range = if selection.is_empty() {
19150                let point = selection.head().to_display_point(&display_map);
19151                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19152                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19153                    .to_point(&display_map);
19154                start..end
19155            } else {
19156                selection.range()
19157            };
19158            if display_map.folds_in_range(range).next().is_some() {
19159                self.unfold_lines(&Default::default(), window, cx)
19160            } else {
19161                self.fold(&Default::default(), window, cx)
19162            }
19163        } else {
19164            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19165            let buffer_ids: HashSet<_> = self
19166                .selections
19167                .disjoint_anchor_ranges()
19168                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19169                .collect();
19170
19171            let should_unfold = buffer_ids
19172                .iter()
19173                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19174
19175            for buffer_id in buffer_ids {
19176                if should_unfold {
19177                    self.unfold_buffer(buffer_id, cx);
19178                } else {
19179                    self.fold_buffer(buffer_id, cx);
19180                }
19181            }
19182        }
19183    }
19184
19185    pub fn toggle_fold_recursive(
19186        &mut self,
19187        _: &actions::ToggleFoldRecursive,
19188        window: &mut Window,
19189        cx: &mut Context<Self>,
19190    ) {
19191        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19192
19193        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19194        let range = if selection.is_empty() {
19195            let point = selection.head().to_display_point(&display_map);
19196            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19197            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19198                .to_point(&display_map);
19199            start..end
19200        } else {
19201            selection.range()
19202        };
19203        if display_map.folds_in_range(range).next().is_some() {
19204            self.unfold_recursive(&Default::default(), window, cx)
19205        } else {
19206            self.fold_recursive(&Default::default(), window, cx)
19207        }
19208    }
19209
19210    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19211        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19212            let mut to_fold = Vec::new();
19213            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19214            let selections = self.selections.all_adjusted(&display_map);
19215
19216            for selection in selections {
19217                let range = selection.range().sorted();
19218                let buffer_start_row = range.start.row;
19219
19220                if range.start.row != range.end.row {
19221                    let mut found = false;
19222                    let mut row = range.start.row;
19223                    while row <= range.end.row {
19224                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19225                        {
19226                            found = true;
19227                            row = crease.range().end.row + 1;
19228                            to_fold.push(crease);
19229                        } else {
19230                            row += 1
19231                        }
19232                    }
19233                    if found {
19234                        continue;
19235                    }
19236                }
19237
19238                for row in (0..=range.start.row).rev() {
19239                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19240                        && crease.range().end.row >= buffer_start_row
19241                    {
19242                        to_fold.push(crease);
19243                        if row <= range.start.row {
19244                            break;
19245                        }
19246                    }
19247                }
19248            }
19249
19250            self.fold_creases(to_fold, true, window, cx);
19251        } else {
19252            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19253            let buffer_ids = self
19254                .selections
19255                .disjoint_anchor_ranges()
19256                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19257                .collect::<HashSet<_>>();
19258            for buffer_id in buffer_ids {
19259                self.fold_buffer(buffer_id, cx);
19260            }
19261        }
19262    }
19263
19264    pub fn toggle_fold_all(
19265        &mut self,
19266        _: &actions::ToggleFoldAll,
19267        window: &mut Window,
19268        cx: &mut Context<Self>,
19269    ) {
19270        let has_folds = if self.buffer.read(cx).is_singleton() {
19271            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19272            let has_folds = display_map
19273                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19274                .next()
19275                .is_some();
19276            has_folds
19277        } else {
19278            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19279            let has_folds = buffer_ids
19280                .iter()
19281                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19282            has_folds
19283        };
19284
19285        if has_folds {
19286            self.unfold_all(&actions::UnfoldAll, window, cx);
19287        } else {
19288            self.fold_all(&actions::FoldAll, window, cx);
19289        }
19290    }
19291
19292    fn fold_at_level(
19293        &mut self,
19294        fold_at: &FoldAtLevel,
19295        window: &mut Window,
19296        cx: &mut Context<Self>,
19297    ) {
19298        if !self.buffer.read(cx).is_singleton() {
19299            return;
19300        }
19301
19302        let fold_at_level = fold_at.0;
19303        let snapshot = self.buffer.read(cx).snapshot(cx);
19304        let mut to_fold = Vec::new();
19305        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19306
19307        let row_ranges_to_keep: Vec<Range<u32>> = self
19308            .selections
19309            .all::<Point>(&self.display_snapshot(cx))
19310            .into_iter()
19311            .map(|sel| sel.start.row..sel.end.row)
19312            .collect();
19313
19314        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19315            while start_row < end_row {
19316                match self
19317                    .snapshot(window, cx)
19318                    .crease_for_buffer_row(MultiBufferRow(start_row))
19319                {
19320                    Some(crease) => {
19321                        let nested_start_row = crease.range().start.row + 1;
19322                        let nested_end_row = crease.range().end.row;
19323
19324                        if current_level < fold_at_level {
19325                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19326                        } else if current_level == fold_at_level {
19327                            // Fold iff there is no selection completely contained within the fold region
19328                            if !row_ranges_to_keep.iter().any(|selection| {
19329                                selection.end >= nested_start_row
19330                                    && selection.start <= nested_end_row
19331                            }) {
19332                                to_fold.push(crease);
19333                            }
19334                        }
19335
19336                        start_row = nested_end_row + 1;
19337                    }
19338                    None => start_row += 1,
19339                }
19340            }
19341        }
19342
19343        self.fold_creases(to_fold, true, window, cx);
19344    }
19345
19346    pub fn fold_at_level_1(
19347        &mut self,
19348        _: &actions::FoldAtLevel1,
19349        window: &mut Window,
19350        cx: &mut Context<Self>,
19351    ) {
19352        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19353    }
19354
19355    pub fn fold_at_level_2(
19356        &mut self,
19357        _: &actions::FoldAtLevel2,
19358        window: &mut Window,
19359        cx: &mut Context<Self>,
19360    ) {
19361        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19362    }
19363
19364    pub fn fold_at_level_3(
19365        &mut self,
19366        _: &actions::FoldAtLevel3,
19367        window: &mut Window,
19368        cx: &mut Context<Self>,
19369    ) {
19370        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19371    }
19372
19373    pub fn fold_at_level_4(
19374        &mut self,
19375        _: &actions::FoldAtLevel4,
19376        window: &mut Window,
19377        cx: &mut Context<Self>,
19378    ) {
19379        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19380    }
19381
19382    pub fn fold_at_level_5(
19383        &mut self,
19384        _: &actions::FoldAtLevel5,
19385        window: &mut Window,
19386        cx: &mut Context<Self>,
19387    ) {
19388        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19389    }
19390
19391    pub fn fold_at_level_6(
19392        &mut self,
19393        _: &actions::FoldAtLevel6,
19394        window: &mut Window,
19395        cx: &mut Context<Self>,
19396    ) {
19397        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19398    }
19399
19400    pub fn fold_at_level_7(
19401        &mut self,
19402        _: &actions::FoldAtLevel7,
19403        window: &mut Window,
19404        cx: &mut Context<Self>,
19405    ) {
19406        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19407    }
19408
19409    pub fn fold_at_level_8(
19410        &mut self,
19411        _: &actions::FoldAtLevel8,
19412        window: &mut Window,
19413        cx: &mut Context<Self>,
19414    ) {
19415        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19416    }
19417
19418    pub fn fold_at_level_9(
19419        &mut self,
19420        _: &actions::FoldAtLevel9,
19421        window: &mut Window,
19422        cx: &mut Context<Self>,
19423    ) {
19424        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19425    }
19426
19427    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19428        if self.buffer.read(cx).is_singleton() {
19429            let mut fold_ranges = Vec::new();
19430            let snapshot = self.buffer.read(cx).snapshot(cx);
19431
19432            for row in 0..snapshot.max_row().0 {
19433                if let Some(foldable_range) = self
19434                    .snapshot(window, cx)
19435                    .crease_for_buffer_row(MultiBufferRow(row))
19436                {
19437                    fold_ranges.push(foldable_range);
19438                }
19439            }
19440
19441            self.fold_creases(fold_ranges, true, window, cx);
19442        } else {
19443            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19444                editor
19445                    .update_in(cx, |editor, _, cx| {
19446                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19447                            editor.fold_buffer(buffer_id, cx);
19448                        }
19449                    })
19450                    .ok();
19451            });
19452        }
19453        cx.emit(SearchEvent::ResultsCollapsedChanged(
19454            CollapseDirection::Collapsed,
19455        ));
19456    }
19457
19458    pub fn fold_function_bodies(
19459        &mut self,
19460        _: &actions::FoldFunctionBodies,
19461        window: &mut Window,
19462        cx: &mut Context<Self>,
19463    ) {
19464        let snapshot = self.buffer.read(cx).snapshot(cx);
19465
19466        let ranges = snapshot
19467            .text_object_ranges(
19468                MultiBufferOffset(0)..snapshot.len(),
19469                TreeSitterOptions::default(),
19470            )
19471            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19472            .collect::<Vec<_>>();
19473
19474        let creases = ranges
19475            .into_iter()
19476            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19477            .collect();
19478
19479        self.fold_creases(creases, true, window, cx);
19480    }
19481
19482    pub fn fold_recursive(
19483        &mut self,
19484        _: &actions::FoldRecursive,
19485        window: &mut Window,
19486        cx: &mut Context<Self>,
19487    ) {
19488        let mut to_fold = Vec::new();
19489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19490        let selections = self.selections.all_adjusted(&display_map);
19491
19492        for selection in selections {
19493            let range = selection.range().sorted();
19494            let buffer_start_row = range.start.row;
19495
19496            if range.start.row != range.end.row {
19497                let mut found = false;
19498                for row in range.start.row..=range.end.row {
19499                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19500                        found = true;
19501                        to_fold.push(crease);
19502                    }
19503                }
19504                if found {
19505                    continue;
19506                }
19507            }
19508
19509            for row in (0..=range.start.row).rev() {
19510                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19511                    if crease.range().end.row >= buffer_start_row {
19512                        to_fold.push(crease);
19513                    } else {
19514                        break;
19515                    }
19516                }
19517            }
19518        }
19519
19520        self.fold_creases(to_fold, true, window, cx);
19521    }
19522
19523    pub fn fold_at(
19524        &mut self,
19525        buffer_row: MultiBufferRow,
19526        window: &mut Window,
19527        cx: &mut Context<Self>,
19528    ) {
19529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19530
19531        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19532            let autoscroll = self
19533                .selections
19534                .all::<Point>(&display_map)
19535                .iter()
19536                .any(|selection| crease.range().overlaps(&selection.range()));
19537
19538            self.fold_creases(vec![crease], autoscroll, window, cx);
19539        }
19540    }
19541
19542    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19543        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19544            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19545            let buffer = display_map.buffer_snapshot();
19546            let selections = self.selections.all::<Point>(&display_map);
19547            let ranges = selections
19548                .iter()
19549                .map(|s| {
19550                    let range = s.display_range(&display_map).sorted();
19551                    let mut start = range.start.to_point(&display_map);
19552                    let mut end = range.end.to_point(&display_map);
19553                    start.column = 0;
19554                    end.column = buffer.line_len(MultiBufferRow(end.row));
19555                    start..end
19556                })
19557                .collect::<Vec<_>>();
19558
19559            self.unfold_ranges(&ranges, true, true, cx);
19560        } else {
19561            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19562            let buffer_ids = self
19563                .selections
19564                .disjoint_anchor_ranges()
19565                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19566                .collect::<HashSet<_>>();
19567            for buffer_id in buffer_ids {
19568                self.unfold_buffer(buffer_id, cx);
19569            }
19570        }
19571    }
19572
19573    pub fn unfold_recursive(
19574        &mut self,
19575        _: &UnfoldRecursive,
19576        _window: &mut Window,
19577        cx: &mut Context<Self>,
19578    ) {
19579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19580        let selections = self.selections.all::<Point>(&display_map);
19581        let ranges = selections
19582            .iter()
19583            .map(|s| {
19584                let mut range = s.display_range(&display_map).sorted();
19585                *range.start.column_mut() = 0;
19586                *range.end.column_mut() = display_map.line_len(range.end.row());
19587                let start = range.start.to_point(&display_map);
19588                let end = range.end.to_point(&display_map);
19589                start..end
19590            })
19591            .collect::<Vec<_>>();
19592
19593        self.unfold_ranges(&ranges, true, true, cx);
19594    }
19595
19596    pub fn unfold_at(
19597        &mut self,
19598        buffer_row: MultiBufferRow,
19599        _window: &mut Window,
19600        cx: &mut Context<Self>,
19601    ) {
19602        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19603
19604        let intersection_range = Point::new(buffer_row.0, 0)
19605            ..Point::new(
19606                buffer_row.0,
19607                display_map.buffer_snapshot().line_len(buffer_row),
19608            );
19609
19610        let autoscroll = self
19611            .selections
19612            .all::<Point>(&display_map)
19613            .iter()
19614            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19615
19616        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19617    }
19618
19619    pub fn unfold_all(
19620        &mut self,
19621        _: &actions::UnfoldAll,
19622        _window: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        if self.buffer.read(cx).is_singleton() {
19626            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19627            self.unfold_ranges(
19628                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19629                true,
19630                true,
19631                cx,
19632            );
19633        } else {
19634            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19635                editor
19636                    .update(cx, |editor, cx| {
19637                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19638                            editor.unfold_buffer(buffer_id, cx);
19639                        }
19640                    })
19641                    .ok();
19642            });
19643        }
19644        cx.emit(SearchEvent::ResultsCollapsedChanged(
19645            CollapseDirection::Expanded,
19646        ));
19647    }
19648
19649    pub fn fold_selected_ranges(
19650        &mut self,
19651        _: &FoldSelectedRanges,
19652        window: &mut Window,
19653        cx: &mut Context<Self>,
19654    ) {
19655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19656        let selections = self.selections.all_adjusted(&display_map);
19657        let ranges = selections
19658            .into_iter()
19659            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19660            .collect::<Vec<_>>();
19661        self.fold_creases(ranges, true, window, cx);
19662    }
19663
19664    pub fn fold_ranges<T: ToOffset + Clone>(
19665        &mut self,
19666        ranges: Vec<Range<T>>,
19667        auto_scroll: bool,
19668        window: &mut Window,
19669        cx: &mut Context<Self>,
19670    ) {
19671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19672        let ranges = ranges
19673            .into_iter()
19674            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19675            .collect::<Vec<_>>();
19676        self.fold_creases(ranges, auto_scroll, window, cx);
19677    }
19678
19679    pub fn fold_creases<T: ToOffset + Clone>(
19680        &mut self,
19681        creases: Vec<Crease<T>>,
19682        auto_scroll: bool,
19683        _window: &mut Window,
19684        cx: &mut Context<Self>,
19685    ) {
19686        if creases.is_empty() {
19687            return;
19688        }
19689
19690        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19691
19692        if auto_scroll {
19693            self.request_autoscroll(Autoscroll::fit(), cx);
19694        }
19695
19696        cx.notify();
19697
19698        self.scrollbar_marker_state.dirty = true;
19699        self.folds_did_change(cx);
19700    }
19701
19702    /// Removes any folds whose ranges intersect any of the given ranges.
19703    pub fn unfold_ranges<T: ToOffset + Clone>(
19704        &mut self,
19705        ranges: &[Range<T>],
19706        inclusive: bool,
19707        auto_scroll: bool,
19708        cx: &mut Context<Self>,
19709    ) {
19710        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19711            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19712        });
19713        self.folds_did_change(cx);
19714    }
19715
19716    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19717        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19718            return;
19719        }
19720
19721        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19722        self.display_map.update(cx, |display_map, cx| {
19723            display_map.fold_buffers([buffer_id], cx)
19724        });
19725
19726        let snapshot = self.display_snapshot(cx);
19727        self.selections.change_with(&snapshot, |selections| {
19728            selections.remove_selections_from_buffer(buffer_id);
19729        });
19730
19731        cx.emit(EditorEvent::BufferFoldToggled {
19732            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19733            folded: true,
19734        });
19735        cx.notify();
19736    }
19737
19738    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19739        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19740            return;
19741        }
19742        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19743        self.display_map.update(cx, |display_map, cx| {
19744            display_map.unfold_buffers([buffer_id], cx);
19745        });
19746        cx.emit(EditorEvent::BufferFoldToggled {
19747            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19748            folded: false,
19749        });
19750        cx.notify();
19751    }
19752
19753    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19754        self.display_map.read(cx).is_buffer_folded(buffer)
19755    }
19756
19757    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19758        self.display_map.read(cx).folded_buffers()
19759    }
19760
19761    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19762        self.display_map.update(cx, |display_map, cx| {
19763            display_map.disable_header_for_buffer(buffer_id, cx);
19764        });
19765        cx.notify();
19766    }
19767
19768    /// Removes any folds with the given ranges.
19769    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19770        &mut self,
19771        ranges: &[Range<T>],
19772        type_id: TypeId,
19773        auto_scroll: bool,
19774        cx: &mut Context<Self>,
19775    ) {
19776        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19777            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19778        });
19779        self.folds_did_change(cx);
19780    }
19781
19782    fn remove_folds_with<T: ToOffset + Clone>(
19783        &mut self,
19784        ranges: &[Range<T>],
19785        auto_scroll: bool,
19786        cx: &mut Context<Self>,
19787        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19788    ) {
19789        if ranges.is_empty() {
19790            return;
19791        }
19792
19793        let mut buffers_affected = HashSet::default();
19794        let multi_buffer = self.buffer().read(cx);
19795        for range in ranges {
19796            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19797                buffers_affected.insert(buffer.read(cx).remote_id());
19798            };
19799        }
19800
19801        self.display_map.update(cx, update);
19802
19803        if auto_scroll {
19804            self.request_autoscroll(Autoscroll::fit(), cx);
19805        }
19806
19807        cx.notify();
19808        self.scrollbar_marker_state.dirty = true;
19809        self.active_indent_guides_state.dirty = true;
19810    }
19811
19812    pub fn update_renderer_widths(
19813        &mut self,
19814        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19815        cx: &mut Context<Self>,
19816    ) -> bool {
19817        self.display_map
19818            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19819    }
19820
19821    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19822        self.display_map.read(cx).fold_placeholder.clone()
19823    }
19824
19825    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19826        self.buffer.update(cx, |buffer, cx| {
19827            buffer.set_all_diff_hunks_expanded(cx);
19828        });
19829    }
19830
19831    pub fn expand_all_diff_hunks(
19832        &mut self,
19833        _: &ExpandAllDiffHunks,
19834        _window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        self.buffer.update(cx, |buffer, cx| {
19838            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19839        });
19840    }
19841
19842    pub fn collapse_all_diff_hunks(
19843        &mut self,
19844        _: &CollapseAllDiffHunks,
19845        _window: &mut Window,
19846        cx: &mut Context<Self>,
19847    ) {
19848        self.buffer.update(cx, |buffer, cx| {
19849            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19850        });
19851    }
19852
19853    pub fn toggle_selected_diff_hunks(
19854        &mut self,
19855        _: &ToggleSelectedDiffHunks,
19856        _window: &mut Window,
19857        cx: &mut Context<Self>,
19858    ) {
19859        let ranges: Vec<_> = self
19860            .selections
19861            .disjoint_anchors()
19862            .iter()
19863            .map(|s| s.range())
19864            .collect();
19865        self.toggle_diff_hunks_in_ranges(ranges, cx);
19866    }
19867
19868    pub fn diff_hunks_in_ranges<'a>(
19869        &'a self,
19870        ranges: &'a [Range<Anchor>],
19871        buffer: &'a MultiBufferSnapshot,
19872    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19873        ranges.iter().flat_map(move |range| {
19874            let end_excerpt_id = range.end.excerpt_id;
19875            let range = range.to_point(buffer);
19876            let mut peek_end = range.end;
19877            if range.end.row < buffer.max_row().0 {
19878                peek_end = Point::new(range.end.row + 1, 0);
19879            }
19880            buffer
19881                .diff_hunks_in_range(range.start..peek_end)
19882                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19883        })
19884    }
19885
19886    pub fn has_stageable_diff_hunks_in_ranges(
19887        &self,
19888        ranges: &[Range<Anchor>],
19889        snapshot: &MultiBufferSnapshot,
19890    ) -> bool {
19891        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19892        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19893    }
19894
19895    pub fn toggle_staged_selected_diff_hunks(
19896        &mut self,
19897        _: &::git::ToggleStaged,
19898        _: &mut Window,
19899        cx: &mut Context<Self>,
19900    ) {
19901        let snapshot = self.buffer.read(cx).snapshot(cx);
19902        let ranges: Vec<_> = self
19903            .selections
19904            .disjoint_anchors()
19905            .iter()
19906            .map(|s| s.range())
19907            .collect();
19908        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19909        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19910    }
19911
19912    pub fn set_render_diff_hunk_controls(
19913        &mut self,
19914        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19915        cx: &mut Context<Self>,
19916    ) {
19917        self.render_diff_hunk_controls = render_diff_hunk_controls;
19918        cx.notify();
19919    }
19920
19921    pub fn stage_and_next(
19922        &mut self,
19923        _: &::git::StageAndNext,
19924        window: &mut Window,
19925        cx: &mut Context<Self>,
19926    ) {
19927        self.do_stage_or_unstage_and_next(true, window, cx);
19928    }
19929
19930    pub fn unstage_and_next(
19931        &mut self,
19932        _: &::git::UnstageAndNext,
19933        window: &mut Window,
19934        cx: &mut Context<Self>,
19935    ) {
19936        self.do_stage_or_unstage_and_next(false, window, cx);
19937    }
19938
19939    pub fn stage_or_unstage_diff_hunks(
19940        &mut self,
19941        stage: bool,
19942        ranges: Vec<Range<Anchor>>,
19943        cx: &mut Context<Self>,
19944    ) {
19945        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19946        cx.spawn(async move |this, cx| {
19947            task.await?;
19948            this.update(cx, |this, cx| {
19949                let snapshot = this.buffer.read(cx).snapshot(cx);
19950                let chunk_by = this
19951                    .diff_hunks_in_ranges(&ranges, &snapshot)
19952                    .chunk_by(|hunk| hunk.buffer_id);
19953                for (buffer_id, hunks) in &chunk_by {
19954                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19955                }
19956            })
19957        })
19958        .detach_and_log_err(cx);
19959    }
19960
19961    fn save_buffers_for_ranges_if_needed(
19962        &mut self,
19963        ranges: &[Range<Anchor>],
19964        cx: &mut Context<Editor>,
19965    ) -> Task<Result<()>> {
19966        let multibuffer = self.buffer.read(cx);
19967        let snapshot = multibuffer.read(cx);
19968        let buffer_ids: HashSet<_> = ranges
19969            .iter()
19970            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19971            .collect();
19972        drop(snapshot);
19973
19974        let mut buffers = HashSet::default();
19975        for buffer_id in buffer_ids {
19976            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19977                let buffer = buffer_entity.read(cx);
19978                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19979                {
19980                    buffers.insert(buffer_entity);
19981                }
19982            }
19983        }
19984
19985        if let Some(project) = &self.project {
19986            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19987        } else {
19988            Task::ready(Ok(()))
19989        }
19990    }
19991
19992    fn do_stage_or_unstage_and_next(
19993        &mut self,
19994        stage: bool,
19995        window: &mut Window,
19996        cx: &mut Context<Self>,
19997    ) {
19998        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19999
20000        if ranges.iter().any(|range| range.start != range.end) {
20001            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20002            return;
20003        }
20004
20005        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20006        let snapshot = self.snapshot(window, cx);
20007        let position = self
20008            .selections
20009            .newest::<Point>(&snapshot.display_snapshot)
20010            .head();
20011        let mut row = snapshot
20012            .buffer_snapshot()
20013            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20014            .find(|hunk| hunk.row_range.start.0 > position.row)
20015            .map(|hunk| hunk.row_range.start);
20016
20017        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20018        // Outside of the project diff editor, wrap around to the beginning.
20019        if !all_diff_hunks_expanded {
20020            row = row.or_else(|| {
20021                snapshot
20022                    .buffer_snapshot()
20023                    .diff_hunks_in_range(Point::zero()..position)
20024                    .find(|hunk| hunk.row_range.end.0 < position.row)
20025                    .map(|hunk| hunk.row_range.start)
20026            });
20027        }
20028
20029        if let Some(row) = row {
20030            let destination = Point::new(row.0, 0);
20031            let autoscroll = Autoscroll::center();
20032
20033            self.unfold_ranges(&[destination..destination], false, false, cx);
20034            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20035                s.select_ranges([destination..destination]);
20036            });
20037        }
20038    }
20039
20040    fn do_stage_or_unstage(
20041        &self,
20042        stage: bool,
20043        buffer_id: BufferId,
20044        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20045        cx: &mut App,
20046    ) -> Option<()> {
20047        let project = self.project()?;
20048        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20049        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20050        let buffer_snapshot = buffer.read(cx).snapshot();
20051        let file_exists = buffer_snapshot
20052            .file()
20053            .is_some_and(|file| file.disk_state().exists());
20054        diff.update(cx, |diff, cx| {
20055            diff.stage_or_unstage_hunks(
20056                stage,
20057                &hunks
20058                    .map(|hunk| buffer_diff::DiffHunk {
20059                        buffer_range: hunk.buffer_range,
20060                        // We don't need to pass in word diffs here because they're only used for rendering and
20061                        // this function changes internal state
20062                        base_word_diffs: Vec::default(),
20063                        buffer_word_diffs: Vec::default(),
20064                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20065                            ..hunk.diff_base_byte_range.end.0,
20066                        secondary_status: hunk.status.secondary,
20067                        range: Point::zero()..Point::zero(), // unused
20068                    })
20069                    .collect::<Vec<_>>(),
20070                &buffer_snapshot,
20071                file_exists,
20072                cx,
20073            )
20074        });
20075        None
20076    }
20077
20078    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20079        let ranges: Vec<_> = self
20080            .selections
20081            .disjoint_anchors()
20082            .iter()
20083            .map(|s| s.range())
20084            .collect();
20085        self.buffer
20086            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20087    }
20088
20089    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20090        self.buffer.update(cx, |buffer, cx| {
20091            let ranges = vec![Anchor::min()..Anchor::max()];
20092            if !buffer.all_diff_hunks_expanded()
20093                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20094            {
20095                buffer.collapse_diff_hunks(ranges, cx);
20096                true
20097            } else {
20098                false
20099            }
20100        })
20101    }
20102
20103    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20104        if self.buffer.read(cx).all_diff_hunks_expanded() {
20105            return true;
20106        }
20107        let ranges = vec![Anchor::min()..Anchor::max()];
20108        self.buffer
20109            .read(cx)
20110            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20111    }
20112
20113    fn toggle_diff_hunks_in_ranges(
20114        &mut self,
20115        ranges: Vec<Range<Anchor>>,
20116        cx: &mut Context<Editor>,
20117    ) {
20118        self.buffer.update(cx, |buffer, cx| {
20119            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20120            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20121        })
20122    }
20123
20124    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20125        self.buffer.update(cx, |buffer, cx| {
20126            let snapshot = buffer.snapshot(cx);
20127            let excerpt_id = range.end.excerpt_id;
20128            let point_range = range.to_point(&snapshot);
20129            let expand = !buffer.single_hunk_is_expanded(range, cx);
20130            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20131        })
20132    }
20133
20134    pub(crate) fn apply_all_diff_hunks(
20135        &mut self,
20136        _: &ApplyAllDiffHunks,
20137        window: &mut Window,
20138        cx: &mut Context<Self>,
20139    ) {
20140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20141
20142        let buffers = self.buffer.read(cx).all_buffers();
20143        for branch_buffer in buffers {
20144            branch_buffer.update(cx, |branch_buffer, cx| {
20145                branch_buffer.merge_into_base(Vec::new(), cx);
20146            });
20147        }
20148
20149        if let Some(project) = self.project.clone() {
20150            self.save(
20151                SaveOptions {
20152                    format: true,
20153                    autosave: false,
20154                },
20155                project,
20156                window,
20157                cx,
20158            )
20159            .detach_and_log_err(cx);
20160        }
20161    }
20162
20163    pub(crate) fn apply_selected_diff_hunks(
20164        &mut self,
20165        _: &ApplyDiffHunk,
20166        window: &mut Window,
20167        cx: &mut Context<Self>,
20168    ) {
20169        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20170        let snapshot = self.snapshot(window, cx);
20171        let hunks = snapshot.hunks_for_ranges(
20172            self.selections
20173                .all(&snapshot.display_snapshot)
20174                .into_iter()
20175                .map(|selection| selection.range()),
20176        );
20177        let mut ranges_by_buffer = HashMap::default();
20178        self.transact(window, cx, |editor, _window, cx| {
20179            for hunk in hunks {
20180                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20181                    ranges_by_buffer
20182                        .entry(buffer.clone())
20183                        .or_insert_with(Vec::new)
20184                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20185                }
20186            }
20187
20188            for (buffer, ranges) in ranges_by_buffer {
20189                buffer.update(cx, |buffer, cx| {
20190                    buffer.merge_into_base(ranges, cx);
20191                });
20192            }
20193        });
20194
20195        if let Some(project) = self.project.clone() {
20196            self.save(
20197                SaveOptions {
20198                    format: true,
20199                    autosave: false,
20200                },
20201                project,
20202                window,
20203                cx,
20204            )
20205            .detach_and_log_err(cx);
20206        }
20207    }
20208
20209    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20210        if hovered != self.gutter_hovered {
20211            self.gutter_hovered = hovered;
20212            cx.notify();
20213        }
20214    }
20215
20216    pub fn insert_blocks(
20217        &mut self,
20218        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20219        autoscroll: Option<Autoscroll>,
20220        cx: &mut Context<Self>,
20221    ) -> Vec<CustomBlockId> {
20222        let blocks = self
20223            .display_map
20224            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20225        if let Some(autoscroll) = autoscroll {
20226            self.request_autoscroll(autoscroll, cx);
20227        }
20228        cx.notify();
20229        blocks
20230    }
20231
20232    pub fn resize_blocks(
20233        &mut self,
20234        heights: HashMap<CustomBlockId, u32>,
20235        autoscroll: Option<Autoscroll>,
20236        cx: &mut Context<Self>,
20237    ) {
20238        self.display_map
20239            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20240        if let Some(autoscroll) = autoscroll {
20241            self.request_autoscroll(autoscroll, cx);
20242        }
20243        cx.notify();
20244    }
20245
20246    pub fn replace_blocks(
20247        &mut self,
20248        renderers: HashMap<CustomBlockId, RenderBlock>,
20249        autoscroll: Option<Autoscroll>,
20250        cx: &mut Context<Self>,
20251    ) {
20252        self.display_map
20253            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20254        if let Some(autoscroll) = autoscroll {
20255            self.request_autoscroll(autoscroll, cx);
20256        }
20257        cx.notify();
20258    }
20259
20260    pub fn remove_blocks(
20261        &mut self,
20262        block_ids: HashSet<CustomBlockId>,
20263        autoscroll: Option<Autoscroll>,
20264        cx: &mut Context<Self>,
20265    ) {
20266        self.display_map.update(cx, |display_map, cx| {
20267            display_map.remove_blocks(block_ids, cx)
20268        });
20269        if let Some(autoscroll) = autoscroll {
20270            self.request_autoscroll(autoscroll, cx);
20271        }
20272        cx.notify();
20273    }
20274
20275    pub fn row_for_block(
20276        &self,
20277        block_id: CustomBlockId,
20278        cx: &mut Context<Self>,
20279    ) -> Option<DisplayRow> {
20280        self.display_map
20281            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20282    }
20283
20284    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20285        self.focused_block = Some(focused_block);
20286    }
20287
20288    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20289        self.focused_block.take()
20290    }
20291
20292    pub fn insert_creases(
20293        &mut self,
20294        creases: impl IntoIterator<Item = Crease<Anchor>>,
20295        cx: &mut Context<Self>,
20296    ) -> Vec<CreaseId> {
20297        self.display_map
20298            .update(cx, |map, cx| map.insert_creases(creases, cx))
20299    }
20300
20301    pub fn remove_creases(
20302        &mut self,
20303        ids: impl IntoIterator<Item = CreaseId>,
20304        cx: &mut Context<Self>,
20305    ) -> Vec<(CreaseId, Range<Anchor>)> {
20306        self.display_map
20307            .update(cx, |map, cx| map.remove_creases(ids, cx))
20308    }
20309
20310    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20311        self.display_map
20312            .update(cx, |map, cx| map.snapshot(cx))
20313            .longest_row()
20314    }
20315
20316    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20317        self.display_map
20318            .update(cx, |map, cx| map.snapshot(cx))
20319            .max_point()
20320    }
20321
20322    pub fn text(&self, cx: &App) -> String {
20323        self.buffer.read(cx).read(cx).text()
20324    }
20325
20326    pub fn is_empty(&self, cx: &App) -> bool {
20327        self.buffer.read(cx).read(cx).is_empty()
20328    }
20329
20330    pub fn text_option(&self, cx: &App) -> Option<String> {
20331        let text = self.text(cx);
20332        let text = text.trim();
20333
20334        if text.is_empty() {
20335            return None;
20336        }
20337
20338        Some(text.to_string())
20339    }
20340
20341    pub fn set_text(
20342        &mut self,
20343        text: impl Into<Arc<str>>,
20344        window: &mut Window,
20345        cx: &mut Context<Self>,
20346    ) {
20347        self.transact(window, cx, |this, _, cx| {
20348            this.buffer
20349                .read(cx)
20350                .as_singleton()
20351                .expect("you can only call set_text on editors for singleton buffers")
20352                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20353        });
20354    }
20355
20356    pub fn display_text(&self, cx: &mut App) -> String {
20357        self.display_map
20358            .update(cx, |map, cx| map.snapshot(cx))
20359            .text()
20360    }
20361
20362    fn create_minimap(
20363        &self,
20364        minimap_settings: MinimapSettings,
20365        window: &mut Window,
20366        cx: &mut Context<Self>,
20367    ) -> Option<Entity<Self>> {
20368        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20369            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20370    }
20371
20372    fn initialize_new_minimap(
20373        &self,
20374        minimap_settings: MinimapSettings,
20375        window: &mut Window,
20376        cx: &mut Context<Self>,
20377    ) -> Entity<Self> {
20378        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20379        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20380
20381        let mut minimap = Editor::new_internal(
20382            EditorMode::Minimap {
20383                parent: cx.weak_entity(),
20384            },
20385            self.buffer.clone(),
20386            None,
20387            Some(self.display_map.clone()),
20388            window,
20389            cx,
20390        );
20391        minimap.scroll_manager.clone_state(&self.scroll_manager);
20392        minimap.set_text_style_refinement(TextStyleRefinement {
20393            font_size: Some(MINIMAP_FONT_SIZE),
20394            font_weight: Some(MINIMAP_FONT_WEIGHT),
20395            font_family: Some(MINIMAP_FONT_FAMILY),
20396            ..Default::default()
20397        });
20398        minimap.update_minimap_configuration(minimap_settings, cx);
20399        cx.new(|_| minimap)
20400    }
20401
20402    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20403        let current_line_highlight = minimap_settings
20404            .current_line_highlight
20405            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20406        self.set_current_line_highlight(Some(current_line_highlight));
20407    }
20408
20409    pub fn minimap(&self) -> Option<&Entity<Self>> {
20410        self.minimap
20411            .as_ref()
20412            .filter(|_| self.minimap_visibility.visible())
20413    }
20414
20415    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20416        let mut wrap_guides = smallvec![];
20417
20418        if self.show_wrap_guides == Some(false) {
20419            return wrap_guides;
20420        }
20421
20422        let settings = self.buffer.read(cx).language_settings(cx);
20423        if settings.show_wrap_guides {
20424            match self.soft_wrap_mode(cx) {
20425                SoftWrap::Column(soft_wrap) => {
20426                    wrap_guides.push((soft_wrap as usize, true));
20427                }
20428                SoftWrap::Bounded(soft_wrap) => {
20429                    wrap_guides.push((soft_wrap as usize, true));
20430                }
20431                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20432            }
20433            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20434        }
20435
20436        wrap_guides
20437    }
20438
20439    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20440        let settings = self.buffer.read(cx).language_settings(cx);
20441        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20442        match mode {
20443            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20444                SoftWrap::None
20445            }
20446            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20447            language_settings::SoftWrap::PreferredLineLength => {
20448                SoftWrap::Column(settings.preferred_line_length)
20449            }
20450            language_settings::SoftWrap::Bounded => {
20451                SoftWrap::Bounded(settings.preferred_line_length)
20452            }
20453        }
20454    }
20455
20456    pub fn set_soft_wrap_mode(
20457        &mut self,
20458        mode: language_settings::SoftWrap,
20459
20460        cx: &mut Context<Self>,
20461    ) {
20462        self.soft_wrap_mode_override = Some(mode);
20463        cx.notify();
20464    }
20465
20466    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20467        self.hard_wrap = hard_wrap;
20468        cx.notify();
20469    }
20470
20471    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20472        self.text_style_refinement = Some(style);
20473    }
20474
20475    /// called by the Element so we know what style we were most recently rendered with.
20476    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20477        // We intentionally do not inform the display map about the minimap style
20478        // so that wrapping is not recalculated and stays consistent for the editor
20479        // and its linked minimap.
20480        if !self.mode.is_minimap() {
20481            let font = style.text.font();
20482            let font_size = style.text.font_size.to_pixels(window.rem_size());
20483            let display_map = self
20484                .placeholder_display_map
20485                .as_ref()
20486                .filter(|_| self.is_empty(cx))
20487                .unwrap_or(&self.display_map);
20488
20489            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20490        }
20491        self.style = Some(style);
20492    }
20493
20494    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20495        if self.style.is_none() {
20496            self.style = Some(self.create_style(cx));
20497        }
20498        self.style.as_ref().unwrap()
20499    }
20500
20501    // Called by the element. This method is not designed to be called outside of the editor
20502    // element's layout code because it does not notify when rewrapping is computed synchronously.
20503    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20504        if self.is_empty(cx) {
20505            self.placeholder_display_map
20506                .as_ref()
20507                .map_or(false, |display_map| {
20508                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20509                })
20510        } else {
20511            self.display_map
20512                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20513        }
20514    }
20515
20516    pub fn set_soft_wrap(&mut self) {
20517        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20518    }
20519
20520    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20521        if self.soft_wrap_mode_override.is_some() {
20522            self.soft_wrap_mode_override.take();
20523        } else {
20524            let soft_wrap = match self.soft_wrap_mode(cx) {
20525                SoftWrap::GitDiff => return,
20526                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20527                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20528                    language_settings::SoftWrap::None
20529                }
20530            };
20531            self.soft_wrap_mode_override = Some(soft_wrap);
20532        }
20533        cx.notify();
20534    }
20535
20536    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20537        let Some(workspace) = self.workspace() else {
20538            return;
20539        };
20540        let fs = workspace.read(cx).app_state().fs.clone();
20541        let current_show = TabBarSettings::get_global(cx).show;
20542        update_settings_file(fs, cx, move |setting, _| {
20543            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20544        });
20545    }
20546
20547    pub fn toggle_indent_guides(
20548        &mut self,
20549        _: &ToggleIndentGuides,
20550        _: &mut Window,
20551        cx: &mut Context<Self>,
20552    ) {
20553        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20554            self.buffer
20555                .read(cx)
20556                .language_settings(cx)
20557                .indent_guides
20558                .enabled
20559        });
20560        self.show_indent_guides = Some(!currently_enabled);
20561        cx.notify();
20562    }
20563
20564    fn should_show_indent_guides(&self) -> Option<bool> {
20565        self.show_indent_guides
20566    }
20567
20568    pub fn disable_indent_guides_for_buffer(
20569        &mut self,
20570        buffer_id: BufferId,
20571        cx: &mut Context<Self>,
20572    ) {
20573        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20574        cx.notify();
20575    }
20576
20577    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20578        self.buffers_with_disabled_indent_guides
20579            .contains(&buffer_id)
20580    }
20581
20582    pub fn toggle_line_numbers(
20583        &mut self,
20584        _: &ToggleLineNumbers,
20585        _: &mut Window,
20586        cx: &mut Context<Self>,
20587    ) {
20588        let mut editor_settings = EditorSettings::get_global(cx).clone();
20589        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20590        EditorSettings::override_global(editor_settings, cx);
20591    }
20592
20593    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20594        if let Some(show_line_numbers) = self.show_line_numbers {
20595            return show_line_numbers;
20596        }
20597        EditorSettings::get_global(cx).gutter.line_numbers
20598    }
20599
20600    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20601        match (
20602            self.use_relative_line_numbers,
20603            EditorSettings::get_global(cx).relative_line_numbers,
20604        ) {
20605            (None, setting) => setting,
20606            (Some(false), _) => RelativeLineNumbers::Disabled,
20607            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20608            (Some(true), _) => RelativeLineNumbers::Enabled,
20609        }
20610    }
20611
20612    pub fn toggle_relative_line_numbers(
20613        &mut self,
20614        _: &ToggleRelativeLineNumbers,
20615        _: &mut Window,
20616        cx: &mut Context<Self>,
20617    ) {
20618        let is_relative = self.relative_line_numbers(cx);
20619        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20620    }
20621
20622    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20623        self.use_relative_line_numbers = is_relative;
20624        cx.notify();
20625    }
20626
20627    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20628        self.show_gutter = show_gutter;
20629        cx.notify();
20630    }
20631
20632    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20633        self.show_scrollbars = ScrollbarAxes {
20634            horizontal: show,
20635            vertical: show,
20636        };
20637        cx.notify();
20638    }
20639
20640    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20641        self.show_scrollbars.vertical = show;
20642        cx.notify();
20643    }
20644
20645    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20646        self.show_scrollbars.horizontal = show;
20647        cx.notify();
20648    }
20649
20650    pub fn set_minimap_visibility(
20651        &mut self,
20652        minimap_visibility: MinimapVisibility,
20653        window: &mut Window,
20654        cx: &mut Context<Self>,
20655    ) {
20656        if self.minimap_visibility != minimap_visibility {
20657            if minimap_visibility.visible() && self.minimap.is_none() {
20658                let minimap_settings = EditorSettings::get_global(cx).minimap;
20659                self.minimap =
20660                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20661            }
20662            self.minimap_visibility = minimap_visibility;
20663            cx.notify();
20664        }
20665    }
20666
20667    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20668        self.set_show_scrollbars(false, cx);
20669        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20670    }
20671
20672    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20673        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20674    }
20675
20676    /// Normally the text in full mode and auto height editors is padded on the
20677    /// left side by roughly half a character width for improved hit testing.
20678    ///
20679    /// Use this method to disable this for cases where this is not wanted (e.g.
20680    /// if you want to align the editor text with some other text above or below)
20681    /// or if you want to add this padding to single-line editors.
20682    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20683        self.offset_content = offset_content;
20684        cx.notify();
20685    }
20686
20687    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20688        self.show_line_numbers = Some(show_line_numbers);
20689        cx.notify();
20690    }
20691
20692    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20693        self.disable_expand_excerpt_buttons = true;
20694        cx.notify();
20695    }
20696
20697    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20698        self.delegate_expand_excerpts = delegate;
20699    }
20700
20701    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20702        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20703        cx.notify();
20704    }
20705
20706    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20707        self.show_code_actions = Some(show_code_actions);
20708        cx.notify();
20709    }
20710
20711    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20712        self.show_runnables = Some(show_runnables);
20713        cx.notify();
20714    }
20715
20716    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20717        self.show_breakpoints = Some(show_breakpoints);
20718        cx.notify();
20719    }
20720
20721    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20722        if self.display_map.read(cx).masked != masked {
20723            self.display_map.update(cx, |map, _| map.masked = masked);
20724        }
20725        cx.notify()
20726    }
20727
20728    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20729        self.show_wrap_guides = Some(show_wrap_guides);
20730        cx.notify();
20731    }
20732
20733    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20734        self.show_indent_guides = Some(show_indent_guides);
20735        cx.notify();
20736    }
20737
20738    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20739        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20740            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20741                && let Some(dir) = file.abs_path(cx).parent()
20742            {
20743                return Some(dir.to_owned());
20744            }
20745        }
20746
20747        None
20748    }
20749
20750    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20751        self.active_excerpt(cx)?
20752            .1
20753            .read(cx)
20754            .file()
20755            .and_then(|f| f.as_local())
20756    }
20757
20758    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20759        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20760            let buffer = buffer.read(cx);
20761            if let Some(project_path) = buffer.project_path(cx) {
20762                let project = self.project()?.read(cx);
20763                project.absolute_path(&project_path, cx)
20764            } else {
20765                buffer
20766                    .file()
20767                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20768            }
20769        })
20770    }
20771
20772    pub fn reveal_in_finder(
20773        &mut self,
20774        _: &RevealInFileManager,
20775        _window: &mut Window,
20776        cx: &mut Context<Self>,
20777    ) {
20778        if let Some(target) = self.target_file(cx) {
20779            cx.reveal_path(&target.abs_path(cx));
20780        }
20781    }
20782
20783    pub fn copy_path(
20784        &mut self,
20785        _: &zed_actions::workspace::CopyPath,
20786        _window: &mut Window,
20787        cx: &mut Context<Self>,
20788    ) {
20789        if let Some(path) = self.target_file_abs_path(cx)
20790            && let Some(path) = path.to_str()
20791        {
20792            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20793        } else {
20794            cx.propagate();
20795        }
20796    }
20797
20798    pub fn copy_relative_path(
20799        &mut self,
20800        _: &zed_actions::workspace::CopyRelativePath,
20801        _window: &mut Window,
20802        cx: &mut Context<Self>,
20803    ) {
20804        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20805            let project = self.project()?.read(cx);
20806            let path = buffer.read(cx).file()?.path();
20807            let path = path.display(project.path_style(cx));
20808            Some(path)
20809        }) {
20810            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20811        } else {
20812            cx.propagate();
20813        }
20814    }
20815
20816    /// Returns the project path for the editor's buffer, if any buffer is
20817    /// opened in the editor.
20818    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20819        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20820            buffer.read(cx).project_path(cx)
20821        } else {
20822            None
20823        }
20824    }
20825
20826    // Returns true if the editor handled a go-to-line request
20827    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20828        maybe!({
20829            let breakpoint_store = self.breakpoint_store.as_ref()?;
20830
20831            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20832            else {
20833                self.clear_row_highlights::<ActiveDebugLine>();
20834                return None;
20835            };
20836
20837            let position = active_stack_frame.position;
20838            let buffer_id = position.buffer_id?;
20839            let snapshot = self
20840                .project
20841                .as_ref()?
20842                .read(cx)
20843                .buffer_for_id(buffer_id, cx)?
20844                .read(cx)
20845                .snapshot();
20846
20847            let mut handled = false;
20848            for (id, ExcerptRange { context, .. }) in
20849                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20850            {
20851                if context.start.cmp(&position, &snapshot).is_ge()
20852                    || context.end.cmp(&position, &snapshot).is_lt()
20853                {
20854                    continue;
20855                }
20856                let snapshot = self.buffer.read(cx).snapshot(cx);
20857                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20858
20859                handled = true;
20860                self.clear_row_highlights::<ActiveDebugLine>();
20861
20862                self.go_to_line::<ActiveDebugLine>(
20863                    multibuffer_anchor,
20864                    Some(cx.theme().colors().editor_debugger_active_line_background),
20865                    window,
20866                    cx,
20867                );
20868
20869                cx.notify();
20870            }
20871
20872            handled.then_some(())
20873        })
20874        .is_some()
20875    }
20876
20877    pub fn copy_file_name_without_extension(
20878        &mut self,
20879        _: &CopyFileNameWithoutExtension,
20880        _: &mut Window,
20881        cx: &mut Context<Self>,
20882    ) {
20883        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20884            let file = buffer.read(cx).file()?;
20885            file.path().file_stem()
20886        }) {
20887            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20888        }
20889    }
20890
20891    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20892        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20893            let file = buffer.read(cx).file()?;
20894            Some(file.file_name(cx))
20895        }) {
20896            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20897        }
20898    }
20899
20900    pub fn toggle_git_blame(
20901        &mut self,
20902        _: &::git::Blame,
20903        window: &mut Window,
20904        cx: &mut Context<Self>,
20905    ) {
20906        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20907
20908        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20909            self.start_git_blame(true, window, cx);
20910        }
20911
20912        cx.notify();
20913    }
20914
20915    pub fn toggle_git_blame_inline(
20916        &mut self,
20917        _: &ToggleGitBlameInline,
20918        window: &mut Window,
20919        cx: &mut Context<Self>,
20920    ) {
20921        self.toggle_git_blame_inline_internal(true, window, cx);
20922        cx.notify();
20923    }
20924
20925    pub fn open_git_blame_commit(
20926        &mut self,
20927        _: &OpenGitBlameCommit,
20928        window: &mut Window,
20929        cx: &mut Context<Self>,
20930    ) {
20931        self.open_git_blame_commit_internal(window, cx);
20932    }
20933
20934    fn open_git_blame_commit_internal(
20935        &mut self,
20936        window: &mut Window,
20937        cx: &mut Context<Self>,
20938    ) -> Option<()> {
20939        let blame = self.blame.as_ref()?;
20940        let snapshot = self.snapshot(window, cx);
20941        let cursor = self
20942            .selections
20943            .newest::<Point>(&snapshot.display_snapshot)
20944            .head();
20945        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20946        let (_, blame_entry) = blame
20947            .update(cx, |blame, cx| {
20948                blame
20949                    .blame_for_rows(
20950                        &[RowInfo {
20951                            buffer_id: Some(buffer.remote_id()),
20952                            buffer_row: Some(point.row),
20953                            ..Default::default()
20954                        }],
20955                        cx,
20956                    )
20957                    .next()
20958            })
20959            .flatten()?;
20960        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20961        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20962        let workspace = self.workspace()?.downgrade();
20963        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20964        None
20965    }
20966
20967    pub fn git_blame_inline_enabled(&self) -> bool {
20968        self.git_blame_inline_enabled
20969    }
20970
20971    pub fn toggle_selection_menu(
20972        &mut self,
20973        _: &ToggleSelectionMenu,
20974        _: &mut Window,
20975        cx: &mut Context<Self>,
20976    ) {
20977        self.show_selection_menu = self
20978            .show_selection_menu
20979            .map(|show_selections_menu| !show_selections_menu)
20980            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20981
20982        cx.notify();
20983    }
20984
20985    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20986        self.show_selection_menu
20987            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20988    }
20989
20990    fn start_git_blame(
20991        &mut self,
20992        user_triggered: bool,
20993        window: &mut Window,
20994        cx: &mut Context<Self>,
20995    ) {
20996        if let Some(project) = self.project() {
20997            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20998                && buffer.read(cx).file().is_none()
20999            {
21000                return;
21001            }
21002
21003            let focused = self.focus_handle(cx).contains_focused(window, cx);
21004
21005            let project = project.clone();
21006            let blame = cx
21007                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
21008            self.blame_subscription =
21009                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
21010            self.blame = Some(blame);
21011        }
21012    }
21013
21014    fn toggle_git_blame_inline_internal(
21015        &mut self,
21016        user_triggered: bool,
21017        window: &mut Window,
21018        cx: &mut Context<Self>,
21019    ) {
21020        if self.git_blame_inline_enabled {
21021            self.git_blame_inline_enabled = false;
21022            self.show_git_blame_inline = false;
21023            self.show_git_blame_inline_delay_task.take();
21024        } else {
21025            self.git_blame_inline_enabled = true;
21026            self.start_git_blame_inline(user_triggered, window, cx);
21027        }
21028
21029        cx.notify();
21030    }
21031
21032    fn start_git_blame_inline(
21033        &mut self,
21034        user_triggered: bool,
21035        window: &mut Window,
21036        cx: &mut Context<Self>,
21037    ) {
21038        self.start_git_blame(user_triggered, window, cx);
21039
21040        if ProjectSettings::get_global(cx)
21041            .git
21042            .inline_blame_delay()
21043            .is_some()
21044        {
21045            self.start_inline_blame_timer(window, cx);
21046        } else {
21047            self.show_git_blame_inline = true
21048        }
21049    }
21050
21051    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21052        self.blame.as_ref()
21053    }
21054
21055    pub fn show_git_blame_gutter(&self) -> bool {
21056        self.show_git_blame_gutter
21057    }
21058
21059    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21060        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21061    }
21062
21063    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21064        self.show_git_blame_inline
21065            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21066            && !self.newest_selection_head_on_empty_line(cx)
21067            && self.has_blame_entries(cx)
21068    }
21069
21070    fn has_blame_entries(&self, cx: &App) -> bool {
21071        self.blame()
21072            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21073    }
21074
21075    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21076        let cursor_anchor = self.selections.newest_anchor().head();
21077
21078        let snapshot = self.buffer.read(cx).snapshot(cx);
21079        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21080
21081        snapshot.line_len(buffer_row) == 0
21082    }
21083
21084    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21085        let buffer_and_selection = maybe!({
21086            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21087            let selection_range = selection.range();
21088
21089            let multi_buffer = self.buffer().read(cx);
21090            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21091            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21092
21093            let (buffer, range, _) = if selection.reversed {
21094                buffer_ranges.first()
21095            } else {
21096                buffer_ranges.last()
21097            }?;
21098
21099            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21100            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21101
21102            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21103                let selection = start_row_in_buffer..end_row_in_buffer;
21104
21105                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21106            };
21107
21108            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21109
21110            Some((
21111                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21112                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21113                    ..buffer_diff_snapshot.row_to_base_text_row(
21114                        end_row_in_buffer,
21115                        Bias::Left,
21116                        buffer,
21117                    ),
21118            ))
21119        });
21120
21121        let Some((buffer, selection)) = buffer_and_selection else {
21122            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21123        };
21124
21125        let Some(project) = self.project() else {
21126            return Task::ready(Err(anyhow!("editor does not have project")));
21127        };
21128
21129        project.update(cx, |project, cx| {
21130            project.get_permalink_to_line(&buffer, selection, cx)
21131        })
21132    }
21133
21134    pub fn copy_permalink_to_line(
21135        &mut self,
21136        _: &CopyPermalinkToLine,
21137        window: &mut Window,
21138        cx: &mut Context<Self>,
21139    ) {
21140        let permalink_task = self.get_permalink_to_line(cx);
21141        let workspace = self.workspace();
21142
21143        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21144            Ok(permalink) => {
21145                cx.update(|_, cx| {
21146                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21147                })
21148                .ok();
21149            }
21150            Err(err) => {
21151                let message = format!("Failed to copy permalink: {err}");
21152
21153                anyhow::Result::<()>::Err(err).log_err();
21154
21155                if let Some(workspace) = workspace {
21156                    workspace
21157                        .update_in(cx, |workspace, _, cx| {
21158                            struct CopyPermalinkToLine;
21159
21160                            workspace.show_toast(
21161                                Toast::new(
21162                                    NotificationId::unique::<CopyPermalinkToLine>(),
21163                                    message,
21164                                ),
21165                                cx,
21166                            )
21167                        })
21168                        .ok();
21169                }
21170            }
21171        })
21172        .detach();
21173    }
21174
21175    pub fn copy_file_location(
21176        &mut self,
21177        _: &CopyFileLocation,
21178        _: &mut Window,
21179        cx: &mut Context<Self>,
21180    ) {
21181        let selection = self
21182            .selections
21183            .newest::<Point>(&self.display_snapshot(cx))
21184            .start
21185            .row
21186            + 1;
21187        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21188            let project = self.project()?.read(cx);
21189            let file = buffer.read(cx).file()?;
21190            let path = file.path().display(project.path_style(cx));
21191
21192            Some(format!("{path}:{selection}"))
21193        }) {
21194            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21195        }
21196    }
21197
21198    pub fn open_permalink_to_line(
21199        &mut self,
21200        _: &OpenPermalinkToLine,
21201        window: &mut Window,
21202        cx: &mut Context<Self>,
21203    ) {
21204        let permalink_task = self.get_permalink_to_line(cx);
21205        let workspace = self.workspace();
21206
21207        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21208            Ok(permalink) => {
21209                cx.update(|_, cx| {
21210                    cx.open_url(permalink.as_ref());
21211                })
21212                .ok();
21213            }
21214            Err(err) => {
21215                let message = format!("Failed to open permalink: {err}");
21216
21217                anyhow::Result::<()>::Err(err).log_err();
21218
21219                if let Some(workspace) = workspace {
21220                    workspace
21221                        .update(cx, |workspace, cx| {
21222                            struct OpenPermalinkToLine;
21223
21224                            workspace.show_toast(
21225                                Toast::new(
21226                                    NotificationId::unique::<OpenPermalinkToLine>(),
21227                                    message,
21228                                ),
21229                                cx,
21230                            )
21231                        })
21232                        .ok();
21233                }
21234            }
21235        })
21236        .detach();
21237    }
21238
21239    pub fn insert_uuid_v4(
21240        &mut self,
21241        _: &InsertUuidV4,
21242        window: &mut Window,
21243        cx: &mut Context<Self>,
21244    ) {
21245        self.insert_uuid(UuidVersion::V4, window, cx);
21246    }
21247
21248    pub fn insert_uuid_v7(
21249        &mut self,
21250        _: &InsertUuidV7,
21251        window: &mut Window,
21252        cx: &mut Context<Self>,
21253    ) {
21254        self.insert_uuid(UuidVersion::V7, window, cx);
21255    }
21256
21257    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21259        self.transact(window, cx, |this, window, cx| {
21260            let edits = this
21261                .selections
21262                .all::<Point>(&this.display_snapshot(cx))
21263                .into_iter()
21264                .map(|selection| {
21265                    let uuid = match version {
21266                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21267                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21268                    };
21269
21270                    (selection.range(), uuid.to_string())
21271                });
21272            this.edit(edits, cx);
21273            this.refresh_edit_prediction(true, false, window, cx);
21274        });
21275    }
21276
21277    pub fn open_selections_in_multibuffer(
21278        &mut self,
21279        _: &OpenSelectionsInMultibuffer,
21280        window: &mut Window,
21281        cx: &mut Context<Self>,
21282    ) {
21283        let multibuffer = self.buffer.read(cx);
21284
21285        let Some(buffer) = multibuffer.as_singleton() else {
21286            return;
21287        };
21288
21289        let Some(workspace) = self.workspace() else {
21290            return;
21291        };
21292
21293        let title = multibuffer.title(cx).to_string();
21294
21295        let locations = self
21296            .selections
21297            .all_anchors(&self.display_snapshot(cx))
21298            .iter()
21299            .map(|selection| {
21300                (
21301                    buffer.clone(),
21302                    (selection.start.text_anchor..selection.end.text_anchor)
21303                        .to_point(buffer.read(cx)),
21304                )
21305            })
21306            .into_group_map();
21307
21308        cx.spawn_in(window, async move |_, cx| {
21309            workspace.update_in(cx, |workspace, window, cx| {
21310                Self::open_locations_in_multibuffer(
21311                    workspace,
21312                    locations,
21313                    format!("Selections for '{title}'"),
21314                    false,
21315                    false,
21316                    MultibufferSelectionMode::All,
21317                    window,
21318                    cx,
21319                );
21320            })
21321        })
21322        .detach();
21323    }
21324
21325    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21326    /// last highlight added will be used.
21327    ///
21328    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21329    pub fn highlight_rows<T: 'static>(
21330        &mut self,
21331        range: Range<Anchor>,
21332        color: Hsla,
21333        options: RowHighlightOptions,
21334        cx: &mut Context<Self>,
21335    ) {
21336        let snapshot = self.buffer().read(cx).snapshot(cx);
21337        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21338        let ix = row_highlights.binary_search_by(|highlight| {
21339            Ordering::Equal
21340                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21341                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21342        });
21343
21344        if let Err(mut ix) = ix {
21345            let index = post_inc(&mut self.highlight_order);
21346
21347            // If this range intersects with the preceding highlight, then merge it with
21348            // the preceding highlight. Otherwise insert a new highlight.
21349            let mut merged = false;
21350            if ix > 0 {
21351                let prev_highlight = &mut row_highlights[ix - 1];
21352                if prev_highlight
21353                    .range
21354                    .end
21355                    .cmp(&range.start, &snapshot)
21356                    .is_ge()
21357                {
21358                    ix -= 1;
21359                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21360                        prev_highlight.range.end = range.end;
21361                    }
21362                    merged = true;
21363                    prev_highlight.index = index;
21364                    prev_highlight.color = color;
21365                    prev_highlight.options = options;
21366                }
21367            }
21368
21369            if !merged {
21370                row_highlights.insert(
21371                    ix,
21372                    RowHighlight {
21373                        range,
21374                        index,
21375                        color,
21376                        options,
21377                        type_id: TypeId::of::<T>(),
21378                    },
21379                );
21380            }
21381
21382            // If any of the following highlights intersect with this one, merge them.
21383            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21384                let highlight = &row_highlights[ix];
21385                if next_highlight
21386                    .range
21387                    .start
21388                    .cmp(&highlight.range.end, &snapshot)
21389                    .is_le()
21390                {
21391                    if next_highlight
21392                        .range
21393                        .end
21394                        .cmp(&highlight.range.end, &snapshot)
21395                        .is_gt()
21396                    {
21397                        row_highlights[ix].range.end = next_highlight.range.end;
21398                    }
21399                    row_highlights.remove(ix + 1);
21400                } else {
21401                    break;
21402                }
21403            }
21404        }
21405    }
21406
21407    /// Remove any highlighted row ranges of the given type that intersect the
21408    /// given ranges.
21409    pub fn remove_highlighted_rows<T: 'static>(
21410        &mut self,
21411        ranges_to_remove: Vec<Range<Anchor>>,
21412        cx: &mut Context<Self>,
21413    ) {
21414        let snapshot = self.buffer().read(cx).snapshot(cx);
21415        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21416        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21417        row_highlights.retain(|highlight| {
21418            while let Some(range_to_remove) = ranges_to_remove.peek() {
21419                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21420                    Ordering::Less | Ordering::Equal => {
21421                        ranges_to_remove.next();
21422                    }
21423                    Ordering::Greater => {
21424                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21425                            Ordering::Less | Ordering::Equal => {
21426                                return false;
21427                            }
21428                            Ordering::Greater => break,
21429                        }
21430                    }
21431                }
21432            }
21433
21434            true
21435        })
21436    }
21437
21438    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21439    pub fn clear_row_highlights<T: 'static>(&mut self) {
21440        self.highlighted_rows.remove(&TypeId::of::<T>());
21441    }
21442
21443    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21444    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21445        self.highlighted_rows
21446            .get(&TypeId::of::<T>())
21447            .map_or(&[] as &[_], |vec| vec.as_slice())
21448            .iter()
21449            .map(|highlight| (highlight.range.clone(), highlight.color))
21450    }
21451
21452    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21453    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21454    /// Allows to ignore certain kinds of highlights.
21455    pub fn highlighted_display_rows(
21456        &self,
21457        window: &mut Window,
21458        cx: &mut App,
21459    ) -> BTreeMap<DisplayRow, LineHighlight> {
21460        let snapshot = self.snapshot(window, cx);
21461        let mut used_highlight_orders = HashMap::default();
21462        self.highlighted_rows
21463            .iter()
21464            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21465            .fold(
21466                BTreeMap::<DisplayRow, LineHighlight>::new(),
21467                |mut unique_rows, highlight| {
21468                    let start = highlight.range.start.to_display_point(&snapshot);
21469                    let end = highlight.range.end.to_display_point(&snapshot);
21470                    let start_row = start.row().0;
21471                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21472                    {
21473                        end.row().0.saturating_sub(1)
21474                    } else {
21475                        end.row().0
21476                    };
21477                    for row in start_row..=end_row {
21478                        let used_index =
21479                            used_highlight_orders.entry(row).or_insert(highlight.index);
21480                        if highlight.index >= *used_index {
21481                            *used_index = highlight.index;
21482                            unique_rows.insert(
21483                                DisplayRow(row),
21484                                LineHighlight {
21485                                    include_gutter: highlight.options.include_gutter,
21486                                    border: None,
21487                                    background: highlight.color.into(),
21488                                    type_id: Some(highlight.type_id),
21489                                },
21490                            );
21491                        }
21492                    }
21493                    unique_rows
21494                },
21495            )
21496    }
21497
21498    pub fn highlighted_display_row_for_autoscroll(
21499        &self,
21500        snapshot: &DisplaySnapshot,
21501    ) -> Option<DisplayRow> {
21502        self.highlighted_rows
21503            .values()
21504            .flat_map(|highlighted_rows| highlighted_rows.iter())
21505            .filter_map(|highlight| {
21506                if highlight.options.autoscroll {
21507                    Some(highlight.range.start.to_display_point(snapshot).row())
21508                } else {
21509                    None
21510                }
21511            })
21512            .min()
21513    }
21514
21515    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21516        self.highlight_background::<SearchWithinRange>(
21517            ranges,
21518            |_, colors| colors.colors().editor_document_highlight_read_background,
21519            cx,
21520        )
21521    }
21522
21523    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21524        self.breadcrumb_header = Some(new_header);
21525    }
21526
21527    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21528        self.clear_background_highlights::<SearchWithinRange>(cx);
21529    }
21530
21531    pub fn highlight_background<T: 'static>(
21532        &mut self,
21533        ranges: &[Range<Anchor>],
21534        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21535        cx: &mut Context<Self>,
21536    ) {
21537        self.background_highlights.insert(
21538            HighlightKey::Type(TypeId::of::<T>()),
21539            (Arc::new(color_fetcher), Arc::from(ranges)),
21540        );
21541        self.scrollbar_marker_state.dirty = true;
21542        cx.notify();
21543    }
21544
21545    pub fn highlight_background_key<T: 'static>(
21546        &mut self,
21547        key: usize,
21548        ranges: &[Range<Anchor>],
21549        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21550        cx: &mut Context<Self>,
21551    ) {
21552        self.background_highlights.insert(
21553            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21554            (Arc::new(color_fetcher), Arc::from(ranges)),
21555        );
21556        self.scrollbar_marker_state.dirty = true;
21557        cx.notify();
21558    }
21559
21560    pub fn clear_background_highlights<T: 'static>(
21561        &mut self,
21562        cx: &mut Context<Self>,
21563    ) -> Option<BackgroundHighlight> {
21564        let text_highlights = self
21565            .background_highlights
21566            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21567        if !text_highlights.1.is_empty() {
21568            self.scrollbar_marker_state.dirty = true;
21569            cx.notify();
21570        }
21571        Some(text_highlights)
21572    }
21573
21574    pub fn highlight_gutter<T: 'static>(
21575        &mut self,
21576        ranges: impl Into<Vec<Range<Anchor>>>,
21577        color_fetcher: fn(&App) -> Hsla,
21578        cx: &mut Context<Self>,
21579    ) {
21580        self.gutter_highlights
21581            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21582        cx.notify();
21583    }
21584
21585    pub fn clear_gutter_highlights<T: 'static>(
21586        &mut self,
21587        cx: &mut Context<Self>,
21588    ) -> Option<GutterHighlight> {
21589        cx.notify();
21590        self.gutter_highlights.remove(&TypeId::of::<T>())
21591    }
21592
21593    pub fn insert_gutter_highlight<T: 'static>(
21594        &mut self,
21595        range: Range<Anchor>,
21596        color_fetcher: fn(&App) -> Hsla,
21597        cx: &mut Context<Self>,
21598    ) {
21599        let snapshot = self.buffer().read(cx).snapshot(cx);
21600        let mut highlights = self
21601            .gutter_highlights
21602            .remove(&TypeId::of::<T>())
21603            .map(|(_, highlights)| highlights)
21604            .unwrap_or_default();
21605        let ix = highlights.binary_search_by(|highlight| {
21606            Ordering::Equal
21607                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21608                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21609        });
21610        if let Err(ix) = ix {
21611            highlights.insert(ix, range);
21612        }
21613        self.gutter_highlights
21614            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21615    }
21616
21617    pub fn remove_gutter_highlights<T: 'static>(
21618        &mut self,
21619        ranges_to_remove: Vec<Range<Anchor>>,
21620        cx: &mut Context<Self>,
21621    ) {
21622        let snapshot = self.buffer().read(cx).snapshot(cx);
21623        let Some((color_fetcher, mut gutter_highlights)) =
21624            self.gutter_highlights.remove(&TypeId::of::<T>())
21625        else {
21626            return;
21627        };
21628        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21629        gutter_highlights.retain(|highlight| {
21630            while let Some(range_to_remove) = ranges_to_remove.peek() {
21631                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21632                    Ordering::Less | Ordering::Equal => {
21633                        ranges_to_remove.next();
21634                    }
21635                    Ordering::Greater => {
21636                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21637                            Ordering::Less | Ordering::Equal => {
21638                                return false;
21639                            }
21640                            Ordering::Greater => break,
21641                        }
21642                    }
21643                }
21644            }
21645
21646            true
21647        });
21648        self.gutter_highlights
21649            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21650    }
21651
21652    #[cfg(feature = "test-support")]
21653    pub fn all_text_highlights(
21654        &self,
21655        window: &mut Window,
21656        cx: &mut Context<Self>,
21657    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21658        let snapshot = self.snapshot(window, cx);
21659        self.display_map.update(cx, |display_map, _| {
21660            display_map
21661                .all_text_highlights()
21662                .map(|highlight| {
21663                    let (style, ranges) = highlight.as_ref();
21664                    (
21665                        *style,
21666                        ranges
21667                            .iter()
21668                            .map(|range| range.clone().to_display_points(&snapshot))
21669                            .collect(),
21670                    )
21671                })
21672                .collect()
21673        })
21674    }
21675
21676    #[cfg(feature = "test-support")]
21677    pub fn all_text_background_highlights(
21678        &self,
21679        window: &mut Window,
21680        cx: &mut Context<Self>,
21681    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21682        let snapshot = self.snapshot(window, cx);
21683        let buffer = &snapshot.buffer_snapshot();
21684        let start = buffer.anchor_before(MultiBufferOffset(0));
21685        let end = buffer.anchor_after(buffer.len());
21686        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21687    }
21688
21689    #[cfg(any(test, feature = "test-support"))]
21690    pub fn sorted_background_highlights_in_range(
21691        &self,
21692        search_range: Range<Anchor>,
21693        display_snapshot: &DisplaySnapshot,
21694        theme: &Theme,
21695    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21696        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21697        res.sort_by(|a, b| {
21698            a.0.start
21699                .cmp(&b.0.start)
21700                .then_with(|| a.0.end.cmp(&b.0.end))
21701                .then_with(|| a.1.cmp(&b.1))
21702        });
21703        res
21704    }
21705
21706    #[cfg(feature = "test-support")]
21707    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21708        let snapshot = self.buffer().read(cx).snapshot(cx);
21709
21710        let highlights = self
21711            .background_highlights
21712            .get(&HighlightKey::Type(TypeId::of::<
21713                items::BufferSearchHighlights,
21714            >()));
21715
21716        if let Some((_color, ranges)) = highlights {
21717            ranges
21718                .iter()
21719                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21720                .collect_vec()
21721        } else {
21722            vec![]
21723        }
21724    }
21725
21726    fn document_highlights_for_position<'a>(
21727        &'a self,
21728        position: Anchor,
21729        buffer: &'a MultiBufferSnapshot,
21730    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21731        let read_highlights = self
21732            .background_highlights
21733            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21734            .map(|h| &h.1);
21735        let write_highlights = self
21736            .background_highlights
21737            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21738            .map(|h| &h.1);
21739        let left_position = position.bias_left(buffer);
21740        let right_position = position.bias_right(buffer);
21741        read_highlights
21742            .into_iter()
21743            .chain(write_highlights)
21744            .flat_map(move |ranges| {
21745                let start_ix = match ranges.binary_search_by(|probe| {
21746                    let cmp = probe.end.cmp(&left_position, buffer);
21747                    if cmp.is_ge() {
21748                        Ordering::Greater
21749                    } else {
21750                        Ordering::Less
21751                    }
21752                }) {
21753                    Ok(i) | Err(i) => i,
21754                };
21755
21756                ranges[start_ix..]
21757                    .iter()
21758                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21759            })
21760    }
21761
21762    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21763        self.background_highlights
21764            .get(&HighlightKey::Type(TypeId::of::<T>()))
21765            .is_some_and(|(_, highlights)| !highlights.is_empty())
21766    }
21767
21768    /// Returns all background highlights for a given range.
21769    ///
21770    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21771    pub fn background_highlights_in_range(
21772        &self,
21773        search_range: Range<Anchor>,
21774        display_snapshot: &DisplaySnapshot,
21775        theme: &Theme,
21776    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21777        let mut results = Vec::new();
21778        for (color_fetcher, ranges) in self.background_highlights.values() {
21779            let start_ix = match ranges.binary_search_by(|probe| {
21780                let cmp = probe
21781                    .end
21782                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21783                if cmp.is_gt() {
21784                    Ordering::Greater
21785                } else {
21786                    Ordering::Less
21787                }
21788            }) {
21789                Ok(i) | Err(i) => i,
21790            };
21791            for (index, range) in ranges[start_ix..].iter().enumerate() {
21792                if range
21793                    .start
21794                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21795                    .is_ge()
21796                {
21797                    break;
21798                }
21799
21800                let color = color_fetcher(&(start_ix + index), theme);
21801                let start = range.start.to_display_point(display_snapshot);
21802                let end = range.end.to_display_point(display_snapshot);
21803                results.push((start..end, color))
21804            }
21805        }
21806        results
21807    }
21808
21809    pub fn gutter_highlights_in_range(
21810        &self,
21811        search_range: Range<Anchor>,
21812        display_snapshot: &DisplaySnapshot,
21813        cx: &App,
21814    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21815        let mut results = Vec::new();
21816        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21817            let color = color_fetcher(cx);
21818            let start_ix = match ranges.binary_search_by(|probe| {
21819                let cmp = probe
21820                    .end
21821                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21822                if cmp.is_gt() {
21823                    Ordering::Greater
21824                } else {
21825                    Ordering::Less
21826                }
21827            }) {
21828                Ok(i) | Err(i) => i,
21829            };
21830            for range in &ranges[start_ix..] {
21831                if range
21832                    .start
21833                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21834                    .is_ge()
21835                {
21836                    break;
21837                }
21838
21839                let start = range.start.to_display_point(display_snapshot);
21840                let end = range.end.to_display_point(display_snapshot);
21841                results.push((start..end, color))
21842            }
21843        }
21844        results
21845    }
21846
21847    /// Get the text ranges corresponding to the redaction query
21848    pub fn redacted_ranges(
21849        &self,
21850        search_range: Range<Anchor>,
21851        display_snapshot: &DisplaySnapshot,
21852        cx: &App,
21853    ) -> Vec<Range<DisplayPoint>> {
21854        display_snapshot
21855            .buffer_snapshot()
21856            .redacted_ranges(search_range, |file| {
21857                if let Some(file) = file {
21858                    file.is_private()
21859                        && EditorSettings::get(
21860                            Some(SettingsLocation {
21861                                worktree_id: file.worktree_id(cx),
21862                                path: file.path().as_ref(),
21863                            }),
21864                            cx,
21865                        )
21866                        .redact_private_values
21867                } else {
21868                    false
21869                }
21870            })
21871            .map(|range| {
21872                range.start.to_display_point(display_snapshot)
21873                    ..range.end.to_display_point(display_snapshot)
21874            })
21875            .collect()
21876    }
21877
21878    pub fn highlight_text_key<T: 'static>(
21879        &mut self,
21880        key: usize,
21881        ranges: Vec<Range<Anchor>>,
21882        style: HighlightStyle,
21883        merge: bool,
21884        cx: &mut Context<Self>,
21885    ) {
21886        self.display_map.update(cx, |map, cx| {
21887            map.highlight_text(
21888                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21889                ranges,
21890                style,
21891                merge,
21892                cx,
21893            );
21894        });
21895        cx.notify();
21896    }
21897
21898    pub fn highlight_text<T: 'static>(
21899        &mut self,
21900        ranges: Vec<Range<Anchor>>,
21901        style: HighlightStyle,
21902        cx: &mut Context<Self>,
21903    ) {
21904        self.display_map.update(cx, |map, cx| {
21905            map.highlight_text(
21906                HighlightKey::Type(TypeId::of::<T>()),
21907                ranges,
21908                style,
21909                false,
21910                cx,
21911            )
21912        });
21913        cx.notify();
21914    }
21915
21916    pub fn text_highlights<'a, T: 'static>(
21917        &'a self,
21918        cx: &'a App,
21919    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21920        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21921    }
21922
21923    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21924        let cleared = self
21925            .display_map
21926            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21927        if cleared {
21928            cx.notify();
21929        }
21930    }
21931
21932    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21933        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21934            && self.focus_handle.is_focused(window)
21935    }
21936
21937    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21938        self.show_cursor_when_unfocused = is_enabled;
21939        cx.notify();
21940    }
21941
21942    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21943        cx.notify();
21944    }
21945
21946    fn on_debug_session_event(
21947        &mut self,
21948        _session: Entity<Session>,
21949        event: &SessionEvent,
21950        cx: &mut Context<Self>,
21951    ) {
21952        if let SessionEvent::InvalidateInlineValue = event {
21953            self.refresh_inline_values(cx);
21954        }
21955    }
21956
21957    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21958        let Some(project) = self.project.clone() else {
21959            return;
21960        };
21961
21962        if !self.inline_value_cache.enabled {
21963            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21964            self.splice_inlays(&inlays, Vec::new(), cx);
21965            return;
21966        }
21967
21968        let current_execution_position = self
21969            .highlighted_rows
21970            .get(&TypeId::of::<ActiveDebugLine>())
21971            .and_then(|lines| lines.last().map(|line| line.range.end));
21972
21973        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21974            let inline_values = editor
21975                .update(cx, |editor, cx| {
21976                    let Some(current_execution_position) = current_execution_position else {
21977                        return Some(Task::ready(Ok(Vec::new())));
21978                    };
21979
21980                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21981                        let snapshot = buffer.snapshot(cx);
21982
21983                        let excerpt = snapshot.excerpt_containing(
21984                            current_execution_position..current_execution_position,
21985                        )?;
21986
21987                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21988                    })?;
21989
21990                    let range =
21991                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21992
21993                    project.inline_values(buffer, range, cx)
21994                })
21995                .ok()
21996                .flatten()?
21997                .await
21998                .context("refreshing debugger inlays")
21999                .log_err()?;
22000
22001            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
22002
22003            for (buffer_id, inline_value) in inline_values
22004                .into_iter()
22005                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
22006            {
22007                buffer_inline_values
22008                    .entry(buffer_id)
22009                    .or_default()
22010                    .push(inline_value);
22011            }
22012
22013            editor
22014                .update(cx, |editor, cx| {
22015                    let snapshot = editor.buffer.read(cx).snapshot(cx);
22016                    let mut new_inlays = Vec::default();
22017
22018                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22019                        let buffer_id = buffer_snapshot.remote_id();
22020                        buffer_inline_values
22021                            .get(&buffer_id)
22022                            .into_iter()
22023                            .flatten()
22024                            .for_each(|hint| {
22025                                let inlay = Inlay::debugger(
22026                                    post_inc(&mut editor.next_inlay_id),
22027                                    Anchor::in_buffer(excerpt_id, hint.position),
22028                                    hint.text(),
22029                                );
22030                                if !inlay.text().chars().contains(&'\n') {
22031                                    new_inlays.push(inlay);
22032                                }
22033                            });
22034                    }
22035
22036                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22037                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22038
22039                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22040                })
22041                .ok()?;
22042            Some(())
22043        });
22044    }
22045
22046    fn on_buffer_event(
22047        &mut self,
22048        multibuffer: &Entity<MultiBuffer>,
22049        event: &multi_buffer::Event,
22050        window: &mut Window,
22051        cx: &mut Context<Self>,
22052    ) {
22053        match event {
22054            multi_buffer::Event::Edited { edited_buffer } => {
22055                self.scrollbar_marker_state.dirty = true;
22056                self.active_indent_guides_state.dirty = true;
22057                self.refresh_active_diagnostics(cx);
22058                self.refresh_code_actions(window, cx);
22059                self.refresh_single_line_folds(window, cx);
22060                self.refresh_matching_bracket_highlights(window, cx);
22061                if self.has_active_edit_prediction() {
22062                    self.update_visible_edit_prediction(window, cx);
22063                }
22064
22065                if let Some(buffer) = edited_buffer {
22066                    if buffer.read(cx).file().is_none() {
22067                        cx.emit(EditorEvent::TitleChanged);
22068                    }
22069
22070                    if self.project.is_some() {
22071                        let buffer_id = buffer.read(cx).remote_id();
22072                        self.register_buffer(buffer_id, cx);
22073                        self.update_lsp_data(Some(buffer_id), window, cx);
22074                        self.refresh_inlay_hints(
22075                            InlayHintRefreshReason::BufferEdited(buffer_id),
22076                            cx,
22077                        );
22078                    }
22079                }
22080
22081                cx.emit(EditorEvent::BufferEdited);
22082                cx.emit(SearchEvent::MatchesInvalidated);
22083
22084                let Some(project) = &self.project else { return };
22085                let (telemetry, is_via_ssh) = {
22086                    let project = project.read(cx);
22087                    let telemetry = project.client().telemetry().clone();
22088                    let is_via_ssh = project.is_via_remote_server();
22089                    (telemetry, is_via_ssh)
22090                };
22091                telemetry.log_edit_event("editor", is_via_ssh);
22092            }
22093            multi_buffer::Event::ExcerptsAdded {
22094                buffer,
22095                predecessor,
22096                excerpts,
22097            } => {
22098                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22099                let buffer_id = buffer.read(cx).remote_id();
22100                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22101                    && let Some(project) = &self.project
22102                {
22103                    update_uncommitted_diff_for_buffer(
22104                        cx.entity(),
22105                        project,
22106                        [buffer.clone()],
22107                        self.buffer.clone(),
22108                        cx,
22109                    )
22110                    .detach();
22111                }
22112                self.update_lsp_data(Some(buffer_id), window, cx);
22113                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22114                self.colorize_brackets(false, cx);
22115                cx.emit(EditorEvent::ExcerptsAdded {
22116                    buffer: buffer.clone(),
22117                    predecessor: *predecessor,
22118                    excerpts: excerpts.clone(),
22119                });
22120            }
22121            multi_buffer::Event::ExcerptsRemoved {
22122                ids,
22123                removed_buffer_ids,
22124            } => {
22125                if let Some(inlay_hints) = &mut self.inlay_hints {
22126                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22127                }
22128                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22129                for buffer_id in removed_buffer_ids {
22130                    self.registered_buffers.remove(buffer_id);
22131                }
22132                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22133                cx.emit(EditorEvent::ExcerptsRemoved {
22134                    ids: ids.clone(),
22135                    removed_buffer_ids: removed_buffer_ids.clone(),
22136                });
22137            }
22138            multi_buffer::Event::ExcerptsEdited {
22139                excerpt_ids,
22140                buffer_ids,
22141            } => {
22142                self.display_map.update(cx, |map, cx| {
22143                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22144                });
22145                cx.emit(EditorEvent::ExcerptsEdited {
22146                    ids: excerpt_ids.clone(),
22147                });
22148            }
22149            multi_buffer::Event::ExcerptsExpanded { ids } => {
22150                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22151                self.refresh_document_highlights(cx);
22152                for id in ids {
22153                    self.fetched_tree_sitter_chunks.remove(id);
22154                }
22155                self.colorize_brackets(false, cx);
22156                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22157            }
22158            multi_buffer::Event::Reparsed(buffer_id) => {
22159                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22160                self.refresh_selected_text_highlights(true, window, cx);
22161                self.colorize_brackets(true, cx);
22162                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22163
22164                cx.emit(EditorEvent::Reparsed(*buffer_id));
22165            }
22166            multi_buffer::Event::DiffHunksToggled => {
22167                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22168            }
22169            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22170                if !is_fresh_language {
22171                    self.registered_buffers.remove(&buffer_id);
22172                }
22173                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22174                cx.emit(EditorEvent::Reparsed(*buffer_id));
22175                cx.notify();
22176            }
22177            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22178            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22179            multi_buffer::Event::FileHandleChanged
22180            | multi_buffer::Event::Reloaded
22181            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22182            multi_buffer::Event::DiagnosticsUpdated => {
22183                self.update_diagnostics_state(window, cx);
22184            }
22185            _ => {}
22186        };
22187    }
22188
22189    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22190        if !self.diagnostics_enabled() {
22191            return;
22192        }
22193        self.refresh_active_diagnostics(cx);
22194        self.refresh_inline_diagnostics(true, window, cx);
22195        self.scrollbar_marker_state.dirty = true;
22196        cx.notify();
22197    }
22198
22199    pub fn start_temporary_diff_override(&mut self) {
22200        self.load_diff_task.take();
22201        self.temporary_diff_override = true;
22202    }
22203
22204    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22205        self.temporary_diff_override = false;
22206        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22207        self.buffer.update(cx, |buffer, cx| {
22208            buffer.set_all_diff_hunks_collapsed(cx);
22209        });
22210
22211        if let Some(project) = self.project.clone() {
22212            self.load_diff_task = Some(
22213                update_uncommitted_diff_for_buffer(
22214                    cx.entity(),
22215                    &project,
22216                    self.buffer.read(cx).all_buffers(),
22217                    self.buffer.clone(),
22218                    cx,
22219                )
22220                .shared(),
22221            );
22222        }
22223    }
22224
22225    fn on_display_map_changed(
22226        &mut self,
22227        _: Entity<DisplayMap>,
22228        _: &mut Window,
22229        cx: &mut Context<Self>,
22230    ) {
22231        cx.notify();
22232    }
22233
22234    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22235        if !self.mode.is_full() {
22236            return None;
22237        }
22238
22239        let theme_settings = theme::ThemeSettings::get_global(cx);
22240        let theme = cx.theme();
22241        let accent_colors = theme.accents().clone();
22242
22243        let accent_overrides = theme_settings
22244            .theme_overrides
22245            .get(theme.name.as_ref())
22246            .map(|theme_style| &theme_style.accents)
22247            .into_iter()
22248            .flatten()
22249            .chain(
22250                theme_settings
22251                    .experimental_theme_overrides
22252                    .as_ref()
22253                    .map(|overrides| &overrides.accents)
22254                    .into_iter()
22255                    .flatten(),
22256            )
22257            .flat_map(|accent| accent.0.clone())
22258            .collect();
22259
22260        Some(AccentData {
22261            colors: accent_colors,
22262            overrides: accent_overrides,
22263        })
22264    }
22265
22266    fn fetch_applicable_language_settings(
22267        &self,
22268        cx: &App,
22269    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22270        if !self.mode.is_full() {
22271            return HashMap::default();
22272        }
22273
22274        self.buffer().read(cx).all_buffers().into_iter().fold(
22275            HashMap::default(),
22276            |mut acc, buffer| {
22277                let buffer = buffer.read(cx);
22278                let language = buffer.language().map(|language| language.name());
22279                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22280                    let file = buffer.file();
22281                    v.insert(language_settings(language, file, cx).into_owned());
22282                }
22283                acc
22284            },
22285        )
22286    }
22287
22288    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22289        let new_language_settings = self.fetch_applicable_language_settings(cx);
22290        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22291        self.applicable_language_settings = new_language_settings;
22292
22293        let new_accents = self.fetch_accent_data(cx);
22294        let accents_changed = new_accents != self.accent_data;
22295        self.accent_data = new_accents;
22296
22297        if self.diagnostics_enabled() {
22298            let new_severity = EditorSettings::get_global(cx)
22299                .diagnostics_max_severity
22300                .unwrap_or(DiagnosticSeverity::Hint);
22301            self.set_max_diagnostics_severity(new_severity, cx);
22302        }
22303        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22304        self.update_edit_prediction_settings(cx);
22305        self.refresh_edit_prediction(true, false, window, cx);
22306        self.refresh_inline_values(cx);
22307        self.refresh_inlay_hints(
22308            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22309                self.selections.newest_anchor().head(),
22310                &self.buffer.read(cx).snapshot(cx),
22311                cx,
22312            )),
22313            cx,
22314        );
22315
22316        let old_cursor_shape = self.cursor_shape;
22317        let old_show_breadcrumbs = self.show_breadcrumbs;
22318
22319        {
22320            let editor_settings = EditorSettings::get_global(cx);
22321            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22322            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22323            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22324            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22325        }
22326
22327        if old_cursor_shape != self.cursor_shape {
22328            cx.emit(EditorEvent::CursorShapeChanged);
22329        }
22330
22331        if old_show_breadcrumbs != self.show_breadcrumbs {
22332            cx.emit(EditorEvent::BreadcrumbsChanged);
22333        }
22334
22335        let project_settings = ProjectSettings::get_global(cx);
22336        self.buffer_serialization = self
22337            .should_serialize_buffer()
22338            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22339
22340        if self.mode.is_full() {
22341            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22342            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22343            if self.show_inline_diagnostics != show_inline_diagnostics {
22344                self.show_inline_diagnostics = show_inline_diagnostics;
22345                self.refresh_inline_diagnostics(false, window, cx);
22346            }
22347
22348            if self.git_blame_inline_enabled != inline_blame_enabled {
22349                self.toggle_git_blame_inline_internal(false, window, cx);
22350            }
22351
22352            let minimap_settings = EditorSettings::get_global(cx).minimap;
22353            if self.minimap_visibility != MinimapVisibility::Disabled {
22354                if self.minimap_visibility.settings_visibility()
22355                    != minimap_settings.minimap_enabled()
22356                {
22357                    self.set_minimap_visibility(
22358                        MinimapVisibility::for_mode(self.mode(), cx),
22359                        window,
22360                        cx,
22361                    );
22362                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22363                    minimap_entity.update(cx, |minimap_editor, cx| {
22364                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22365                    })
22366                }
22367            }
22368
22369            if language_settings_changed || accents_changed {
22370                self.colorize_brackets(true, cx);
22371            }
22372
22373            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22374                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22375            }) {
22376                if !inlay_splice.is_empty() {
22377                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22378                }
22379                self.refresh_colors_for_visible_range(None, window, cx);
22380            }
22381        }
22382
22383        cx.notify();
22384    }
22385
22386    pub fn set_searchable(&mut self, searchable: bool) {
22387        self.searchable = searchable;
22388    }
22389
22390    pub fn searchable(&self) -> bool {
22391        self.searchable
22392    }
22393
22394    pub fn open_excerpts_in_split(
22395        &mut self,
22396        _: &OpenExcerptsSplit,
22397        window: &mut Window,
22398        cx: &mut Context<Self>,
22399    ) {
22400        self.open_excerpts_common(None, true, window, cx)
22401    }
22402
22403    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22404        self.open_excerpts_common(None, false, window, cx)
22405    }
22406
22407    fn open_excerpts_common(
22408        &mut self,
22409        jump_data: Option<JumpData>,
22410        split: bool,
22411        window: &mut Window,
22412        cx: &mut Context<Self>,
22413    ) {
22414        let Some(workspace) = self.workspace() else {
22415            cx.propagate();
22416            return;
22417        };
22418
22419        if self.buffer.read(cx).is_singleton() {
22420            cx.propagate();
22421            return;
22422        }
22423
22424        let mut new_selections_by_buffer = HashMap::default();
22425        match &jump_data {
22426            Some(JumpData::MultiBufferPoint {
22427                excerpt_id,
22428                position,
22429                anchor,
22430                line_offset_from_top,
22431            }) => {
22432                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22433                if let Some(buffer) = multi_buffer_snapshot
22434                    .buffer_id_for_excerpt(*excerpt_id)
22435                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22436                {
22437                    let buffer_snapshot = buffer.read(cx).snapshot();
22438                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22439                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22440                    } else {
22441                        buffer_snapshot.clip_point(*position, Bias::Left)
22442                    };
22443                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22444                    new_selections_by_buffer.insert(
22445                        buffer,
22446                        (
22447                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22448                            Some(*line_offset_from_top),
22449                        ),
22450                    );
22451                }
22452            }
22453            Some(JumpData::MultiBufferRow {
22454                row,
22455                line_offset_from_top,
22456            }) => {
22457                let point = MultiBufferPoint::new(row.0, 0);
22458                if let Some((buffer, buffer_point, _)) =
22459                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22460                {
22461                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22462                    new_selections_by_buffer
22463                        .entry(buffer)
22464                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22465                        .0
22466                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22467                }
22468            }
22469            None => {
22470                let selections = self
22471                    .selections
22472                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22473                let multi_buffer = self.buffer.read(cx);
22474                for selection in selections {
22475                    for (snapshot, range, _, anchor) in multi_buffer
22476                        .snapshot(cx)
22477                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22478                    {
22479                        if let Some(anchor) = anchor {
22480                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22481                            else {
22482                                continue;
22483                            };
22484                            let offset = text::ToOffset::to_offset(
22485                                &anchor.text_anchor,
22486                                &buffer_handle.read(cx).snapshot(),
22487                            );
22488                            let range = BufferOffset(offset)..BufferOffset(offset);
22489                            new_selections_by_buffer
22490                                .entry(buffer_handle)
22491                                .or_insert((Vec::new(), None))
22492                                .0
22493                                .push(range)
22494                        } else {
22495                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22496                            else {
22497                                continue;
22498                            };
22499                            new_selections_by_buffer
22500                                .entry(buffer_handle)
22501                                .or_insert((Vec::new(), None))
22502                                .0
22503                                .push(range)
22504                        }
22505                    }
22506                }
22507            }
22508        }
22509
22510        new_selections_by_buffer
22511            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22512
22513        if new_selections_by_buffer.is_empty() {
22514            return;
22515        }
22516
22517        // We defer the pane interaction because we ourselves are a workspace item
22518        // and activating a new item causes the pane to call a method on us reentrantly,
22519        // which panics if we're on the stack.
22520        window.defer(cx, move |window, cx| {
22521            workspace.update(cx, |workspace, cx| {
22522                let pane = if split {
22523                    workspace.adjacent_pane(window, cx)
22524                } else {
22525                    workspace.active_pane().clone()
22526                };
22527
22528                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22529                    let buffer_read = buffer.read(cx);
22530                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22531                        (true, project::File::from_dyn(Some(file)).is_some())
22532                    } else {
22533                        (false, false)
22534                    };
22535
22536                    // If project file is none workspace.open_project_item will fail to open the excerpt
22537                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22538                    // so we check if there's a tab match in that case first
22539                    let editor = (!has_file || !is_project_file)
22540                        .then(|| {
22541                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22542                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22543                            // Instead, we try to activate the existing editor in the pane first.
22544                            let (editor, pane_item_index, pane_item_id) =
22545                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22546                                    let editor = item.downcast::<Editor>()?;
22547                                    let singleton_buffer =
22548                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22549                                    if singleton_buffer == buffer {
22550                                        Some((editor, i, item.item_id()))
22551                                    } else {
22552                                        None
22553                                    }
22554                                })?;
22555                            pane.update(cx, |pane, cx| {
22556                                pane.activate_item(pane_item_index, true, true, window, cx);
22557                                if !PreviewTabsSettings::get_global(cx)
22558                                    .enable_preview_from_multibuffer
22559                                {
22560                                    pane.unpreview_item_if_preview(pane_item_id);
22561                                }
22562                            });
22563                            Some(editor)
22564                        })
22565                        .flatten()
22566                        .unwrap_or_else(|| {
22567                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22568                                .enable_keep_preview_on_code_navigation;
22569                            let allow_new_preview =
22570                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22571                            workspace.open_project_item::<Self>(
22572                                pane.clone(),
22573                                buffer,
22574                                true,
22575                                true,
22576                                keep_old_preview,
22577                                allow_new_preview,
22578                                window,
22579                                cx,
22580                            )
22581                        });
22582
22583                    editor.update(cx, |editor, cx| {
22584                        if has_file && !is_project_file {
22585                            editor.set_read_only(true);
22586                        }
22587                        let autoscroll = match scroll_offset {
22588                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22589                            None => Autoscroll::newest(),
22590                        };
22591                        let nav_history = editor.nav_history.take();
22592                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22593                        let Some((&excerpt_id, _, buffer_snapshot)) =
22594                            multibuffer_snapshot.as_singleton()
22595                        else {
22596                            return;
22597                        };
22598                        editor.change_selections(
22599                            SelectionEffects::scroll(autoscroll),
22600                            window,
22601                            cx,
22602                            |s| {
22603                                s.select_ranges(ranges.into_iter().map(|range| {
22604                                    let range = buffer_snapshot.anchor_before(range.start)
22605                                        ..buffer_snapshot.anchor_after(range.end);
22606                                    multibuffer_snapshot
22607                                        .anchor_range_in_excerpt(excerpt_id, range)
22608                                        .unwrap()
22609                                }));
22610                            },
22611                        );
22612                        editor.nav_history = nav_history;
22613                    });
22614                }
22615            })
22616        });
22617    }
22618
22619    // Allow opening excerpts for buffers that either belong to the current project
22620    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22621    // are also supported so tests and other in-memory views keep working.
22622    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22623        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22624    }
22625
22626    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22627        let snapshot = self.buffer.read(cx).read(cx);
22628        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22629        Some(
22630            ranges
22631                .iter()
22632                .map(move |range| {
22633                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22634                })
22635                .collect(),
22636        )
22637    }
22638
22639    fn selection_replacement_ranges(
22640        &self,
22641        range: Range<MultiBufferOffsetUtf16>,
22642        cx: &mut App,
22643    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22644        let selections = self
22645            .selections
22646            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22647        let newest_selection = selections
22648            .iter()
22649            .max_by_key(|selection| selection.id)
22650            .unwrap();
22651        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22652        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22653        let snapshot = self.buffer.read(cx).read(cx);
22654        selections
22655            .into_iter()
22656            .map(|mut selection| {
22657                selection.start.0.0 =
22658                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22659                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22660                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22661                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22662            })
22663            .collect()
22664    }
22665
22666    fn report_editor_event(
22667        &self,
22668        reported_event: ReportEditorEvent,
22669        file_extension: Option<String>,
22670        cx: &App,
22671    ) {
22672        if cfg!(any(test, feature = "test-support")) {
22673            return;
22674        }
22675
22676        let Some(project) = &self.project else { return };
22677
22678        // If None, we are in a file without an extension
22679        let file = self
22680            .buffer
22681            .read(cx)
22682            .as_singleton()
22683            .and_then(|b| b.read(cx).file());
22684        let file_extension = file_extension.or(file
22685            .as_ref()
22686            .and_then(|file| Path::new(file.file_name(cx)).extension())
22687            .and_then(|e| e.to_str())
22688            .map(|a| a.to_string()));
22689
22690        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22691            .map(|vim_mode| vim_mode.0)
22692            .unwrap_or(false);
22693
22694        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22695        let copilot_enabled = edit_predictions_provider
22696            == language::language_settings::EditPredictionProvider::Copilot;
22697        let copilot_enabled_for_language = self
22698            .buffer
22699            .read(cx)
22700            .language_settings(cx)
22701            .show_edit_predictions;
22702
22703        let project = project.read(cx);
22704        let event_type = reported_event.event_type();
22705
22706        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22707            telemetry::event!(
22708                event_type,
22709                type = if auto_saved {"autosave"} else {"manual"},
22710                file_extension,
22711                vim_mode,
22712                copilot_enabled,
22713                copilot_enabled_for_language,
22714                edit_predictions_provider,
22715                is_via_ssh = project.is_via_remote_server(),
22716            );
22717        } else {
22718            telemetry::event!(
22719                event_type,
22720                file_extension,
22721                vim_mode,
22722                copilot_enabled,
22723                copilot_enabled_for_language,
22724                edit_predictions_provider,
22725                is_via_ssh = project.is_via_remote_server(),
22726            );
22727        };
22728    }
22729
22730    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22731    /// with each line being an array of {text, highlight} objects.
22732    fn copy_highlight_json(
22733        &mut self,
22734        _: &CopyHighlightJson,
22735        window: &mut Window,
22736        cx: &mut Context<Self>,
22737    ) {
22738        #[derive(Serialize)]
22739        struct Chunk<'a> {
22740            text: String,
22741            highlight: Option<&'a str>,
22742        }
22743
22744        let snapshot = self.buffer.read(cx).snapshot(cx);
22745        let range = self
22746            .selected_text_range(false, window, cx)
22747            .and_then(|selection| {
22748                if selection.range.is_empty() {
22749                    None
22750                } else {
22751                    Some(
22752                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22753                            selection.range.start,
22754                        )))
22755                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22756                                selection.range.end,
22757                            ))),
22758                    )
22759                }
22760            })
22761            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22762
22763        let chunks = snapshot.chunks(range, true);
22764        let mut lines = Vec::new();
22765        let mut line: VecDeque<Chunk> = VecDeque::new();
22766
22767        let Some(style) = self.style.as_ref() else {
22768            return;
22769        };
22770
22771        for chunk in chunks {
22772            let highlight = chunk
22773                .syntax_highlight_id
22774                .and_then(|id| id.name(&style.syntax));
22775            let mut chunk_lines = chunk.text.split('\n').peekable();
22776            while let Some(text) = chunk_lines.next() {
22777                let mut merged_with_last_token = false;
22778                if let Some(last_token) = line.back_mut()
22779                    && last_token.highlight == highlight
22780                {
22781                    last_token.text.push_str(text);
22782                    merged_with_last_token = true;
22783                }
22784
22785                if !merged_with_last_token {
22786                    line.push_back(Chunk {
22787                        text: text.into(),
22788                        highlight,
22789                    });
22790                }
22791
22792                if chunk_lines.peek().is_some() {
22793                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22794                        line.pop_front();
22795                    }
22796                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22797                        line.pop_back();
22798                    }
22799
22800                    lines.push(mem::take(&mut line));
22801                }
22802            }
22803        }
22804
22805        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22806            return;
22807        };
22808        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22809    }
22810
22811    pub fn open_context_menu(
22812        &mut self,
22813        _: &OpenContextMenu,
22814        window: &mut Window,
22815        cx: &mut Context<Self>,
22816    ) {
22817        self.request_autoscroll(Autoscroll::newest(), cx);
22818        let position = self
22819            .selections
22820            .newest_display(&self.display_snapshot(cx))
22821            .start;
22822        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22823    }
22824
22825    pub fn replay_insert_event(
22826        &mut self,
22827        text: &str,
22828        relative_utf16_range: Option<Range<isize>>,
22829        window: &mut Window,
22830        cx: &mut Context<Self>,
22831    ) {
22832        if !self.input_enabled {
22833            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22834            return;
22835        }
22836        if let Some(relative_utf16_range) = relative_utf16_range {
22837            let selections = self
22838                .selections
22839                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22840            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22841                let new_ranges = selections.into_iter().map(|range| {
22842                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22843                        range
22844                            .head()
22845                            .0
22846                            .0
22847                            .saturating_add_signed(relative_utf16_range.start),
22848                    ));
22849                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22850                        range
22851                            .head()
22852                            .0
22853                            .0
22854                            .saturating_add_signed(relative_utf16_range.end),
22855                    ));
22856                    start..end
22857                });
22858                s.select_ranges(new_ranges);
22859            });
22860        }
22861
22862        self.handle_input(text, window, cx);
22863    }
22864
22865    pub fn is_focused(&self, window: &Window) -> bool {
22866        self.focus_handle.is_focused(window)
22867    }
22868
22869    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22870        cx.emit(EditorEvent::Focused);
22871
22872        if let Some(descendant) = self
22873            .last_focused_descendant
22874            .take()
22875            .and_then(|descendant| descendant.upgrade())
22876        {
22877            window.focus(&descendant, cx);
22878        } else {
22879            if let Some(blame) = self.blame.as_ref() {
22880                blame.update(cx, GitBlame::focus)
22881            }
22882
22883            self.blink_manager.update(cx, BlinkManager::enable);
22884            self.show_cursor_names(window, cx);
22885            self.buffer.update(cx, |buffer, cx| {
22886                buffer.finalize_last_transaction(cx);
22887                if self.leader_id.is_none() {
22888                    buffer.set_active_selections(
22889                        &self.selections.disjoint_anchors_arc(),
22890                        self.selections.line_mode(),
22891                        self.cursor_shape,
22892                        cx,
22893                    );
22894                }
22895            });
22896
22897            if let Some(position_map) = self.last_position_map.clone() {
22898                EditorElement::mouse_moved(
22899                    self,
22900                    &MouseMoveEvent {
22901                        position: window.mouse_position(),
22902                        pressed_button: None,
22903                        modifiers: window.modifiers(),
22904                    },
22905                    &position_map,
22906                    window,
22907                    cx,
22908                );
22909            }
22910        }
22911    }
22912
22913    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22914        cx.emit(EditorEvent::FocusedIn)
22915    }
22916
22917    fn handle_focus_out(
22918        &mut self,
22919        event: FocusOutEvent,
22920        _window: &mut Window,
22921        cx: &mut Context<Self>,
22922    ) {
22923        if event.blurred != self.focus_handle {
22924            self.last_focused_descendant = Some(event.blurred);
22925        }
22926        self.selection_drag_state = SelectionDragState::None;
22927        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22928    }
22929
22930    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22931        self.blink_manager.update(cx, BlinkManager::disable);
22932        self.buffer
22933            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22934
22935        if let Some(blame) = self.blame.as_ref() {
22936            blame.update(cx, GitBlame::blur)
22937        }
22938        if !self.hover_state.focused(window, cx) {
22939            hide_hover(self, cx);
22940        }
22941        if !self
22942            .context_menu
22943            .borrow()
22944            .as_ref()
22945            .is_some_and(|context_menu| context_menu.focused(window, cx))
22946        {
22947            self.hide_context_menu(window, cx);
22948        }
22949        self.take_active_edit_prediction(cx);
22950        cx.emit(EditorEvent::Blurred);
22951        cx.notify();
22952    }
22953
22954    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22955        let mut pending: String = window
22956            .pending_input_keystrokes()
22957            .into_iter()
22958            .flatten()
22959            .filter_map(|keystroke| keystroke.key_char.clone())
22960            .collect();
22961
22962        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22963            pending = "".to_string();
22964        }
22965
22966        let existing_pending = self
22967            .text_highlights::<PendingInput>(cx)
22968            .map(|(_, ranges)| ranges.to_vec());
22969        if existing_pending.is_none() && pending.is_empty() {
22970            return;
22971        }
22972        let transaction =
22973            self.transact(window, cx, |this, window, cx| {
22974                let selections = this
22975                    .selections
22976                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22977                let edits = selections
22978                    .iter()
22979                    .map(|selection| (selection.end..selection.end, pending.clone()));
22980                this.edit(edits, cx);
22981                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22982                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22983                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22984                    }));
22985                });
22986                if let Some(existing_ranges) = existing_pending {
22987                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22988                    this.edit(edits, cx);
22989                }
22990            });
22991
22992        let snapshot = self.snapshot(window, cx);
22993        let ranges = self
22994            .selections
22995            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22996            .into_iter()
22997            .map(|selection| {
22998                snapshot.buffer_snapshot().anchor_after(selection.end)
22999                    ..snapshot
23000                        .buffer_snapshot()
23001                        .anchor_before(selection.end + pending.len())
23002            })
23003            .collect();
23004
23005        if pending.is_empty() {
23006            self.clear_highlights::<PendingInput>(cx);
23007        } else {
23008            self.highlight_text::<PendingInput>(
23009                ranges,
23010                HighlightStyle {
23011                    underline: Some(UnderlineStyle {
23012                        thickness: px(1.),
23013                        color: None,
23014                        wavy: false,
23015                    }),
23016                    ..Default::default()
23017                },
23018                cx,
23019            );
23020        }
23021
23022        self.ime_transaction = self.ime_transaction.or(transaction);
23023        if let Some(transaction) = self.ime_transaction {
23024            self.buffer.update(cx, |buffer, cx| {
23025                buffer.group_until_transaction(transaction, cx);
23026            });
23027        }
23028
23029        if self.text_highlights::<PendingInput>(cx).is_none() {
23030            self.ime_transaction.take();
23031        }
23032    }
23033
23034    pub fn register_action_renderer(
23035        &mut self,
23036        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23037    ) -> Subscription {
23038        let id = self.next_editor_action_id.post_inc();
23039        self.editor_actions
23040            .borrow_mut()
23041            .insert(id, Box::new(listener));
23042
23043        let editor_actions = self.editor_actions.clone();
23044        Subscription::new(move || {
23045            editor_actions.borrow_mut().remove(&id);
23046        })
23047    }
23048
23049    pub fn register_action<A: Action>(
23050        &mut self,
23051        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23052    ) -> Subscription {
23053        let id = self.next_editor_action_id.post_inc();
23054        let listener = Arc::new(listener);
23055        self.editor_actions.borrow_mut().insert(
23056            id,
23057            Box::new(move |_, window, _| {
23058                let listener = listener.clone();
23059                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23060                    let action = action.downcast_ref().unwrap();
23061                    if phase == DispatchPhase::Bubble {
23062                        listener(action, window, cx)
23063                    }
23064                })
23065            }),
23066        );
23067
23068        let editor_actions = self.editor_actions.clone();
23069        Subscription::new(move || {
23070            editor_actions.borrow_mut().remove(&id);
23071        })
23072    }
23073
23074    pub fn file_header_size(&self) -> u32 {
23075        FILE_HEADER_HEIGHT
23076    }
23077
23078    pub fn restore(
23079        &mut self,
23080        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23081        window: &mut Window,
23082        cx: &mut Context<Self>,
23083    ) {
23084        self.buffer().update(cx, |multi_buffer, cx| {
23085            for (buffer_id, changes) in revert_changes {
23086                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23087                    buffer.update(cx, |buffer, cx| {
23088                        buffer.edit(
23089                            changes
23090                                .into_iter()
23091                                .map(|(range, text)| (range, text.to_string())),
23092                            None,
23093                            cx,
23094                        );
23095                    });
23096                }
23097            }
23098        });
23099        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23100            selections.refresh()
23101        });
23102    }
23103
23104    pub fn to_pixel_point(
23105        &mut self,
23106        source: multi_buffer::Anchor,
23107        editor_snapshot: &EditorSnapshot,
23108        window: &mut Window,
23109        cx: &App,
23110    ) -> Option<gpui::Point<Pixels>> {
23111        let source_point = source.to_display_point(editor_snapshot);
23112        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23113    }
23114
23115    pub fn display_to_pixel_point(
23116        &mut self,
23117        source: DisplayPoint,
23118        editor_snapshot: &EditorSnapshot,
23119        window: &mut Window,
23120        cx: &App,
23121    ) -> Option<gpui::Point<Pixels>> {
23122        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23123        let text_layout_details = self.text_layout_details(window);
23124        let scroll_top = text_layout_details
23125            .scroll_anchor
23126            .scroll_position(editor_snapshot)
23127            .y;
23128
23129        if source.row().as_f64() < scroll_top.floor() {
23130            return None;
23131        }
23132        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23133        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23134        Some(gpui::Point::new(source_x, source_y))
23135    }
23136
23137    pub fn has_visible_completions_menu(&self) -> bool {
23138        !self.edit_prediction_preview_is_active()
23139            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23140                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23141            })
23142    }
23143
23144    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23145        if self.mode.is_minimap() {
23146            return;
23147        }
23148        self.addons
23149            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23150    }
23151
23152    pub fn unregister_addon<T: Addon>(&mut self) {
23153        self.addons.remove(&std::any::TypeId::of::<T>());
23154    }
23155
23156    pub fn addon<T: Addon>(&self) -> Option<&T> {
23157        let type_id = std::any::TypeId::of::<T>();
23158        self.addons
23159            .get(&type_id)
23160            .and_then(|item| item.to_any().downcast_ref::<T>())
23161    }
23162
23163    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23164        let type_id = std::any::TypeId::of::<T>();
23165        self.addons
23166            .get_mut(&type_id)
23167            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23168    }
23169
23170    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23171        let text_layout_details = self.text_layout_details(window);
23172        let style = &text_layout_details.editor_style;
23173        let font_id = window.text_system().resolve_font(&style.text.font());
23174        let font_size = style.text.font_size.to_pixels(window.rem_size());
23175        let line_height = style.text.line_height_in_pixels(window.rem_size());
23176        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23177        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23178
23179        CharacterDimensions {
23180            em_width,
23181            em_advance,
23182            line_height,
23183        }
23184    }
23185
23186    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23187        self.load_diff_task.clone()
23188    }
23189
23190    fn read_metadata_from_db(
23191        &mut self,
23192        item_id: u64,
23193        workspace_id: WorkspaceId,
23194        window: &mut Window,
23195        cx: &mut Context<Editor>,
23196    ) {
23197        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23198            && !self.mode.is_minimap()
23199            && WorkspaceSettings::get(None, cx).restore_on_startup
23200                != RestoreOnStartupBehavior::EmptyTab
23201        {
23202            let buffer_snapshot = OnceCell::new();
23203
23204            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23205                && !folds.is_empty()
23206            {
23207                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23208                self.fold_ranges(
23209                    folds
23210                        .into_iter()
23211                        .map(|(start, end)| {
23212                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23213                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23214                        })
23215                        .collect(),
23216                    false,
23217                    window,
23218                    cx,
23219                );
23220            }
23221
23222            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23223                && !selections.is_empty()
23224            {
23225                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23226                // skip adding the initial selection to selection history
23227                self.selection_history.mode = SelectionHistoryMode::Skipping;
23228                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23229                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23230                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23231                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23232                    }));
23233                });
23234                self.selection_history.mode = SelectionHistoryMode::Normal;
23235            };
23236        }
23237
23238        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23239    }
23240
23241    fn update_lsp_data(
23242        &mut self,
23243        for_buffer: Option<BufferId>,
23244        window: &mut Window,
23245        cx: &mut Context<'_, Self>,
23246    ) {
23247        self.pull_diagnostics(for_buffer, window, cx);
23248        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23249    }
23250
23251    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23252        if self.ignore_lsp_data() {
23253            return;
23254        }
23255        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23256            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23257        }
23258    }
23259
23260    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23261        if self.ignore_lsp_data() {
23262            return;
23263        }
23264
23265        if !self.registered_buffers.contains_key(&buffer_id)
23266            && let Some(project) = self.project.as_ref()
23267        {
23268            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23269                project.update(cx, |project, cx| {
23270                    self.registered_buffers.insert(
23271                        buffer_id,
23272                        project.register_buffer_with_language_servers(&buffer, cx),
23273                    );
23274                });
23275            } else {
23276                self.registered_buffers.remove(&buffer_id);
23277            }
23278        }
23279    }
23280
23281    fn ignore_lsp_data(&self) -> bool {
23282        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23283        // skip any LSP updates for it.
23284        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23285    }
23286
23287    fn create_style(&self, cx: &App) -> EditorStyle {
23288        let settings = ThemeSettings::get_global(cx);
23289
23290        let mut text_style = match self.mode {
23291            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23292                color: cx.theme().colors().editor_foreground,
23293                font_family: settings.ui_font.family.clone(),
23294                font_features: settings.ui_font.features.clone(),
23295                font_fallbacks: settings.ui_font.fallbacks.clone(),
23296                font_size: rems(0.875).into(),
23297                font_weight: settings.ui_font.weight,
23298                line_height: relative(settings.buffer_line_height.value()),
23299                ..Default::default()
23300            },
23301            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23302                color: cx.theme().colors().editor_foreground,
23303                font_family: settings.buffer_font.family.clone(),
23304                font_features: settings.buffer_font.features.clone(),
23305                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23306                font_size: settings.buffer_font_size(cx).into(),
23307                font_weight: settings.buffer_font.weight,
23308                line_height: relative(settings.buffer_line_height.value()),
23309                ..Default::default()
23310            },
23311        };
23312        if let Some(text_style_refinement) = &self.text_style_refinement {
23313            text_style.refine(text_style_refinement)
23314        }
23315
23316        let background = match self.mode {
23317            EditorMode::SingleLine => cx.theme().system().transparent,
23318            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23319            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23320            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23321        };
23322
23323        EditorStyle {
23324            background,
23325            border: cx.theme().colors().border,
23326            local_player: cx.theme().players().local(),
23327            text: text_style,
23328            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23329            syntax: cx.theme().syntax().clone(),
23330            status: cx.theme().status().clone(),
23331            inlay_hints_style: make_inlay_hints_style(cx),
23332            edit_prediction_styles: make_suggestion_styles(cx),
23333            unnecessary_code_fade: settings.unnecessary_code_fade,
23334            show_underlines: self.diagnostics_enabled(),
23335        }
23336    }
23337    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23338        let cursor = self.selections.newest_anchor().head();
23339        let multibuffer = self.buffer().read(cx);
23340        let is_singleton = multibuffer.is_singleton();
23341        let (buffer_id, symbols) = multibuffer
23342            .read(cx)
23343            .symbols_containing(cursor, Some(variant.syntax()))?;
23344        let buffer = multibuffer.buffer(buffer_id)?;
23345
23346        let buffer = buffer.read(cx);
23347        let settings = ThemeSettings::get_global(cx);
23348        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23349        let mut breadcrumbs = if is_singleton {
23350            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23351                buffer
23352                    .snapshot()
23353                    .resolve_file_path(
23354                        self.project
23355                            .as_ref()
23356                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23357                            .unwrap_or_default(),
23358                        cx,
23359                    )
23360                    .unwrap_or_else(|| {
23361                        if multibuffer.is_singleton() {
23362                            multibuffer.title(cx).to_string()
23363                        } else {
23364                            "untitled".to_string()
23365                        }
23366                    })
23367            });
23368            vec![BreadcrumbText {
23369                text,
23370                highlights: None,
23371                font: Some(settings.buffer_font.clone()),
23372            }]
23373        } else {
23374            vec![]
23375        };
23376
23377        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23378            text: symbol.text,
23379            highlights: Some(symbol.highlight_ranges),
23380            font: Some(settings.buffer_font.clone()),
23381        }));
23382        Some(breadcrumbs)
23383    }
23384}
23385
23386fn edit_for_markdown_paste<'a>(
23387    buffer: &MultiBufferSnapshot,
23388    range: Range<MultiBufferOffset>,
23389    to_insert: &'a str,
23390    url: Option<url::Url>,
23391) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23392    if url.is_none() {
23393        return (range, Cow::Borrowed(to_insert));
23394    };
23395
23396    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23397
23398    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23399        Cow::Borrowed(to_insert)
23400    } else {
23401        Cow::Owned(format!("[{old_text}]({to_insert})"))
23402    };
23403    (range, new_text)
23404}
23405
23406fn process_completion_for_edit(
23407    completion: &Completion,
23408    intent: CompletionIntent,
23409    buffer: &Entity<Buffer>,
23410    cursor_position: &text::Anchor,
23411    cx: &mut Context<Editor>,
23412) -> CompletionEdit {
23413    let buffer = buffer.read(cx);
23414    let buffer_snapshot = buffer.snapshot();
23415    let (snippet, new_text) = if completion.is_snippet() {
23416        let mut snippet_source = completion.new_text.clone();
23417        // Workaround for typescript language server issues so that methods don't expand within
23418        // strings and functions with type expressions. The previous point is used because the query
23419        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23420        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23421        let previous_point = if previous_point.column > 0 {
23422            cursor_position.to_previous_offset(&buffer_snapshot)
23423        } else {
23424            cursor_position.to_offset(&buffer_snapshot)
23425        };
23426        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23427            && scope.prefers_label_for_snippet_in_completion()
23428            && let Some(label) = completion.label()
23429            && matches!(
23430                completion.kind(),
23431                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23432            )
23433        {
23434            snippet_source = label;
23435        }
23436        match Snippet::parse(&snippet_source).log_err() {
23437            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23438            None => (None, completion.new_text.clone()),
23439        }
23440    } else {
23441        (None, completion.new_text.clone())
23442    };
23443
23444    let mut range_to_replace = {
23445        let replace_range = &completion.replace_range;
23446        if let CompletionSource::Lsp {
23447            insert_range: Some(insert_range),
23448            ..
23449        } = &completion.source
23450        {
23451            debug_assert_eq!(
23452                insert_range.start, replace_range.start,
23453                "insert_range and replace_range should start at the same position"
23454            );
23455            debug_assert!(
23456                insert_range
23457                    .start
23458                    .cmp(cursor_position, &buffer_snapshot)
23459                    .is_le(),
23460                "insert_range should start before or at cursor position"
23461            );
23462            debug_assert!(
23463                replace_range
23464                    .start
23465                    .cmp(cursor_position, &buffer_snapshot)
23466                    .is_le(),
23467                "replace_range should start before or at cursor position"
23468            );
23469
23470            let should_replace = match intent {
23471                CompletionIntent::CompleteWithInsert => false,
23472                CompletionIntent::CompleteWithReplace => true,
23473                CompletionIntent::Complete | CompletionIntent::Compose => {
23474                    let insert_mode =
23475                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23476                            .completions
23477                            .lsp_insert_mode;
23478                    match insert_mode {
23479                        LspInsertMode::Insert => false,
23480                        LspInsertMode::Replace => true,
23481                        LspInsertMode::ReplaceSubsequence => {
23482                            let mut text_to_replace = buffer.chars_for_range(
23483                                buffer.anchor_before(replace_range.start)
23484                                    ..buffer.anchor_after(replace_range.end),
23485                            );
23486                            let mut current_needle = text_to_replace.next();
23487                            for haystack_ch in completion.label.text.chars() {
23488                                if let Some(needle_ch) = current_needle
23489                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23490                                {
23491                                    current_needle = text_to_replace.next();
23492                                }
23493                            }
23494                            current_needle.is_none()
23495                        }
23496                        LspInsertMode::ReplaceSuffix => {
23497                            if replace_range
23498                                .end
23499                                .cmp(cursor_position, &buffer_snapshot)
23500                                .is_gt()
23501                            {
23502                                let range_after_cursor = *cursor_position..replace_range.end;
23503                                let text_after_cursor = buffer
23504                                    .text_for_range(
23505                                        buffer.anchor_before(range_after_cursor.start)
23506                                            ..buffer.anchor_after(range_after_cursor.end),
23507                                    )
23508                                    .collect::<String>()
23509                                    .to_ascii_lowercase();
23510                                completion
23511                                    .label
23512                                    .text
23513                                    .to_ascii_lowercase()
23514                                    .ends_with(&text_after_cursor)
23515                            } else {
23516                                true
23517                            }
23518                        }
23519                    }
23520                }
23521            };
23522
23523            if should_replace {
23524                replace_range.clone()
23525            } else {
23526                insert_range.clone()
23527            }
23528        } else {
23529            replace_range.clone()
23530        }
23531    };
23532
23533    if range_to_replace
23534        .end
23535        .cmp(cursor_position, &buffer_snapshot)
23536        .is_lt()
23537    {
23538        range_to_replace.end = *cursor_position;
23539    }
23540
23541    let replace_range = range_to_replace.to_offset(buffer);
23542    CompletionEdit {
23543        new_text,
23544        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23545        snippet,
23546    }
23547}
23548
23549struct CompletionEdit {
23550    new_text: String,
23551    replace_range: Range<BufferOffset>,
23552    snippet: Option<Snippet>,
23553}
23554
23555fn comment_delimiter_for_newline(
23556    start_point: &Point,
23557    buffer: &MultiBufferSnapshot,
23558    language: &LanguageScope,
23559) -> Option<Arc<str>> {
23560    let delimiters = language.line_comment_prefixes();
23561    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23562    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23563
23564    let num_of_whitespaces = snapshot
23565        .chars_for_range(range.clone())
23566        .take_while(|c| c.is_whitespace())
23567        .count();
23568    let comment_candidate = snapshot
23569        .chars_for_range(range.clone())
23570        .skip(num_of_whitespaces)
23571        .take(max_len_of_delimiter)
23572        .collect::<String>();
23573    let (delimiter, trimmed_len) = delimiters
23574        .iter()
23575        .filter_map(|delimiter| {
23576            let prefix = delimiter.trim_end();
23577            if comment_candidate.starts_with(prefix) {
23578                Some((delimiter, prefix.len()))
23579            } else {
23580                None
23581            }
23582        })
23583        .max_by_key(|(_, len)| *len)?;
23584
23585    if let Some(BlockCommentConfig {
23586        start: block_start, ..
23587    }) = language.block_comment()
23588    {
23589        let block_start_trimmed = block_start.trim_end();
23590        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23591            let line_content = snapshot
23592                .chars_for_range(range)
23593                .skip(num_of_whitespaces)
23594                .take(block_start_trimmed.len())
23595                .collect::<String>();
23596
23597            if line_content.starts_with(block_start_trimmed) {
23598                return None;
23599            }
23600        }
23601    }
23602
23603    let cursor_is_placed_after_comment_marker =
23604        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23605    if cursor_is_placed_after_comment_marker {
23606        Some(delimiter.clone())
23607    } else {
23608        None
23609    }
23610}
23611
23612fn documentation_delimiter_for_newline(
23613    start_point: &Point,
23614    buffer: &MultiBufferSnapshot,
23615    language: &LanguageScope,
23616    newline_config: &mut NewlineConfig,
23617) -> Option<Arc<str>> {
23618    let BlockCommentConfig {
23619        start: start_tag,
23620        end: end_tag,
23621        prefix: delimiter,
23622        tab_size: len,
23623    } = language.documentation_comment()?;
23624    let is_within_block_comment = buffer
23625        .language_scope_at(*start_point)
23626        .is_some_and(|scope| scope.override_name() == Some("comment"));
23627    if !is_within_block_comment {
23628        return None;
23629    }
23630
23631    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23632
23633    let num_of_whitespaces = snapshot
23634        .chars_for_range(range.clone())
23635        .take_while(|c| c.is_whitespace())
23636        .count();
23637
23638    // 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.
23639    let column = start_point.column;
23640    let cursor_is_after_start_tag = {
23641        let start_tag_len = start_tag.len();
23642        let start_tag_line = snapshot
23643            .chars_for_range(range.clone())
23644            .skip(num_of_whitespaces)
23645            .take(start_tag_len)
23646            .collect::<String>();
23647        if start_tag_line.starts_with(start_tag.as_ref()) {
23648            num_of_whitespaces + start_tag_len <= column as usize
23649        } else {
23650            false
23651        }
23652    };
23653
23654    let cursor_is_after_delimiter = {
23655        let delimiter_trim = delimiter.trim_end();
23656        let delimiter_line = snapshot
23657            .chars_for_range(range.clone())
23658            .skip(num_of_whitespaces)
23659            .take(delimiter_trim.len())
23660            .collect::<String>();
23661        if delimiter_line.starts_with(delimiter_trim) {
23662            num_of_whitespaces + delimiter_trim.len() <= column as usize
23663        } else {
23664            false
23665        }
23666    };
23667
23668    let mut needs_extra_line = false;
23669    let mut extra_line_additional_indent = IndentSize::spaces(0);
23670
23671    let cursor_is_before_end_tag_if_exists = {
23672        let mut char_position = 0u32;
23673        let mut end_tag_offset = None;
23674
23675        'outer: for chunk in snapshot.text_for_range(range) {
23676            if let Some(byte_pos) = chunk.find(&**end_tag) {
23677                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23678                end_tag_offset = Some(char_position + chars_before_match);
23679                break 'outer;
23680            }
23681            char_position += chunk.chars().count() as u32;
23682        }
23683
23684        if let Some(end_tag_offset) = end_tag_offset {
23685            let cursor_is_before_end_tag = column <= end_tag_offset;
23686            if cursor_is_after_start_tag {
23687                if cursor_is_before_end_tag {
23688                    needs_extra_line = true;
23689                }
23690                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23691                if cursor_is_at_start_of_end_tag {
23692                    extra_line_additional_indent.len = *len;
23693                }
23694            }
23695            cursor_is_before_end_tag
23696        } else {
23697            true
23698        }
23699    };
23700
23701    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23702        && cursor_is_before_end_tag_if_exists
23703    {
23704        let additional_indent = if cursor_is_after_start_tag {
23705            IndentSize::spaces(*len)
23706        } else {
23707            IndentSize::spaces(0)
23708        };
23709
23710        *newline_config = NewlineConfig::Newline {
23711            additional_indent,
23712            extra_line_additional_indent: if needs_extra_line {
23713                Some(extra_line_additional_indent)
23714            } else {
23715                None
23716            },
23717            prevent_auto_indent: true,
23718        };
23719        Some(delimiter.clone())
23720    } else {
23721        None
23722    }
23723}
23724
23725const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23726
23727fn list_delimiter_for_newline(
23728    start_point: &Point,
23729    buffer: &MultiBufferSnapshot,
23730    language: &LanguageScope,
23731    newline_config: &mut NewlineConfig,
23732) -> Option<Arc<str>> {
23733    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23734
23735    let num_of_whitespaces = snapshot
23736        .chars_for_range(range.clone())
23737        .take_while(|c| c.is_whitespace())
23738        .count();
23739
23740    let task_list_entries: Vec<_> = language
23741        .task_list()
23742        .into_iter()
23743        .flat_map(|config| {
23744            config
23745                .prefixes
23746                .iter()
23747                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23748        })
23749        .collect();
23750    let unordered_list_entries: Vec<_> = language
23751        .unordered_list()
23752        .iter()
23753        .map(|marker| (marker.as_ref(), marker.as_ref()))
23754        .collect();
23755
23756    let all_entries: Vec<_> = task_list_entries
23757        .into_iter()
23758        .chain(unordered_list_entries)
23759        .collect();
23760
23761    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23762        let candidate: String = snapshot
23763            .chars_for_range(range.clone())
23764            .skip(num_of_whitespaces)
23765            .take(max_prefix_len)
23766            .collect();
23767
23768        if let Some((prefix, continuation)) = all_entries
23769            .iter()
23770            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23771            .max_by_key(|(prefix, _)| prefix.len())
23772        {
23773            let end_of_prefix = num_of_whitespaces + prefix.len();
23774            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23775            let has_content_after_marker = snapshot
23776                .chars_for_range(range)
23777                .skip(end_of_prefix)
23778                .any(|c| !c.is_whitespace());
23779
23780            if has_content_after_marker && cursor_is_after_prefix {
23781                return Some((*continuation).into());
23782            }
23783
23784            if start_point.column as usize == end_of_prefix {
23785                if num_of_whitespaces == 0 {
23786                    *newline_config = NewlineConfig::ClearCurrentLine;
23787                } else {
23788                    *newline_config = NewlineConfig::UnindentCurrentLine {
23789                        continuation: (*continuation).into(),
23790                    };
23791                }
23792            }
23793
23794            return None;
23795        }
23796    }
23797
23798    let candidate: String = snapshot
23799        .chars_for_range(range.clone())
23800        .skip(num_of_whitespaces)
23801        .take(ORDERED_LIST_MAX_MARKER_LEN)
23802        .collect();
23803
23804    for ordered_config in language.ordered_list() {
23805        let regex = match Regex::new(&ordered_config.pattern) {
23806            Ok(r) => r,
23807            Err(_) => continue,
23808        };
23809
23810        if let Some(captures) = regex.captures(&candidate) {
23811            let full_match = captures.get(0)?;
23812            let marker_len = full_match.len();
23813            let end_of_prefix = num_of_whitespaces + marker_len;
23814            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23815
23816            let has_content_after_marker = snapshot
23817                .chars_for_range(range)
23818                .skip(end_of_prefix)
23819                .any(|c| !c.is_whitespace());
23820
23821            if has_content_after_marker && cursor_is_after_prefix {
23822                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23823                let continuation = ordered_config
23824                    .format
23825                    .replace("{1}", &(number + 1).to_string());
23826                return Some(continuation.into());
23827            }
23828
23829            if start_point.column as usize == end_of_prefix {
23830                let continuation = ordered_config.format.replace("{1}", "1");
23831                if num_of_whitespaces == 0 {
23832                    *newline_config = NewlineConfig::ClearCurrentLine;
23833                } else {
23834                    *newline_config = NewlineConfig::UnindentCurrentLine {
23835                        continuation: continuation.into(),
23836                    };
23837                }
23838            }
23839
23840            return None;
23841        }
23842    }
23843
23844    None
23845}
23846
23847fn is_list_prefix_row(
23848    row: MultiBufferRow,
23849    buffer: &MultiBufferSnapshot,
23850    language: &LanguageScope,
23851) -> bool {
23852    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23853        return false;
23854    };
23855
23856    let num_of_whitespaces = snapshot
23857        .chars_for_range(range.clone())
23858        .take_while(|c| c.is_whitespace())
23859        .count();
23860
23861    let task_list_prefixes: Vec<_> = language
23862        .task_list()
23863        .into_iter()
23864        .flat_map(|config| {
23865            config
23866                .prefixes
23867                .iter()
23868                .map(|p| p.as_ref())
23869                .collect::<Vec<_>>()
23870        })
23871        .collect();
23872    let unordered_list_markers: Vec<_> = language
23873        .unordered_list()
23874        .iter()
23875        .map(|marker| marker.as_ref())
23876        .collect();
23877    let all_prefixes: Vec<_> = task_list_prefixes
23878        .into_iter()
23879        .chain(unordered_list_markers)
23880        .collect();
23881    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23882        let candidate: String = snapshot
23883            .chars_for_range(range.clone())
23884            .skip(num_of_whitespaces)
23885            .take(max_prefix_len)
23886            .collect();
23887        if all_prefixes
23888            .iter()
23889            .any(|prefix| candidate.starts_with(*prefix))
23890        {
23891            return true;
23892        }
23893    }
23894
23895    let ordered_list_candidate: String = snapshot
23896        .chars_for_range(range)
23897        .skip(num_of_whitespaces)
23898        .take(ORDERED_LIST_MAX_MARKER_LEN)
23899        .collect();
23900    for ordered_config in language.ordered_list() {
23901        let regex = match Regex::new(&ordered_config.pattern) {
23902            Ok(r) => r,
23903            Err(_) => continue,
23904        };
23905        if let Some(captures) = regex.captures(&ordered_list_candidate) {
23906            return captures.get(0).is_some();
23907        }
23908    }
23909
23910    false
23911}
23912
23913#[derive(Debug)]
23914enum NewlineConfig {
23915    /// Insert newline with optional additional indent and optional extra blank line
23916    Newline {
23917        additional_indent: IndentSize,
23918        extra_line_additional_indent: Option<IndentSize>,
23919        prevent_auto_indent: bool,
23920    },
23921    /// Clear the current line
23922    ClearCurrentLine,
23923    /// Unindent the current line and add continuation
23924    UnindentCurrentLine { continuation: Arc<str> },
23925}
23926
23927impl NewlineConfig {
23928    fn has_extra_line(&self) -> bool {
23929        matches!(
23930            self,
23931            Self::Newline {
23932                extra_line_additional_indent: Some(_),
23933                ..
23934            }
23935        )
23936    }
23937
23938    fn insert_extra_newline_brackets(
23939        buffer: &MultiBufferSnapshot,
23940        range: Range<MultiBufferOffset>,
23941        language: &language::LanguageScope,
23942    ) -> bool {
23943        let leading_whitespace_len = buffer
23944            .reversed_chars_at(range.start)
23945            .take_while(|c| c.is_whitespace() && *c != '\n')
23946            .map(|c| c.len_utf8())
23947            .sum::<usize>();
23948        let trailing_whitespace_len = buffer
23949            .chars_at(range.end)
23950            .take_while(|c| c.is_whitespace() && *c != '\n')
23951            .map(|c| c.len_utf8())
23952            .sum::<usize>();
23953        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23954
23955        language.brackets().any(|(pair, enabled)| {
23956            let pair_start = pair.start.trim_end();
23957            let pair_end = pair.end.trim_start();
23958
23959            enabled
23960                && pair.newline
23961                && buffer.contains_str_at(range.end, pair_end)
23962                && buffer.contains_str_at(
23963                    range.start.saturating_sub_usize(pair_start.len()),
23964                    pair_start,
23965                )
23966        })
23967    }
23968
23969    fn insert_extra_newline_tree_sitter(
23970        buffer: &MultiBufferSnapshot,
23971        range: Range<MultiBufferOffset>,
23972    ) -> bool {
23973        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23974            [(buffer, range, _)] => (*buffer, range.clone()),
23975            _ => return false,
23976        };
23977        let pair = {
23978            let mut result: Option<BracketMatch<usize>> = None;
23979
23980            for pair in buffer
23981                .all_bracket_ranges(range.start.0..range.end.0)
23982                .filter(move |pair| {
23983                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23984                })
23985            {
23986                let len = pair.close_range.end - pair.open_range.start;
23987
23988                if let Some(existing) = &result {
23989                    let existing_len = existing.close_range.end - existing.open_range.start;
23990                    if len > existing_len {
23991                        continue;
23992                    }
23993                }
23994
23995                result = Some(pair);
23996            }
23997
23998            result
23999        };
24000        let Some(pair) = pair else {
24001            return false;
24002        };
24003        pair.newline_only
24004            && buffer
24005                .chars_for_range(pair.open_range.end..range.start.0)
24006                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
24007                .all(|c| c.is_whitespace() && c != '\n')
24008    }
24009}
24010
24011fn update_uncommitted_diff_for_buffer(
24012    editor: Entity<Editor>,
24013    project: &Entity<Project>,
24014    buffers: impl IntoIterator<Item = Entity<Buffer>>,
24015    buffer: Entity<MultiBuffer>,
24016    cx: &mut App,
24017) -> Task<()> {
24018    let mut tasks = Vec::new();
24019    project.update(cx, |project, cx| {
24020        for buffer in buffers {
24021            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
24022                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
24023            }
24024        }
24025    });
24026    cx.spawn(async move |cx| {
24027        let diffs = future::join_all(tasks).await;
24028        if editor
24029            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
24030            .unwrap_or(false)
24031        {
24032            return;
24033        }
24034
24035        buffer
24036            .update(cx, |buffer, cx| {
24037                for diff in diffs.into_iter().flatten() {
24038                    buffer.add_diff(diff, cx);
24039                }
24040            })
24041            .ok();
24042    })
24043}
24044
24045fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
24046    let tab_size = tab_size.get() as usize;
24047    let mut width = offset;
24048
24049    for ch in text.chars() {
24050        width += if ch == '\t' {
24051            tab_size - (width % tab_size)
24052        } else {
24053            1
24054        };
24055    }
24056
24057    width - offset
24058}
24059
24060#[cfg(test)]
24061mod tests {
24062    use super::*;
24063
24064    #[test]
24065    fn test_string_size_with_expanded_tabs() {
24066        let nz = |val| NonZeroU32::new(val).unwrap();
24067        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24068        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24069        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24070        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24071        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24072        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24073        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24074        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24075    }
24076}
24077
24078/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24079struct WordBreakingTokenizer<'a> {
24080    input: &'a str,
24081}
24082
24083impl<'a> WordBreakingTokenizer<'a> {
24084    fn new(input: &'a str) -> Self {
24085        Self { input }
24086    }
24087}
24088
24089fn is_char_ideographic(ch: char) -> bool {
24090    use unicode_script::Script::*;
24091    use unicode_script::UnicodeScript;
24092    matches!(ch.script(), Han | Tangut | Yi)
24093}
24094
24095fn is_grapheme_ideographic(text: &str) -> bool {
24096    text.chars().any(is_char_ideographic)
24097}
24098
24099fn is_grapheme_whitespace(text: &str) -> bool {
24100    text.chars().any(|x| x.is_whitespace())
24101}
24102
24103fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24104    text.chars()
24105        .next()
24106        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24107}
24108
24109#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24110enum WordBreakToken<'a> {
24111    Word { token: &'a str, grapheme_len: usize },
24112    InlineWhitespace { token: &'a str, grapheme_len: usize },
24113    Newline,
24114}
24115
24116impl<'a> Iterator for WordBreakingTokenizer<'a> {
24117    /// Yields a span, the count of graphemes in the token, and whether it was
24118    /// whitespace. Note that it also breaks at word boundaries.
24119    type Item = WordBreakToken<'a>;
24120
24121    fn next(&mut self) -> Option<Self::Item> {
24122        use unicode_segmentation::UnicodeSegmentation;
24123        if self.input.is_empty() {
24124            return None;
24125        }
24126
24127        let mut iter = self.input.graphemes(true).peekable();
24128        let mut offset = 0;
24129        let mut grapheme_len = 0;
24130        if let Some(first_grapheme) = iter.next() {
24131            let is_newline = first_grapheme == "\n";
24132            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24133            offset += first_grapheme.len();
24134            grapheme_len += 1;
24135            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24136                if let Some(grapheme) = iter.peek().copied()
24137                    && should_stay_with_preceding_ideograph(grapheme)
24138                {
24139                    offset += grapheme.len();
24140                    grapheme_len += 1;
24141                }
24142            } else {
24143                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24144                let mut next_word_bound = words.peek().copied();
24145                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24146                    next_word_bound = words.next();
24147                }
24148                while let Some(grapheme) = iter.peek().copied() {
24149                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24150                        break;
24151                    };
24152                    if is_grapheme_whitespace(grapheme) != is_whitespace
24153                        || (grapheme == "\n") != is_newline
24154                    {
24155                        break;
24156                    };
24157                    offset += grapheme.len();
24158                    grapheme_len += 1;
24159                    iter.next();
24160                }
24161            }
24162            let token = &self.input[..offset];
24163            self.input = &self.input[offset..];
24164            if token == "\n" {
24165                Some(WordBreakToken::Newline)
24166            } else if is_whitespace {
24167                Some(WordBreakToken::InlineWhitespace {
24168                    token,
24169                    grapheme_len,
24170                })
24171            } else {
24172                Some(WordBreakToken::Word {
24173                    token,
24174                    grapheme_len,
24175                })
24176            }
24177        } else {
24178            None
24179        }
24180    }
24181}
24182
24183#[test]
24184fn test_word_breaking_tokenizer() {
24185    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24186        ("", &[]),
24187        ("  ", &[whitespace("  ", 2)]),
24188        ("Ʒ", &[word("Ʒ", 1)]),
24189        ("Ǽ", &[word("Ǽ", 1)]),
24190        ("", &[word("", 1)]),
24191        ("⋑⋑", &[word("⋑⋑", 2)]),
24192        (
24193            "原理,进而",
24194            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24195        ),
24196        (
24197            "hello world",
24198            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24199        ),
24200        (
24201            "hello, world",
24202            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24203        ),
24204        (
24205            "  hello world",
24206            &[
24207                whitespace("  ", 2),
24208                word("hello", 5),
24209                whitespace(" ", 1),
24210                word("world", 5),
24211            ],
24212        ),
24213        (
24214            "这是什么 \n 钢笔",
24215            &[
24216                word("", 1),
24217                word("", 1),
24218                word("", 1),
24219                word("", 1),
24220                whitespace(" ", 1),
24221                newline(),
24222                whitespace(" ", 1),
24223                word("", 1),
24224                word("", 1),
24225            ],
24226        ),
24227        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24228    ];
24229
24230    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24231        WordBreakToken::Word {
24232            token,
24233            grapheme_len,
24234        }
24235    }
24236
24237    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24238        WordBreakToken::InlineWhitespace {
24239            token,
24240            grapheme_len,
24241        }
24242    }
24243
24244    fn newline() -> WordBreakToken<'static> {
24245        WordBreakToken::Newline
24246    }
24247
24248    for (input, result) in tests {
24249        assert_eq!(
24250            WordBreakingTokenizer::new(input)
24251                .collect::<Vec<_>>()
24252                .as_slice(),
24253            *result,
24254        );
24255    }
24256}
24257
24258fn wrap_with_prefix(
24259    first_line_prefix: String,
24260    subsequent_lines_prefix: String,
24261    unwrapped_text: String,
24262    wrap_column: usize,
24263    tab_size: NonZeroU32,
24264    preserve_existing_whitespace: bool,
24265) -> String {
24266    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24267    let subsequent_lines_prefix_len =
24268        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24269    let mut wrapped_text = String::new();
24270    let mut current_line = first_line_prefix;
24271    let mut is_first_line = true;
24272
24273    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24274    let mut current_line_len = first_line_prefix_len;
24275    let mut in_whitespace = false;
24276    for token in tokenizer {
24277        let have_preceding_whitespace = in_whitespace;
24278        match token {
24279            WordBreakToken::Word {
24280                token,
24281                grapheme_len,
24282            } => {
24283                in_whitespace = false;
24284                let current_prefix_len = if is_first_line {
24285                    first_line_prefix_len
24286                } else {
24287                    subsequent_lines_prefix_len
24288                };
24289                if current_line_len + grapheme_len > wrap_column
24290                    && current_line_len != current_prefix_len
24291                {
24292                    wrapped_text.push_str(current_line.trim_end());
24293                    wrapped_text.push('\n');
24294                    is_first_line = false;
24295                    current_line = subsequent_lines_prefix.clone();
24296                    current_line_len = subsequent_lines_prefix_len;
24297                }
24298                current_line.push_str(token);
24299                current_line_len += grapheme_len;
24300            }
24301            WordBreakToken::InlineWhitespace {
24302                mut token,
24303                mut grapheme_len,
24304            } => {
24305                in_whitespace = true;
24306                if have_preceding_whitespace && !preserve_existing_whitespace {
24307                    continue;
24308                }
24309                if !preserve_existing_whitespace {
24310                    // Keep a single whitespace grapheme as-is
24311                    if let Some(first) =
24312                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24313                    {
24314                        token = first;
24315                    } else {
24316                        token = " ";
24317                    }
24318                    grapheme_len = 1;
24319                }
24320                let current_prefix_len = if is_first_line {
24321                    first_line_prefix_len
24322                } else {
24323                    subsequent_lines_prefix_len
24324                };
24325                if current_line_len + grapheme_len > wrap_column {
24326                    wrapped_text.push_str(current_line.trim_end());
24327                    wrapped_text.push('\n');
24328                    is_first_line = false;
24329                    current_line = subsequent_lines_prefix.clone();
24330                    current_line_len = subsequent_lines_prefix_len;
24331                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24332                    current_line.push_str(token);
24333                    current_line_len += grapheme_len;
24334                }
24335            }
24336            WordBreakToken::Newline => {
24337                in_whitespace = true;
24338                let current_prefix_len = if is_first_line {
24339                    first_line_prefix_len
24340                } else {
24341                    subsequent_lines_prefix_len
24342                };
24343                if preserve_existing_whitespace {
24344                    wrapped_text.push_str(current_line.trim_end());
24345                    wrapped_text.push('\n');
24346                    is_first_line = false;
24347                    current_line = subsequent_lines_prefix.clone();
24348                    current_line_len = subsequent_lines_prefix_len;
24349                } else if have_preceding_whitespace {
24350                    continue;
24351                } else if current_line_len + 1 > wrap_column
24352                    && current_line_len != current_prefix_len
24353                {
24354                    wrapped_text.push_str(current_line.trim_end());
24355                    wrapped_text.push('\n');
24356                    is_first_line = false;
24357                    current_line = subsequent_lines_prefix.clone();
24358                    current_line_len = subsequent_lines_prefix_len;
24359                } else if current_line_len != current_prefix_len {
24360                    current_line.push(' ');
24361                    current_line_len += 1;
24362                }
24363            }
24364        }
24365    }
24366
24367    if !current_line.is_empty() {
24368        wrapped_text.push_str(&current_line);
24369    }
24370    wrapped_text
24371}
24372
24373#[test]
24374fn test_wrap_with_prefix() {
24375    assert_eq!(
24376        wrap_with_prefix(
24377            "# ".to_string(),
24378            "# ".to_string(),
24379            "abcdefg".to_string(),
24380            4,
24381            NonZeroU32::new(4).unwrap(),
24382            false,
24383        ),
24384        "# abcdefg"
24385    );
24386    assert_eq!(
24387        wrap_with_prefix(
24388            "".to_string(),
24389            "".to_string(),
24390            "\thello world".to_string(),
24391            8,
24392            NonZeroU32::new(4).unwrap(),
24393            false,
24394        ),
24395        "hello\nworld"
24396    );
24397    assert_eq!(
24398        wrap_with_prefix(
24399            "// ".to_string(),
24400            "// ".to_string(),
24401            "xx \nyy zz aa bb cc".to_string(),
24402            12,
24403            NonZeroU32::new(4).unwrap(),
24404            false,
24405        ),
24406        "// xx yy zz\n// aa bb cc"
24407    );
24408    assert_eq!(
24409        wrap_with_prefix(
24410            String::new(),
24411            String::new(),
24412            "这是什么 \n 钢笔".to_string(),
24413            3,
24414            NonZeroU32::new(4).unwrap(),
24415            false,
24416        ),
24417        "这是什\n么 钢\n"
24418    );
24419    assert_eq!(
24420        wrap_with_prefix(
24421            String::new(),
24422            String::new(),
24423            format!("foo{}bar", '\u{2009}'), // thin space
24424            80,
24425            NonZeroU32::new(4).unwrap(),
24426            false,
24427        ),
24428        format!("foo{}bar", '\u{2009}')
24429    );
24430}
24431
24432pub trait CollaborationHub {
24433    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24434    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24435    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24436}
24437
24438impl CollaborationHub for Entity<Project> {
24439    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24440        self.read(cx).collaborators()
24441    }
24442
24443    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24444        self.read(cx).user_store().read(cx).participant_indices()
24445    }
24446
24447    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24448        let this = self.read(cx);
24449        let user_ids = this.collaborators().values().map(|c| c.user_id);
24450        this.user_store().read(cx).participant_names(user_ids, cx)
24451    }
24452}
24453
24454pub trait SemanticsProvider {
24455    fn hover(
24456        &self,
24457        buffer: &Entity<Buffer>,
24458        position: text::Anchor,
24459        cx: &mut App,
24460    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24461
24462    fn inline_values(
24463        &self,
24464        buffer_handle: Entity<Buffer>,
24465        range: Range<text::Anchor>,
24466        cx: &mut App,
24467    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24468
24469    fn applicable_inlay_chunks(
24470        &self,
24471        buffer: &Entity<Buffer>,
24472        ranges: &[Range<text::Anchor>],
24473        cx: &mut App,
24474    ) -> Vec<Range<BufferRow>>;
24475
24476    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24477
24478    fn inlay_hints(
24479        &self,
24480        invalidate: InvalidationStrategy,
24481        buffer: Entity<Buffer>,
24482        ranges: Vec<Range<text::Anchor>>,
24483        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24484        cx: &mut App,
24485    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24486
24487    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24488
24489    fn document_highlights(
24490        &self,
24491        buffer: &Entity<Buffer>,
24492        position: text::Anchor,
24493        cx: &mut App,
24494    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24495
24496    fn definitions(
24497        &self,
24498        buffer: &Entity<Buffer>,
24499        position: text::Anchor,
24500        kind: GotoDefinitionKind,
24501        cx: &mut App,
24502    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24503
24504    fn range_for_rename(
24505        &self,
24506        buffer: &Entity<Buffer>,
24507        position: text::Anchor,
24508        cx: &mut App,
24509    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24510
24511    fn perform_rename(
24512        &self,
24513        buffer: &Entity<Buffer>,
24514        position: text::Anchor,
24515        new_name: String,
24516        cx: &mut App,
24517    ) -> Option<Task<Result<ProjectTransaction>>>;
24518}
24519
24520pub trait CompletionProvider {
24521    fn completions(
24522        &self,
24523        excerpt_id: ExcerptId,
24524        buffer: &Entity<Buffer>,
24525        buffer_position: text::Anchor,
24526        trigger: CompletionContext,
24527        window: &mut Window,
24528        cx: &mut Context<Editor>,
24529    ) -> Task<Result<Vec<CompletionResponse>>>;
24530
24531    fn resolve_completions(
24532        &self,
24533        _buffer: Entity<Buffer>,
24534        _completion_indices: Vec<usize>,
24535        _completions: Rc<RefCell<Box<[Completion]>>>,
24536        _cx: &mut Context<Editor>,
24537    ) -> Task<Result<bool>> {
24538        Task::ready(Ok(false))
24539    }
24540
24541    fn apply_additional_edits_for_completion(
24542        &self,
24543        _buffer: Entity<Buffer>,
24544        _completions: Rc<RefCell<Box<[Completion]>>>,
24545        _completion_index: usize,
24546        _push_to_history: bool,
24547        _cx: &mut Context<Editor>,
24548    ) -> Task<Result<Option<language::Transaction>>> {
24549        Task::ready(Ok(None))
24550    }
24551
24552    fn is_completion_trigger(
24553        &self,
24554        buffer: &Entity<Buffer>,
24555        position: language::Anchor,
24556        text: &str,
24557        trigger_in_words: bool,
24558        cx: &mut Context<Editor>,
24559    ) -> bool;
24560
24561    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24562
24563    fn sort_completions(&self) -> bool {
24564        true
24565    }
24566
24567    fn filter_completions(&self) -> bool {
24568        true
24569    }
24570
24571    fn show_snippets(&self) -> bool {
24572        false
24573    }
24574}
24575
24576pub trait CodeActionProvider {
24577    fn id(&self) -> Arc<str>;
24578
24579    fn code_actions(
24580        &self,
24581        buffer: &Entity<Buffer>,
24582        range: Range<text::Anchor>,
24583        window: &mut Window,
24584        cx: &mut App,
24585    ) -> Task<Result<Vec<CodeAction>>>;
24586
24587    fn apply_code_action(
24588        &self,
24589        buffer_handle: Entity<Buffer>,
24590        action: CodeAction,
24591        excerpt_id: ExcerptId,
24592        push_to_history: bool,
24593        window: &mut Window,
24594        cx: &mut App,
24595    ) -> Task<Result<ProjectTransaction>>;
24596}
24597
24598impl CodeActionProvider for Entity<Project> {
24599    fn id(&self) -> Arc<str> {
24600        "project".into()
24601    }
24602
24603    fn code_actions(
24604        &self,
24605        buffer: &Entity<Buffer>,
24606        range: Range<text::Anchor>,
24607        _window: &mut Window,
24608        cx: &mut App,
24609    ) -> Task<Result<Vec<CodeAction>>> {
24610        self.update(cx, |project, cx| {
24611            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24612            let code_actions = project.code_actions(buffer, range, None, cx);
24613            cx.background_spawn(async move {
24614                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24615                Ok(code_lens_actions
24616                    .context("code lens fetch")?
24617                    .into_iter()
24618                    .flatten()
24619                    .chain(
24620                        code_actions
24621                            .context("code action fetch")?
24622                            .into_iter()
24623                            .flatten(),
24624                    )
24625                    .collect())
24626            })
24627        })
24628    }
24629
24630    fn apply_code_action(
24631        &self,
24632        buffer_handle: Entity<Buffer>,
24633        action: CodeAction,
24634        _excerpt_id: ExcerptId,
24635        push_to_history: bool,
24636        _window: &mut Window,
24637        cx: &mut App,
24638    ) -> Task<Result<ProjectTransaction>> {
24639        self.update(cx, |project, cx| {
24640            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24641        })
24642    }
24643}
24644
24645fn snippet_completions(
24646    project: &Project,
24647    buffer: &Entity<Buffer>,
24648    buffer_anchor: text::Anchor,
24649    classifier: CharClassifier,
24650    cx: &mut App,
24651) -> Task<Result<CompletionResponse>> {
24652    let languages = buffer.read(cx).languages_at(buffer_anchor);
24653    let snippet_store = project.snippets().read(cx);
24654
24655    let scopes: Vec<_> = languages
24656        .iter()
24657        .filter_map(|language| {
24658            let language_name = language.lsp_id();
24659            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24660
24661            if snippets.is_empty() {
24662                None
24663            } else {
24664                Some((language.default_scope(), snippets))
24665            }
24666        })
24667        .collect();
24668
24669    if scopes.is_empty() {
24670        return Task::ready(Ok(CompletionResponse {
24671            completions: vec![],
24672            display_options: CompletionDisplayOptions::default(),
24673            is_incomplete: false,
24674        }));
24675    }
24676
24677    let snapshot = buffer.read(cx).text_snapshot();
24678    let executor = cx.background_executor().clone();
24679
24680    cx.background_spawn(async move {
24681        let is_word_char = |c| classifier.is_word(c);
24682
24683        let mut is_incomplete = false;
24684        let mut completions: Vec<Completion> = Vec::new();
24685
24686        const MAX_PREFIX_LEN: usize = 128;
24687        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24688        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24689        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24690
24691        let max_buffer_window: String = snapshot
24692            .text_for_range(window_start..buffer_offset)
24693            .collect();
24694
24695        if max_buffer_window.is_empty() {
24696            return Ok(CompletionResponse {
24697                completions: vec![],
24698                display_options: CompletionDisplayOptions::default(),
24699                is_incomplete: true,
24700            });
24701        }
24702
24703        for (_scope, snippets) in scopes.into_iter() {
24704            // Sort snippets by word count to match longer snippet prefixes first.
24705            let mut sorted_snippet_candidates = snippets
24706                .iter()
24707                .enumerate()
24708                .flat_map(|(snippet_ix, snippet)| {
24709                    snippet
24710                        .prefix
24711                        .iter()
24712                        .enumerate()
24713                        .map(move |(prefix_ix, prefix)| {
24714                            let word_count =
24715                                snippet_candidate_suffixes(prefix, is_word_char).count();
24716                            ((snippet_ix, prefix_ix), prefix, word_count)
24717                        })
24718                })
24719                .collect_vec();
24720            sorted_snippet_candidates
24721                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24722
24723            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24724
24725            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24726                .take(
24727                    sorted_snippet_candidates
24728                        .first()
24729                        .map(|(_, _, word_count)| *word_count)
24730                        .unwrap_or_default(),
24731                )
24732                .collect_vec();
24733
24734            const MAX_RESULTS: usize = 100;
24735            // Each match also remembers how many characters from the buffer it consumed
24736            let mut matches: Vec<(StringMatch, usize)> = vec![];
24737
24738            let mut snippet_list_cutoff_index = 0;
24739            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24740                let word_count = buffer_index + 1;
24741                // Increase `snippet_list_cutoff_index` until we have all of the
24742                // snippets with sufficiently many words.
24743                while sorted_snippet_candidates
24744                    .get(snippet_list_cutoff_index)
24745                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24746                        *snippet_word_count >= word_count
24747                    })
24748                {
24749                    snippet_list_cutoff_index += 1;
24750                }
24751
24752                // Take only the candidates with at least `word_count` many words
24753                let snippet_candidates_at_word_len =
24754                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24755
24756                let candidates = snippet_candidates_at_word_len
24757                    .iter()
24758                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24759                    .enumerate() // index in `sorted_snippet_candidates`
24760                    // First char must match
24761                    .filter(|(_ix, prefix)| {
24762                        itertools::equal(
24763                            prefix
24764                                .chars()
24765                                .next()
24766                                .into_iter()
24767                                .flat_map(|c| c.to_lowercase()),
24768                            buffer_window
24769                                .chars()
24770                                .next()
24771                                .into_iter()
24772                                .flat_map(|c| c.to_lowercase()),
24773                        )
24774                    })
24775                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24776                    .collect::<Vec<StringMatchCandidate>>();
24777
24778                matches.extend(
24779                    fuzzy::match_strings(
24780                        &candidates,
24781                        &buffer_window,
24782                        buffer_window.chars().any(|c| c.is_uppercase()),
24783                        true,
24784                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24785                        &Default::default(),
24786                        executor.clone(),
24787                    )
24788                    .await
24789                    .into_iter()
24790                    .map(|string_match| (string_match, buffer_window.len())),
24791                );
24792
24793                if matches.len() >= MAX_RESULTS {
24794                    break;
24795                }
24796            }
24797
24798            let to_lsp = |point: &text::Anchor| {
24799                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24800                point_to_lsp(end)
24801            };
24802            let lsp_end = to_lsp(&buffer_anchor);
24803
24804            if matches.len() >= MAX_RESULTS {
24805                is_incomplete = true;
24806            }
24807
24808            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24809                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24810                    sorted_snippet_candidates[string_match.candidate_id];
24811                let snippet = &snippets[snippet_index];
24812                let start = buffer_offset - buffer_window_len;
24813                let start = snapshot.anchor_before(start);
24814                let range = start..buffer_anchor;
24815                let lsp_start = to_lsp(&start);
24816                let lsp_range = lsp::Range {
24817                    start: lsp_start,
24818                    end: lsp_end,
24819                };
24820                Completion {
24821                    replace_range: range,
24822                    new_text: snippet.body.clone(),
24823                    source: CompletionSource::Lsp {
24824                        insert_range: None,
24825                        server_id: LanguageServerId(usize::MAX),
24826                        resolved: true,
24827                        lsp_completion: Box::new(lsp::CompletionItem {
24828                            label: snippet.prefix.first().unwrap().clone(),
24829                            kind: Some(CompletionItemKind::SNIPPET),
24830                            label_details: snippet.description.as_ref().map(|description| {
24831                                lsp::CompletionItemLabelDetails {
24832                                    detail: Some(description.clone()),
24833                                    description: None,
24834                                }
24835                            }),
24836                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24837                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24838                                lsp::InsertReplaceEdit {
24839                                    new_text: snippet.body.clone(),
24840                                    insert: lsp_range,
24841                                    replace: lsp_range,
24842                                },
24843                            )),
24844                            filter_text: Some(snippet.body.clone()),
24845                            sort_text: Some(char::MAX.to_string()),
24846                            ..lsp::CompletionItem::default()
24847                        }),
24848                        lsp_defaults: None,
24849                    },
24850                    label: CodeLabel {
24851                        text: matching_prefix.clone(),
24852                        runs: Vec::new(),
24853                        filter_range: 0..matching_prefix.len(),
24854                    },
24855                    icon_path: None,
24856                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24857                        single_line: snippet.name.clone().into(),
24858                        plain_text: snippet
24859                            .description
24860                            .clone()
24861                            .map(|description| description.into()),
24862                    }),
24863                    insert_text_mode: None,
24864                    confirm: None,
24865                    match_start: Some(start),
24866                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24867                }
24868            }));
24869        }
24870
24871        Ok(CompletionResponse {
24872            completions,
24873            display_options: CompletionDisplayOptions::default(),
24874            is_incomplete,
24875        })
24876    })
24877}
24878
24879impl CompletionProvider for Entity<Project> {
24880    fn completions(
24881        &self,
24882        _excerpt_id: ExcerptId,
24883        buffer: &Entity<Buffer>,
24884        buffer_position: text::Anchor,
24885        options: CompletionContext,
24886        _window: &mut Window,
24887        cx: &mut Context<Editor>,
24888    ) -> Task<Result<Vec<CompletionResponse>>> {
24889        self.update(cx, |project, cx| {
24890            let task = project.completions(buffer, buffer_position, options, cx);
24891            cx.background_spawn(task)
24892        })
24893    }
24894
24895    fn resolve_completions(
24896        &self,
24897        buffer: Entity<Buffer>,
24898        completion_indices: Vec<usize>,
24899        completions: Rc<RefCell<Box<[Completion]>>>,
24900        cx: &mut Context<Editor>,
24901    ) -> Task<Result<bool>> {
24902        self.update(cx, |project, cx| {
24903            project.lsp_store().update(cx, |lsp_store, cx| {
24904                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24905            })
24906        })
24907    }
24908
24909    fn apply_additional_edits_for_completion(
24910        &self,
24911        buffer: Entity<Buffer>,
24912        completions: Rc<RefCell<Box<[Completion]>>>,
24913        completion_index: usize,
24914        push_to_history: bool,
24915        cx: &mut Context<Editor>,
24916    ) -> Task<Result<Option<language::Transaction>>> {
24917        self.update(cx, |project, cx| {
24918            project.lsp_store().update(cx, |lsp_store, cx| {
24919                lsp_store.apply_additional_edits_for_completion(
24920                    buffer,
24921                    completions,
24922                    completion_index,
24923                    push_to_history,
24924                    cx,
24925                )
24926            })
24927        })
24928    }
24929
24930    fn is_completion_trigger(
24931        &self,
24932        buffer: &Entity<Buffer>,
24933        position: language::Anchor,
24934        text: &str,
24935        trigger_in_words: bool,
24936        cx: &mut Context<Editor>,
24937    ) -> bool {
24938        let mut chars = text.chars();
24939        let char = if let Some(char) = chars.next() {
24940            char
24941        } else {
24942            return false;
24943        };
24944        if chars.next().is_some() {
24945            return false;
24946        }
24947
24948        let buffer = buffer.read(cx);
24949        let snapshot = buffer.snapshot();
24950        let classifier = snapshot
24951            .char_classifier_at(position)
24952            .scope_context(Some(CharScopeContext::Completion));
24953        if trigger_in_words && classifier.is_word(char) {
24954            return true;
24955        }
24956
24957        buffer.completion_triggers().contains(text)
24958    }
24959
24960    fn show_snippets(&self) -> bool {
24961        true
24962    }
24963}
24964
24965impl SemanticsProvider for Entity<Project> {
24966    fn hover(
24967        &self,
24968        buffer: &Entity<Buffer>,
24969        position: text::Anchor,
24970        cx: &mut App,
24971    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24972        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24973    }
24974
24975    fn document_highlights(
24976        &self,
24977        buffer: &Entity<Buffer>,
24978        position: text::Anchor,
24979        cx: &mut App,
24980    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24981        Some(self.update(cx, |project, cx| {
24982            project.document_highlights(buffer, position, cx)
24983        }))
24984    }
24985
24986    fn definitions(
24987        &self,
24988        buffer: &Entity<Buffer>,
24989        position: text::Anchor,
24990        kind: GotoDefinitionKind,
24991        cx: &mut App,
24992    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24993        Some(self.update(cx, |project, cx| match kind {
24994            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24995            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24996            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24997            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24998        }))
24999    }
25000
25001    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
25002        self.update(cx, |project, cx| {
25003            if project
25004                .active_debug_session(cx)
25005                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
25006            {
25007                return true;
25008            }
25009
25010            buffer.update(cx, |buffer, cx| {
25011                project.any_language_server_supports_inlay_hints(buffer, cx)
25012            })
25013        })
25014    }
25015
25016    fn inline_values(
25017        &self,
25018        buffer_handle: Entity<Buffer>,
25019        range: Range<text::Anchor>,
25020        cx: &mut App,
25021    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
25022        self.update(cx, |project, cx| {
25023            let (session, active_stack_frame) = project.active_debug_session(cx)?;
25024
25025            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
25026        })
25027    }
25028
25029    fn applicable_inlay_chunks(
25030        &self,
25031        buffer: &Entity<Buffer>,
25032        ranges: &[Range<text::Anchor>],
25033        cx: &mut App,
25034    ) -> Vec<Range<BufferRow>> {
25035        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25036            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
25037        })
25038    }
25039
25040    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
25041        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
25042            lsp_store.invalidate_inlay_hints(for_buffers)
25043        });
25044    }
25045
25046    fn inlay_hints(
25047        &self,
25048        invalidate: InvalidationStrategy,
25049        buffer: Entity<Buffer>,
25050        ranges: Vec<Range<text::Anchor>>,
25051        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25052        cx: &mut App,
25053    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25054        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25055            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25056        }))
25057    }
25058
25059    fn range_for_rename(
25060        &self,
25061        buffer: &Entity<Buffer>,
25062        position: text::Anchor,
25063        cx: &mut App,
25064    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25065        Some(self.update(cx, |project, cx| {
25066            let buffer = buffer.clone();
25067            let task = project.prepare_rename(buffer.clone(), position, cx);
25068            cx.spawn(async move |_, cx| {
25069                Ok(match task.await? {
25070                    PrepareRenameResponse::Success(range) => Some(range),
25071                    PrepareRenameResponse::InvalidPosition => None,
25072                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25073                        // Fallback on using TreeSitter info to determine identifier range
25074                        buffer.read_with(cx, |buffer, _| {
25075                            let snapshot = buffer.snapshot();
25076                            let (range, kind) = snapshot.surrounding_word(position, None);
25077                            if kind != Some(CharKind::Word) {
25078                                return None;
25079                            }
25080                            Some(
25081                                snapshot.anchor_before(range.start)
25082                                    ..snapshot.anchor_after(range.end),
25083                            )
25084                        })?
25085                    }
25086                })
25087            })
25088        }))
25089    }
25090
25091    fn perform_rename(
25092        &self,
25093        buffer: &Entity<Buffer>,
25094        position: text::Anchor,
25095        new_name: String,
25096        cx: &mut App,
25097    ) -> Option<Task<Result<ProjectTransaction>>> {
25098        Some(self.update(cx, |project, cx| {
25099            project.perform_rename(buffer.clone(), position, new_name, cx)
25100        }))
25101    }
25102}
25103
25104fn consume_contiguous_rows(
25105    contiguous_row_selections: &mut Vec<Selection<Point>>,
25106    selection: &Selection<Point>,
25107    display_map: &DisplaySnapshot,
25108    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25109) -> (MultiBufferRow, MultiBufferRow) {
25110    contiguous_row_selections.push(selection.clone());
25111    let start_row = starting_row(selection, display_map);
25112    let mut end_row = ending_row(selection, display_map);
25113
25114    while let Some(next_selection) = selections.peek() {
25115        if next_selection.start.row <= end_row.0 {
25116            end_row = ending_row(next_selection, display_map);
25117            contiguous_row_selections.push(selections.next().unwrap().clone());
25118        } else {
25119            break;
25120        }
25121    }
25122    (start_row, end_row)
25123}
25124
25125fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25126    if selection.start.column > 0 {
25127        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25128    } else {
25129        MultiBufferRow(selection.start.row)
25130    }
25131}
25132
25133fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25134    if next_selection.end.column > 0 || next_selection.is_empty() {
25135        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25136    } else {
25137        MultiBufferRow(next_selection.end.row)
25138    }
25139}
25140
25141impl EditorSnapshot {
25142    pub fn remote_selections_in_range<'a>(
25143        &'a self,
25144        range: &'a Range<Anchor>,
25145        collaboration_hub: &dyn CollaborationHub,
25146        cx: &'a App,
25147    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25148        let participant_names = collaboration_hub.user_names(cx);
25149        let participant_indices = collaboration_hub.user_participant_indices(cx);
25150        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25151        let collaborators_by_replica_id = collaborators_by_peer_id
25152            .values()
25153            .map(|collaborator| (collaborator.replica_id, collaborator))
25154            .collect::<HashMap<_, _>>();
25155        self.buffer_snapshot()
25156            .selections_in_range(range, false)
25157            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25158                if replica_id == ReplicaId::AGENT {
25159                    Some(RemoteSelection {
25160                        replica_id,
25161                        selection,
25162                        cursor_shape,
25163                        line_mode,
25164                        collaborator_id: CollaboratorId::Agent,
25165                        user_name: Some("Agent".into()),
25166                        color: cx.theme().players().agent(),
25167                    })
25168                } else {
25169                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25170                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25171                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25172                    Some(RemoteSelection {
25173                        replica_id,
25174                        selection,
25175                        cursor_shape,
25176                        line_mode,
25177                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25178                        user_name,
25179                        color: if let Some(index) = participant_index {
25180                            cx.theme().players().color_for_participant(index.0)
25181                        } else {
25182                            cx.theme().players().absent()
25183                        },
25184                    })
25185                }
25186            })
25187    }
25188
25189    pub fn hunks_for_ranges(
25190        &self,
25191        ranges: impl IntoIterator<Item = Range<Point>>,
25192    ) -> Vec<MultiBufferDiffHunk> {
25193        let mut hunks = Vec::new();
25194        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25195            HashMap::default();
25196        for query_range in ranges {
25197            let query_rows =
25198                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25199            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25200                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25201            ) {
25202                // Include deleted hunks that are adjacent to the query range, because
25203                // otherwise they would be missed.
25204                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25205                if hunk.status().is_deleted() {
25206                    intersects_range |= hunk.row_range.start == query_rows.end;
25207                    intersects_range |= hunk.row_range.end == query_rows.start;
25208                }
25209                if intersects_range {
25210                    if !processed_buffer_rows
25211                        .entry(hunk.buffer_id)
25212                        .or_default()
25213                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25214                    {
25215                        continue;
25216                    }
25217                    hunks.push(hunk);
25218                }
25219            }
25220        }
25221
25222        hunks
25223    }
25224
25225    fn display_diff_hunks_for_rows<'a>(
25226        &'a self,
25227        display_rows: Range<DisplayRow>,
25228        folded_buffers: &'a HashSet<BufferId>,
25229    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25230        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25231        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25232
25233        self.buffer_snapshot()
25234            .diff_hunks_in_range(buffer_start..buffer_end)
25235            .filter_map(|hunk| {
25236                if folded_buffers.contains(&hunk.buffer_id) {
25237                    return None;
25238                }
25239
25240                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25241                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25242
25243                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25244                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25245
25246                let display_hunk = if hunk_display_start.column() != 0 {
25247                    DisplayDiffHunk::Folded {
25248                        display_row: hunk_display_start.row(),
25249                    }
25250                } else {
25251                    let mut end_row = hunk_display_end.row();
25252                    if hunk_display_end.column() > 0 {
25253                        end_row.0 += 1;
25254                    }
25255                    let is_created_file = hunk.is_created_file();
25256
25257                    DisplayDiffHunk::Unfolded {
25258                        status: hunk.status(),
25259                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25260                            ..hunk.diff_base_byte_range.end.0,
25261                        word_diffs: hunk.word_diffs,
25262                        display_row_range: hunk_display_start.row()..end_row,
25263                        multi_buffer_range: Anchor::range_in_buffer(
25264                            hunk.excerpt_id,
25265                            hunk.buffer_range,
25266                        ),
25267                        is_created_file,
25268                    }
25269                };
25270
25271                Some(display_hunk)
25272            })
25273    }
25274
25275    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25276        self.display_snapshot
25277            .buffer_snapshot()
25278            .language_at(position)
25279    }
25280
25281    pub fn is_focused(&self) -> bool {
25282        self.is_focused
25283    }
25284
25285    pub fn placeholder_text(&self) -> Option<String> {
25286        self.placeholder_display_snapshot
25287            .as_ref()
25288            .map(|display_map| display_map.text())
25289    }
25290
25291    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25292        self.scroll_anchor.scroll_position(&self.display_snapshot)
25293    }
25294
25295    pub fn gutter_dimensions(
25296        &self,
25297        font_id: FontId,
25298        font_size: Pixels,
25299        style: &EditorStyle,
25300        window: &mut Window,
25301        cx: &App,
25302    ) -> GutterDimensions {
25303        if self.show_gutter
25304            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25305            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25306        {
25307            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25308                matches!(
25309                    ProjectSettings::get_global(cx).git.git_gutter,
25310                    GitGutterSetting::TrackedFiles
25311                )
25312            });
25313            let gutter_settings = EditorSettings::get_global(cx).gutter;
25314            let show_line_numbers = self
25315                .show_line_numbers
25316                .unwrap_or(gutter_settings.line_numbers);
25317            let line_gutter_width = if show_line_numbers {
25318                // Avoid flicker-like gutter resizes when the line number gains another digit by
25319                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25320                let min_width_for_number_on_gutter =
25321                    ch_advance * gutter_settings.min_line_number_digits as f32;
25322                self.max_line_number_width(style, window)
25323                    .max(min_width_for_number_on_gutter)
25324            } else {
25325                0.0.into()
25326            };
25327
25328            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25329            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25330
25331            let git_blame_entries_width =
25332                self.git_blame_gutter_max_author_length
25333                    .map(|max_author_length| {
25334                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25335                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25336
25337                        /// The number of characters to dedicate to gaps and margins.
25338                        const SPACING_WIDTH: usize = 4;
25339
25340                        let max_char_count = max_author_length.min(renderer.max_author_length())
25341                            + ::git::SHORT_SHA_LENGTH
25342                            + MAX_RELATIVE_TIMESTAMP.len()
25343                            + SPACING_WIDTH;
25344
25345                        ch_advance * max_char_count
25346                    });
25347
25348            let is_singleton = self.buffer_snapshot().is_singleton();
25349
25350            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25351            left_padding += if !is_singleton {
25352                ch_width * 4.0
25353            } else if show_runnables || show_breakpoints {
25354                ch_width * 3.0
25355            } else if show_git_gutter && show_line_numbers {
25356                ch_width * 2.0
25357            } else if show_git_gutter || show_line_numbers {
25358                ch_width
25359            } else {
25360                px(0.)
25361            };
25362
25363            let shows_folds = is_singleton && gutter_settings.folds;
25364
25365            let right_padding = if shows_folds && show_line_numbers {
25366                ch_width * 4.0
25367            } else if shows_folds || (!is_singleton && show_line_numbers) {
25368                ch_width * 3.0
25369            } else if show_line_numbers {
25370                ch_width
25371            } else {
25372                px(0.)
25373            };
25374
25375            GutterDimensions {
25376                left_padding,
25377                right_padding,
25378                width: line_gutter_width + left_padding + right_padding,
25379                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25380                git_blame_entries_width,
25381            }
25382        } else if self.offset_content {
25383            GutterDimensions::default_with_margin(font_id, font_size, cx)
25384        } else {
25385            GutterDimensions::default()
25386        }
25387    }
25388
25389    pub fn render_crease_toggle(
25390        &self,
25391        buffer_row: MultiBufferRow,
25392        row_contains_cursor: bool,
25393        editor: Entity<Editor>,
25394        window: &mut Window,
25395        cx: &mut App,
25396    ) -> Option<AnyElement> {
25397        let folded = self.is_line_folded(buffer_row);
25398        let mut is_foldable = false;
25399
25400        if let Some(crease) = self
25401            .crease_snapshot
25402            .query_row(buffer_row, self.buffer_snapshot())
25403        {
25404            is_foldable = true;
25405            match crease {
25406                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25407                    if let Some(render_toggle) = render_toggle {
25408                        let toggle_callback =
25409                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25410                                if folded {
25411                                    editor.update(cx, |editor, cx| {
25412                                        editor.fold_at(buffer_row, window, cx)
25413                                    });
25414                                } else {
25415                                    editor.update(cx, |editor, cx| {
25416                                        editor.unfold_at(buffer_row, window, cx)
25417                                    });
25418                                }
25419                            });
25420                        return Some((render_toggle)(
25421                            buffer_row,
25422                            folded,
25423                            toggle_callback,
25424                            window,
25425                            cx,
25426                        ));
25427                    }
25428                }
25429            }
25430        }
25431
25432        is_foldable |= self.starts_indent(buffer_row);
25433
25434        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25435            Some(
25436                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25437                    .toggle_state(folded)
25438                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25439                        if folded {
25440                            this.unfold_at(buffer_row, window, cx);
25441                        } else {
25442                            this.fold_at(buffer_row, window, cx);
25443                        }
25444                    }))
25445                    .into_any_element(),
25446            )
25447        } else {
25448            None
25449        }
25450    }
25451
25452    pub fn render_crease_trailer(
25453        &self,
25454        buffer_row: MultiBufferRow,
25455        window: &mut Window,
25456        cx: &mut App,
25457    ) -> Option<AnyElement> {
25458        let folded = self.is_line_folded(buffer_row);
25459        if let Crease::Inline { render_trailer, .. } = self
25460            .crease_snapshot
25461            .query_row(buffer_row, self.buffer_snapshot())?
25462        {
25463            let render_trailer = render_trailer.as_ref()?;
25464            Some(render_trailer(buffer_row, folded, window, cx))
25465        } else {
25466            None
25467        }
25468    }
25469
25470    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25471        let digit_count = self.widest_line_number().ilog10() + 1;
25472        column_pixels(style, digit_count as usize, window)
25473    }
25474
25475    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25476    ///
25477    /// This is positive if `base` is before `line`.
25478    fn relative_line_delta(
25479        &self,
25480        base: DisplayRow,
25481        line: DisplayRow,
25482        consider_wrapped_lines: bool,
25483    ) -> i64 {
25484        let point = DisplayPoint::new(line, 0).to_point(self);
25485        self.relative_line_delta_to_point(base, point, consider_wrapped_lines)
25486    }
25487
25488    /// Returns the line delta from `base` to `point` in the multibuffer.
25489    ///
25490    /// This is positive if `base` is before `point`.
25491    pub fn relative_line_delta_to_point(
25492        &self,
25493        base: DisplayRow,
25494        point: Point,
25495        consider_wrapped_lines: bool,
25496    ) -> i64 {
25497        let base_point = DisplayPoint::new(base, 0).to_point(self);
25498        if consider_wrapped_lines {
25499            let wrap_snapshot = self.wrap_snapshot();
25500            let base_wrap_row = wrap_snapshot.make_wrap_point(base_point, Bias::Left).row();
25501            let wrap_row = wrap_snapshot.make_wrap_point(point, Bias::Left).row();
25502            wrap_row.0 as i64 - base_wrap_row.0 as i64
25503        } else {
25504            point.row as i64 - base_point.row as i64
25505        }
25506    }
25507
25508    /// Returns the unsigned relative line number to display for each row in `rows`.
25509    ///
25510    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25511    pub fn calculate_relative_line_numbers(
25512        &self,
25513        rows: &Range<DisplayRow>,
25514        relative_to: DisplayRow,
25515        count_wrapped_lines: bool,
25516    ) -> HashMap<DisplayRow, u32> {
25517        let initial_offset = self.relative_line_delta(relative_to, rows.start, count_wrapped_lines);
25518
25519        self.row_infos(rows.start)
25520            .take(rows.len())
25521            .enumerate()
25522            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25523            .filter(|(_row, row_info)| {
25524                row_info.buffer_row.is_some()
25525                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25526            })
25527            .enumerate()
25528            .flat_map(|(i, (row, _row_info))| {
25529                (row != relative_to)
25530                    .then_some((row, (initial_offset + i as i64).unsigned_abs() as u32))
25531            })
25532            .collect()
25533    }
25534}
25535
25536pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25537    let font_size = style.text.font_size.to_pixels(window.rem_size());
25538    let layout = window.text_system().shape_line(
25539        SharedString::from(" ".repeat(column)),
25540        font_size,
25541        &[TextRun {
25542            len: column,
25543            font: style.text.font(),
25544            color: Hsla::default(),
25545            ..Default::default()
25546        }],
25547        None,
25548    );
25549
25550    layout.width
25551}
25552
25553impl Deref for EditorSnapshot {
25554    type Target = DisplaySnapshot;
25555
25556    fn deref(&self) -> &Self::Target {
25557        &self.display_snapshot
25558    }
25559}
25560
25561#[derive(Clone, Debug, PartialEq, Eq)]
25562pub enum EditorEvent {
25563    InputIgnored {
25564        text: Arc<str>,
25565    },
25566    InputHandled {
25567        utf16_range_to_replace: Option<Range<isize>>,
25568        text: Arc<str>,
25569    },
25570    ExcerptsAdded {
25571        buffer: Entity<Buffer>,
25572        predecessor: ExcerptId,
25573        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25574    },
25575    ExcerptsRemoved {
25576        ids: Vec<ExcerptId>,
25577        removed_buffer_ids: Vec<BufferId>,
25578    },
25579    BufferFoldToggled {
25580        ids: Vec<ExcerptId>,
25581        folded: bool,
25582    },
25583    ExcerptsEdited {
25584        ids: Vec<ExcerptId>,
25585    },
25586    ExcerptsExpanded {
25587        ids: Vec<ExcerptId>,
25588    },
25589    ExpandExcerptsRequested {
25590        excerpt_ids: Vec<ExcerptId>,
25591        lines: u32,
25592        direction: ExpandExcerptDirection,
25593    },
25594    BufferEdited,
25595    Edited {
25596        transaction_id: clock::Lamport,
25597    },
25598    Reparsed(BufferId),
25599    Focused,
25600    FocusedIn,
25601    Blurred,
25602    DirtyChanged,
25603    Saved,
25604    TitleChanged,
25605    SelectionsChanged {
25606        local: bool,
25607    },
25608    ScrollPositionChanged {
25609        local: bool,
25610        autoscroll: bool,
25611    },
25612    TransactionUndone {
25613        transaction_id: clock::Lamport,
25614    },
25615    TransactionBegun {
25616        transaction_id: clock::Lamport,
25617    },
25618    CursorShapeChanged,
25619    BreadcrumbsChanged,
25620    PushedToNavHistory {
25621        anchor: Anchor,
25622        is_deactivate: bool,
25623    },
25624}
25625
25626impl EventEmitter<EditorEvent> for Editor {}
25627
25628impl Focusable for Editor {
25629    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25630        self.focus_handle.clone()
25631    }
25632}
25633
25634impl Render for Editor {
25635    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25636        EditorElement::new(&cx.entity(), self.create_style(cx))
25637    }
25638}
25639
25640impl EntityInputHandler for Editor {
25641    fn text_for_range(
25642        &mut self,
25643        range_utf16: Range<usize>,
25644        adjusted_range: &mut Option<Range<usize>>,
25645        _: &mut Window,
25646        cx: &mut Context<Self>,
25647    ) -> Option<String> {
25648        let snapshot = self.buffer.read(cx).read(cx);
25649        let start = snapshot.clip_offset_utf16(
25650            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25651            Bias::Left,
25652        );
25653        let end = snapshot.clip_offset_utf16(
25654            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25655            Bias::Right,
25656        );
25657        if (start.0.0..end.0.0) != range_utf16 {
25658            adjusted_range.replace(start.0.0..end.0.0);
25659        }
25660        Some(snapshot.text_for_range(start..end).collect())
25661    }
25662
25663    fn selected_text_range(
25664        &mut self,
25665        ignore_disabled_input: bool,
25666        _: &mut Window,
25667        cx: &mut Context<Self>,
25668    ) -> Option<UTF16Selection> {
25669        // Prevent the IME menu from appearing when holding down an alphabetic key
25670        // while input is disabled.
25671        if !ignore_disabled_input && !self.input_enabled {
25672            return None;
25673        }
25674
25675        let selection = self
25676            .selections
25677            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25678        let range = selection.range();
25679
25680        Some(UTF16Selection {
25681            range: range.start.0.0..range.end.0.0,
25682            reversed: selection.reversed,
25683        })
25684    }
25685
25686    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25687        let snapshot = self.buffer.read(cx).read(cx);
25688        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25689        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25690    }
25691
25692    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25693        self.clear_highlights::<InputComposition>(cx);
25694        self.ime_transaction.take();
25695    }
25696
25697    fn replace_text_in_range(
25698        &mut self,
25699        range_utf16: Option<Range<usize>>,
25700        text: &str,
25701        window: &mut Window,
25702        cx: &mut Context<Self>,
25703    ) {
25704        if !self.input_enabled {
25705            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25706            return;
25707        }
25708
25709        self.transact(window, cx, |this, window, cx| {
25710            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25711                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25712                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25713                Some(this.selection_replacement_ranges(range_utf16, cx))
25714            } else {
25715                this.marked_text_ranges(cx)
25716            };
25717
25718            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25719                let newest_selection_id = this.selections.newest_anchor().id;
25720                this.selections
25721                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25722                    .iter()
25723                    .zip(ranges_to_replace.iter())
25724                    .find_map(|(selection, range)| {
25725                        if selection.id == newest_selection_id {
25726                            Some(
25727                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25728                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25729                            )
25730                        } else {
25731                            None
25732                        }
25733                    })
25734            });
25735
25736            cx.emit(EditorEvent::InputHandled {
25737                utf16_range_to_replace: range_to_replace,
25738                text: text.into(),
25739            });
25740
25741            if let Some(new_selected_ranges) = new_selected_ranges {
25742                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25743                    selections.select_ranges(new_selected_ranges)
25744                });
25745                this.backspace(&Default::default(), window, cx);
25746            }
25747
25748            this.handle_input(text, window, cx);
25749        });
25750
25751        if let Some(transaction) = self.ime_transaction {
25752            self.buffer.update(cx, |buffer, cx| {
25753                buffer.group_until_transaction(transaction, cx);
25754            });
25755        }
25756
25757        self.unmark_text(window, cx);
25758    }
25759
25760    fn replace_and_mark_text_in_range(
25761        &mut self,
25762        range_utf16: Option<Range<usize>>,
25763        text: &str,
25764        new_selected_range_utf16: Option<Range<usize>>,
25765        window: &mut Window,
25766        cx: &mut Context<Self>,
25767    ) {
25768        if !self.input_enabled {
25769            return;
25770        }
25771
25772        let transaction = self.transact(window, cx, |this, window, cx| {
25773            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25774                let snapshot = this.buffer.read(cx).read(cx);
25775                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25776                    for marked_range in &mut marked_ranges {
25777                        marked_range.end = marked_range.start + relative_range_utf16.end;
25778                        marked_range.start += relative_range_utf16.start;
25779                        marked_range.start =
25780                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25781                        marked_range.end =
25782                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25783                    }
25784                }
25785                Some(marked_ranges)
25786            } else if let Some(range_utf16) = range_utf16 {
25787                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25788                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25789                Some(this.selection_replacement_ranges(range_utf16, cx))
25790            } else {
25791                None
25792            };
25793
25794            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25795                let newest_selection_id = this.selections.newest_anchor().id;
25796                this.selections
25797                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25798                    .iter()
25799                    .zip(ranges_to_replace.iter())
25800                    .find_map(|(selection, range)| {
25801                        if selection.id == newest_selection_id {
25802                            Some(
25803                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25804                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25805                            )
25806                        } else {
25807                            None
25808                        }
25809                    })
25810            });
25811
25812            cx.emit(EditorEvent::InputHandled {
25813                utf16_range_to_replace: range_to_replace,
25814                text: text.into(),
25815            });
25816
25817            if let Some(ranges) = ranges_to_replace {
25818                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25819                    s.select_ranges(ranges)
25820                });
25821            }
25822
25823            let marked_ranges = {
25824                let snapshot = this.buffer.read(cx).read(cx);
25825                this.selections
25826                    .disjoint_anchors_arc()
25827                    .iter()
25828                    .map(|selection| {
25829                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25830                    })
25831                    .collect::<Vec<_>>()
25832            };
25833
25834            if text.is_empty() {
25835                this.unmark_text(window, cx);
25836            } else {
25837                this.highlight_text::<InputComposition>(
25838                    marked_ranges.clone(),
25839                    HighlightStyle {
25840                        underline: Some(UnderlineStyle {
25841                            thickness: px(1.),
25842                            color: None,
25843                            wavy: false,
25844                        }),
25845                        ..Default::default()
25846                    },
25847                    cx,
25848                );
25849            }
25850
25851            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25852            let use_autoclose = this.use_autoclose;
25853            let use_auto_surround = this.use_auto_surround;
25854            this.set_use_autoclose(false);
25855            this.set_use_auto_surround(false);
25856            this.handle_input(text, window, cx);
25857            this.set_use_autoclose(use_autoclose);
25858            this.set_use_auto_surround(use_auto_surround);
25859
25860            if let Some(new_selected_range) = new_selected_range_utf16 {
25861                let snapshot = this.buffer.read(cx).read(cx);
25862                let new_selected_ranges = marked_ranges
25863                    .into_iter()
25864                    .map(|marked_range| {
25865                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25866                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25867                            insertion_start.0 + new_selected_range.start,
25868                        ));
25869                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25870                            insertion_start.0 + new_selected_range.end,
25871                        ));
25872                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25873                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25874                    })
25875                    .collect::<Vec<_>>();
25876
25877                drop(snapshot);
25878                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25879                    selections.select_ranges(new_selected_ranges)
25880                });
25881            }
25882        });
25883
25884        self.ime_transaction = self.ime_transaction.or(transaction);
25885        if let Some(transaction) = self.ime_transaction {
25886            self.buffer.update(cx, |buffer, cx| {
25887                buffer.group_until_transaction(transaction, cx);
25888            });
25889        }
25890
25891        if self.text_highlights::<InputComposition>(cx).is_none() {
25892            self.ime_transaction.take();
25893        }
25894    }
25895
25896    fn bounds_for_range(
25897        &mut self,
25898        range_utf16: Range<usize>,
25899        element_bounds: gpui::Bounds<Pixels>,
25900        window: &mut Window,
25901        cx: &mut Context<Self>,
25902    ) -> Option<gpui::Bounds<Pixels>> {
25903        let text_layout_details = self.text_layout_details(window);
25904        let CharacterDimensions {
25905            em_width,
25906            em_advance,
25907            line_height,
25908        } = self.character_dimensions(window);
25909
25910        let snapshot = self.snapshot(window, cx);
25911        let scroll_position = snapshot.scroll_position();
25912        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25913
25914        let start =
25915            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25916        let x = Pixels::from(
25917            ScrollOffset::from(
25918                snapshot.x_for_display_point(start, &text_layout_details)
25919                    + self.gutter_dimensions.full_width(),
25920            ) - scroll_left,
25921        );
25922        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25923
25924        Some(Bounds {
25925            origin: element_bounds.origin + point(x, y),
25926            size: size(em_width, line_height),
25927        })
25928    }
25929
25930    fn character_index_for_point(
25931        &mut self,
25932        point: gpui::Point<Pixels>,
25933        _window: &mut Window,
25934        _cx: &mut Context<Self>,
25935    ) -> Option<usize> {
25936        let position_map = self.last_position_map.as_ref()?;
25937        if !position_map.text_hitbox.contains(&point) {
25938            return None;
25939        }
25940        let display_point = position_map.point_for_position(point).previous_valid;
25941        let anchor = position_map
25942            .snapshot
25943            .display_point_to_anchor(display_point, Bias::Left);
25944        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25945        Some(utf16_offset.0.0)
25946    }
25947
25948    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25949        self.input_enabled
25950    }
25951}
25952
25953trait SelectionExt {
25954    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25955    fn spanned_rows(
25956        &self,
25957        include_end_if_at_line_start: bool,
25958        map: &DisplaySnapshot,
25959    ) -> Range<MultiBufferRow>;
25960}
25961
25962impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25963    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25964        let start = self
25965            .start
25966            .to_point(map.buffer_snapshot())
25967            .to_display_point(map);
25968        let end = self
25969            .end
25970            .to_point(map.buffer_snapshot())
25971            .to_display_point(map);
25972        if self.reversed {
25973            end..start
25974        } else {
25975            start..end
25976        }
25977    }
25978
25979    fn spanned_rows(
25980        &self,
25981        include_end_if_at_line_start: bool,
25982        map: &DisplaySnapshot,
25983    ) -> Range<MultiBufferRow> {
25984        let start = self.start.to_point(map.buffer_snapshot());
25985        let mut end = self.end.to_point(map.buffer_snapshot());
25986        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25987            end.row -= 1;
25988        }
25989
25990        let buffer_start = map.prev_line_boundary(start).0;
25991        let buffer_end = map.next_line_boundary(end).0;
25992        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25993    }
25994}
25995
25996impl<T: InvalidationRegion> InvalidationStack<T> {
25997    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25998    where
25999        S: Clone + ToOffset,
26000    {
26001        while let Some(region) = self.last() {
26002            let all_selections_inside_invalidation_ranges =
26003                if selections.len() == region.ranges().len() {
26004                    selections
26005                        .iter()
26006                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
26007                        .all(|(selection, invalidation_range)| {
26008                            let head = selection.head().to_offset(buffer);
26009                            invalidation_range.start <= head && invalidation_range.end >= head
26010                        })
26011                } else {
26012                    false
26013                };
26014
26015            if all_selections_inside_invalidation_ranges {
26016                break;
26017            } else {
26018                self.pop();
26019            }
26020        }
26021    }
26022}
26023
26024impl<T> Default for InvalidationStack<T> {
26025    fn default() -> Self {
26026        Self(Default::default())
26027    }
26028}
26029
26030impl<T> Deref for InvalidationStack<T> {
26031    type Target = Vec<T>;
26032
26033    fn deref(&self) -> &Self::Target {
26034        &self.0
26035    }
26036}
26037
26038impl<T> DerefMut for InvalidationStack<T> {
26039    fn deref_mut(&mut self) -> &mut Self::Target {
26040        &mut self.0
26041    }
26042}
26043
26044impl InvalidationRegion for SnippetState {
26045    fn ranges(&self) -> &[Range<Anchor>] {
26046        &self.ranges[self.active_index]
26047    }
26048}
26049
26050fn edit_prediction_edit_text(
26051    current_snapshot: &BufferSnapshot,
26052    edits: &[(Range<Anchor>, impl AsRef<str>)],
26053    edit_preview: &EditPreview,
26054    include_deletions: bool,
26055    cx: &App,
26056) -> HighlightedText {
26057    let edits = edits
26058        .iter()
26059        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26060        .collect::<Vec<_>>();
26061
26062    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26063}
26064
26065fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26066    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26067    // Just show the raw edit text with basic styling
26068    let mut text = String::new();
26069    let mut highlights = Vec::new();
26070
26071    let insertion_highlight_style = HighlightStyle {
26072        color: Some(cx.theme().colors().text),
26073        ..Default::default()
26074    };
26075
26076    for (_, edit_text) in edits {
26077        let start_offset = text.len();
26078        text.push_str(edit_text);
26079        let end_offset = text.len();
26080
26081        if start_offset < end_offset {
26082            highlights.push((start_offset..end_offset, insertion_highlight_style));
26083        }
26084    }
26085
26086    HighlightedText {
26087        text: text.into(),
26088        highlights,
26089    }
26090}
26091
26092pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26093    match severity {
26094        lsp::DiagnosticSeverity::ERROR => colors.error,
26095        lsp::DiagnosticSeverity::WARNING => colors.warning,
26096        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26097        lsp::DiagnosticSeverity::HINT => colors.info,
26098        _ => colors.ignored,
26099    }
26100}
26101
26102pub fn styled_runs_for_code_label<'a>(
26103    label: &'a CodeLabel,
26104    syntax_theme: &'a theme::SyntaxTheme,
26105    local_player: &'a theme::PlayerColor,
26106) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26107    let fade_out = HighlightStyle {
26108        fade_out: Some(0.35),
26109        ..Default::default()
26110    };
26111
26112    let mut prev_end = label.filter_range.end;
26113    label
26114        .runs
26115        .iter()
26116        .enumerate()
26117        .flat_map(move |(ix, (range, highlight_id))| {
26118            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26119                HighlightStyle {
26120                    color: Some(local_player.cursor),
26121                    ..Default::default()
26122                }
26123            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26124                HighlightStyle {
26125                    background_color: Some(local_player.selection),
26126                    ..Default::default()
26127                }
26128            } else if let Some(style) = highlight_id.style(syntax_theme) {
26129                style
26130            } else {
26131                return Default::default();
26132            };
26133            let muted_style = style.highlight(fade_out);
26134
26135            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26136            if range.start >= label.filter_range.end {
26137                if range.start > prev_end {
26138                    runs.push((prev_end..range.start, fade_out));
26139                }
26140                runs.push((range.clone(), muted_style));
26141            } else if range.end <= label.filter_range.end {
26142                runs.push((range.clone(), style));
26143            } else {
26144                runs.push((range.start..label.filter_range.end, style));
26145                runs.push((label.filter_range.end..range.end, muted_style));
26146            }
26147            prev_end = cmp::max(prev_end, range.end);
26148
26149            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26150                runs.push((prev_end..label.text.len(), fade_out));
26151            }
26152
26153            runs
26154        })
26155}
26156
26157pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26158    let mut prev_index = 0;
26159    let mut prev_codepoint: Option<char> = None;
26160    text.char_indices()
26161        .chain([(text.len(), '\0')])
26162        .filter_map(move |(index, codepoint)| {
26163            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26164            let is_boundary = index == text.len()
26165                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26166                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26167            if is_boundary {
26168                let chunk = &text[prev_index..index];
26169                prev_index = index;
26170                Some(chunk)
26171            } else {
26172                None
26173            }
26174        })
26175}
26176
26177/// Given a string of text immediately before the cursor, iterates over possible
26178/// strings a snippet could match to. More precisely: returns an iterator over
26179/// suffixes of `text` created by splitting at word boundaries (before & after
26180/// every non-word character).
26181///
26182/// Shorter suffixes are returned first.
26183pub(crate) fn snippet_candidate_suffixes(
26184    text: &str,
26185    is_word_char: impl Fn(char) -> bool,
26186) -> impl std::iter::Iterator<Item = &str> {
26187    let mut prev_index = text.len();
26188    let mut prev_codepoint = None;
26189    text.char_indices()
26190        .rev()
26191        .chain([(0, '\0')])
26192        .filter_map(move |(index, codepoint)| {
26193            let prev_index = std::mem::replace(&mut prev_index, index);
26194            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26195            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26196                None
26197            } else {
26198                let chunk = &text[prev_index..]; // go to end of string
26199                Some(chunk)
26200            }
26201        })
26202}
26203
26204pub trait RangeToAnchorExt: Sized {
26205    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26206
26207    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26208        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26209        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26210    }
26211}
26212
26213impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26214    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26215        let start_offset = self.start.to_offset(snapshot);
26216        let end_offset = self.end.to_offset(snapshot);
26217        if start_offset == end_offset {
26218            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26219        } else {
26220            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26221        }
26222    }
26223}
26224
26225pub trait RowExt {
26226    fn as_f64(&self) -> f64;
26227
26228    fn next_row(&self) -> Self;
26229
26230    fn previous_row(&self) -> Self;
26231
26232    fn minus(&self, other: Self) -> u32;
26233}
26234
26235impl RowExt for DisplayRow {
26236    fn as_f64(&self) -> f64 {
26237        self.0 as _
26238    }
26239
26240    fn next_row(&self) -> Self {
26241        Self(self.0 + 1)
26242    }
26243
26244    fn previous_row(&self) -> Self {
26245        Self(self.0.saturating_sub(1))
26246    }
26247
26248    fn minus(&self, other: Self) -> u32 {
26249        self.0 - other.0
26250    }
26251}
26252
26253impl RowExt for MultiBufferRow {
26254    fn as_f64(&self) -> f64 {
26255        self.0 as _
26256    }
26257
26258    fn next_row(&self) -> Self {
26259        Self(self.0 + 1)
26260    }
26261
26262    fn previous_row(&self) -> Self {
26263        Self(self.0.saturating_sub(1))
26264    }
26265
26266    fn minus(&self, other: Self) -> u32 {
26267        self.0 - other.0
26268    }
26269}
26270
26271trait RowRangeExt {
26272    type Row;
26273
26274    fn len(&self) -> usize;
26275
26276    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26277}
26278
26279impl RowRangeExt for Range<MultiBufferRow> {
26280    type Row = MultiBufferRow;
26281
26282    fn len(&self) -> usize {
26283        (self.end.0 - self.start.0) as usize
26284    }
26285
26286    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26287        (self.start.0..self.end.0).map(MultiBufferRow)
26288    }
26289}
26290
26291impl RowRangeExt for Range<DisplayRow> {
26292    type Row = DisplayRow;
26293
26294    fn len(&self) -> usize {
26295        (self.end.0 - self.start.0) as usize
26296    }
26297
26298    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26299        (self.start.0..self.end.0).map(DisplayRow)
26300    }
26301}
26302
26303/// If select range has more than one line, we
26304/// just point the cursor to range.start.
26305fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26306    if range.start.row == range.end.row {
26307        range
26308    } else {
26309        range.start..range.start
26310    }
26311}
26312pub struct KillRing(ClipboardItem);
26313impl Global for KillRing {}
26314
26315const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26316
26317enum BreakpointPromptEditAction {
26318    Log,
26319    Condition,
26320    HitCondition,
26321}
26322
26323struct BreakpointPromptEditor {
26324    pub(crate) prompt: Entity<Editor>,
26325    editor: WeakEntity<Editor>,
26326    breakpoint_anchor: Anchor,
26327    breakpoint: Breakpoint,
26328    edit_action: BreakpointPromptEditAction,
26329    block_ids: HashSet<CustomBlockId>,
26330    editor_margins: Arc<Mutex<EditorMargins>>,
26331    _subscriptions: Vec<Subscription>,
26332}
26333
26334impl BreakpointPromptEditor {
26335    const MAX_LINES: u8 = 4;
26336
26337    fn new(
26338        editor: WeakEntity<Editor>,
26339        breakpoint_anchor: Anchor,
26340        breakpoint: Breakpoint,
26341        edit_action: BreakpointPromptEditAction,
26342        window: &mut Window,
26343        cx: &mut Context<Self>,
26344    ) -> Self {
26345        let base_text = match edit_action {
26346            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26347            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26348            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26349        }
26350        .map(|msg| msg.to_string())
26351        .unwrap_or_default();
26352
26353        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26354        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26355
26356        let prompt = cx.new(|cx| {
26357            let mut prompt = Editor::new(
26358                EditorMode::AutoHeight {
26359                    min_lines: 1,
26360                    max_lines: Some(Self::MAX_LINES as usize),
26361                },
26362                buffer,
26363                None,
26364                window,
26365                cx,
26366            );
26367            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26368            prompt.set_show_cursor_when_unfocused(false, cx);
26369            prompt.set_placeholder_text(
26370                match edit_action {
26371                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26372                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26373                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26374                },
26375                window,
26376                cx,
26377            );
26378
26379            prompt
26380        });
26381
26382        Self {
26383            prompt,
26384            editor,
26385            breakpoint_anchor,
26386            breakpoint,
26387            edit_action,
26388            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26389            block_ids: Default::default(),
26390            _subscriptions: vec![],
26391        }
26392    }
26393
26394    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26395        self.block_ids.extend(block_ids)
26396    }
26397
26398    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26399        if let Some(editor) = self.editor.upgrade() {
26400            let message = self
26401                .prompt
26402                .read(cx)
26403                .buffer
26404                .read(cx)
26405                .as_singleton()
26406                .expect("A multi buffer in breakpoint prompt isn't possible")
26407                .read(cx)
26408                .as_rope()
26409                .to_string();
26410
26411            editor.update(cx, |editor, cx| {
26412                editor.edit_breakpoint_at_anchor(
26413                    self.breakpoint_anchor,
26414                    self.breakpoint.clone(),
26415                    match self.edit_action {
26416                        BreakpointPromptEditAction::Log => {
26417                            BreakpointEditAction::EditLogMessage(message.into())
26418                        }
26419                        BreakpointPromptEditAction::Condition => {
26420                            BreakpointEditAction::EditCondition(message.into())
26421                        }
26422                        BreakpointPromptEditAction::HitCondition => {
26423                            BreakpointEditAction::EditHitCondition(message.into())
26424                        }
26425                    },
26426                    cx,
26427                );
26428
26429                editor.remove_blocks(self.block_ids.clone(), None, cx);
26430                cx.focus_self(window);
26431            });
26432        }
26433    }
26434
26435    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26436        self.editor
26437            .update(cx, |editor, cx| {
26438                editor.remove_blocks(self.block_ids.clone(), None, cx);
26439                window.focus(&editor.focus_handle, cx);
26440            })
26441            .log_err();
26442    }
26443
26444    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26445        let settings = ThemeSettings::get_global(cx);
26446        let text_style = TextStyle {
26447            color: if self.prompt.read(cx).read_only(cx) {
26448                cx.theme().colors().text_disabled
26449            } else {
26450                cx.theme().colors().text
26451            },
26452            font_family: settings.buffer_font.family.clone(),
26453            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26454            font_size: settings.buffer_font_size(cx).into(),
26455            font_weight: settings.buffer_font.weight,
26456            line_height: relative(settings.buffer_line_height.value()),
26457            ..Default::default()
26458        };
26459        EditorElement::new(
26460            &self.prompt,
26461            EditorStyle {
26462                background: cx.theme().colors().editor_background,
26463                local_player: cx.theme().players().local(),
26464                text: text_style,
26465                ..Default::default()
26466            },
26467        )
26468    }
26469}
26470
26471impl Render for BreakpointPromptEditor {
26472    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26473        let editor_margins = *self.editor_margins.lock();
26474        let gutter_dimensions = editor_margins.gutter;
26475        h_flex()
26476            .key_context("Editor")
26477            .bg(cx.theme().colors().editor_background)
26478            .border_y_1()
26479            .border_color(cx.theme().status().info_border)
26480            .size_full()
26481            .py(window.line_height() / 2.5)
26482            .on_action(cx.listener(Self::confirm))
26483            .on_action(cx.listener(Self::cancel))
26484            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26485            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26486    }
26487}
26488
26489impl Focusable for BreakpointPromptEditor {
26490    fn focus_handle(&self, cx: &App) -> FocusHandle {
26491        self.prompt.focus_handle(cx)
26492    }
26493}
26494
26495fn all_edits_insertions_or_deletions(
26496    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26497    snapshot: &MultiBufferSnapshot,
26498) -> bool {
26499    let mut all_insertions = true;
26500    let mut all_deletions = true;
26501
26502    for (range, new_text) in edits.iter() {
26503        let range_is_empty = range.to_offset(snapshot).is_empty();
26504        let text_is_empty = new_text.is_empty();
26505
26506        if range_is_empty != text_is_empty {
26507            if range_is_empty {
26508                all_deletions = false;
26509            } else {
26510                all_insertions = false;
26511            }
26512        } else {
26513            return false;
26514        }
26515
26516        if !all_insertions && !all_deletions {
26517            return false;
26518        }
26519    }
26520    all_insertions || all_deletions
26521}
26522
26523struct MissingEditPredictionKeybindingTooltip;
26524
26525impl Render for MissingEditPredictionKeybindingTooltip {
26526    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26527        ui::tooltip_container(cx, |container, cx| {
26528            container
26529                .flex_shrink_0()
26530                .max_w_80()
26531                .min_h(rems_from_px(124.))
26532                .justify_between()
26533                .child(
26534                    v_flex()
26535                        .flex_1()
26536                        .text_ui_sm(cx)
26537                        .child(Label::new("Conflict with Accept Keybinding"))
26538                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26539                )
26540                .child(
26541                    h_flex()
26542                        .pb_1()
26543                        .gap_1()
26544                        .items_end()
26545                        .w_full()
26546                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26547                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26548                        }))
26549                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26550                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26551                        })),
26552                )
26553        })
26554    }
26555}
26556
26557#[derive(Debug, Clone, Copy, PartialEq)]
26558pub struct LineHighlight {
26559    pub background: Background,
26560    pub border: Option<gpui::Hsla>,
26561    pub include_gutter: bool,
26562    pub type_id: Option<TypeId>,
26563}
26564
26565struct LineManipulationResult {
26566    pub new_text: String,
26567    pub line_count_before: usize,
26568    pub line_count_after: usize,
26569}
26570
26571fn render_diff_hunk_controls(
26572    row: u32,
26573    status: &DiffHunkStatus,
26574    hunk_range: Range<Anchor>,
26575    is_created_file: bool,
26576    line_height: Pixels,
26577    editor: &Entity<Editor>,
26578    _window: &mut Window,
26579    cx: &mut App,
26580) -> AnyElement {
26581    h_flex()
26582        .h(line_height)
26583        .mr_1()
26584        .gap_1()
26585        .px_0p5()
26586        .pb_1()
26587        .border_x_1()
26588        .border_b_1()
26589        .border_color(cx.theme().colors().border_variant)
26590        .rounded_b_lg()
26591        .bg(cx.theme().colors().editor_background)
26592        .gap_1()
26593        .block_mouse_except_scroll()
26594        .shadow_md()
26595        .child(if status.has_secondary_hunk() {
26596            Button::new(("stage", row as u64), "Stage")
26597                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26598                .tooltip({
26599                    let focus_handle = editor.focus_handle(cx);
26600                    move |_window, cx| {
26601                        Tooltip::for_action_in(
26602                            "Stage Hunk",
26603                            &::git::ToggleStaged,
26604                            &focus_handle,
26605                            cx,
26606                        )
26607                    }
26608                })
26609                .on_click({
26610                    let editor = editor.clone();
26611                    move |_event, _window, cx| {
26612                        editor.update(cx, |editor, cx| {
26613                            editor.stage_or_unstage_diff_hunks(
26614                                true,
26615                                vec![hunk_range.start..hunk_range.start],
26616                                cx,
26617                            );
26618                        });
26619                    }
26620                })
26621        } else {
26622            Button::new(("unstage", row as u64), "Unstage")
26623                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26624                .tooltip({
26625                    let focus_handle = editor.focus_handle(cx);
26626                    move |_window, cx| {
26627                        Tooltip::for_action_in(
26628                            "Unstage Hunk",
26629                            &::git::ToggleStaged,
26630                            &focus_handle,
26631                            cx,
26632                        )
26633                    }
26634                })
26635                .on_click({
26636                    let editor = editor.clone();
26637                    move |_event, _window, cx| {
26638                        editor.update(cx, |editor, cx| {
26639                            editor.stage_or_unstage_diff_hunks(
26640                                false,
26641                                vec![hunk_range.start..hunk_range.start],
26642                                cx,
26643                            );
26644                        });
26645                    }
26646                })
26647        })
26648        .child(
26649            Button::new(("restore", row as u64), "Restore")
26650                .tooltip({
26651                    let focus_handle = editor.focus_handle(cx);
26652                    move |_window, cx| {
26653                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26654                    }
26655                })
26656                .on_click({
26657                    let editor = editor.clone();
26658                    move |_event, window, cx| {
26659                        editor.update(cx, |editor, cx| {
26660                            let snapshot = editor.snapshot(window, cx);
26661                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26662                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26663                        });
26664                    }
26665                })
26666                .disabled(is_created_file),
26667        )
26668        .when(
26669            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26670            |el| {
26671                el.child(
26672                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26673                        .shape(IconButtonShape::Square)
26674                        .icon_size(IconSize::Small)
26675                        // .disabled(!has_multiple_hunks)
26676                        .tooltip({
26677                            let focus_handle = editor.focus_handle(cx);
26678                            move |_window, cx| {
26679                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26680                            }
26681                        })
26682                        .on_click({
26683                            let editor = editor.clone();
26684                            move |_event, window, cx| {
26685                                editor.update(cx, |editor, cx| {
26686                                    let snapshot = editor.snapshot(window, cx);
26687                                    let position =
26688                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26689                                    editor.go_to_hunk_before_or_after_position(
26690                                        &snapshot,
26691                                        position,
26692                                        Direction::Next,
26693                                        window,
26694                                        cx,
26695                                    );
26696                                    editor.expand_selected_diff_hunks(cx);
26697                                });
26698                            }
26699                        }),
26700                )
26701                .child(
26702                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26703                        .shape(IconButtonShape::Square)
26704                        .icon_size(IconSize::Small)
26705                        // .disabled(!has_multiple_hunks)
26706                        .tooltip({
26707                            let focus_handle = editor.focus_handle(cx);
26708                            move |_window, cx| {
26709                                Tooltip::for_action_in(
26710                                    "Previous Hunk",
26711                                    &GoToPreviousHunk,
26712                                    &focus_handle,
26713                                    cx,
26714                                )
26715                            }
26716                        })
26717                        .on_click({
26718                            let editor = editor.clone();
26719                            move |_event, window, cx| {
26720                                editor.update(cx, |editor, cx| {
26721                                    let snapshot = editor.snapshot(window, cx);
26722                                    let point =
26723                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26724                                    editor.go_to_hunk_before_or_after_position(
26725                                        &snapshot,
26726                                        point,
26727                                        Direction::Prev,
26728                                        window,
26729                                        cx,
26730                                    );
26731                                    editor.expand_selected_diff_hunks(cx);
26732                                });
26733                            }
26734                        }),
26735                )
26736            },
26737        )
26738        .into_any_element()
26739}
26740
26741pub fn multibuffer_context_lines(cx: &App) -> u32 {
26742    EditorSettings::try_get(cx)
26743        .map(|settings| settings.excerpt_context_lines)
26744        .unwrap_or(2)
26745        .min(32)
26746}