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.update(cx, |buffer, _| {
 5516                        buffer.push_transaction(transaction, Instant::now());
 5517                        buffer.finalize_last_transaction();
 5518                    });
 5519                }
 5520                editor.update(cx, |editor, cx| {
 5521                    editor.refresh_document_highlights(cx);
 5522                })?;
 5523            }
 5524            Ok(())
 5525        }))
 5526    }
 5527
 5528    pub fn show_word_completions(
 5529        &mut self,
 5530        _: &ShowWordCompletions,
 5531        window: &mut Window,
 5532        cx: &mut Context<Self>,
 5533    ) {
 5534        self.open_or_update_completions_menu(
 5535            Some(CompletionsMenuSource::Words {
 5536                ignore_threshold: true,
 5537            }),
 5538            None,
 5539            false,
 5540            window,
 5541            cx,
 5542        );
 5543    }
 5544
 5545    pub fn show_completions(
 5546        &mut self,
 5547        _: &ShowCompletions,
 5548        window: &mut Window,
 5549        cx: &mut Context<Self>,
 5550    ) {
 5551        self.open_or_update_completions_menu(None, None, false, window, cx);
 5552    }
 5553
 5554    fn open_or_update_completions_menu(
 5555        &mut self,
 5556        requested_source: Option<CompletionsMenuSource>,
 5557        trigger: Option<String>,
 5558        trigger_in_words: bool,
 5559        window: &mut Window,
 5560        cx: &mut Context<Self>,
 5561    ) {
 5562        if self.pending_rename.is_some() {
 5563            return;
 5564        }
 5565
 5566        let completions_source = self
 5567            .context_menu
 5568            .borrow()
 5569            .as_ref()
 5570            .and_then(|menu| match menu {
 5571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5572                CodeContextMenu::CodeActions(_) => None,
 5573            });
 5574
 5575        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5576
 5577        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5578        // inserted and selected. To handle that case, the start of the selection is used so that
 5579        // the menu starts with all choices.
 5580        let position = self
 5581            .selections
 5582            .newest_anchor()
 5583            .start
 5584            .bias_right(&multibuffer_snapshot);
 5585        if position.diff_base_anchor.is_some() {
 5586            return;
 5587        }
 5588        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5589        let Some(buffer) = buffer_position
 5590            .text_anchor
 5591            .buffer_id
 5592            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5593        else {
 5594            return;
 5595        };
 5596        let buffer_snapshot = buffer.read(cx).snapshot();
 5597
 5598        let menu_is_open = matches!(
 5599            self.context_menu.borrow().as_ref(),
 5600            Some(CodeContextMenu::Completions(_))
 5601        );
 5602
 5603        let language = buffer_snapshot
 5604            .language_at(buffer_position.text_anchor)
 5605            .map(|language| language.name());
 5606
 5607        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5608        let completion_settings = language_settings.completions.clone();
 5609
 5610        let show_completions_on_input = self
 5611            .show_completions_on_input_override
 5612            .unwrap_or(language_settings.show_completions_on_input);
 5613        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5614            return;
 5615        }
 5616
 5617        let query: Option<Arc<String>> =
 5618            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5619                .map(|query| query.into());
 5620
 5621        drop(multibuffer_snapshot);
 5622
 5623        // Hide the current completions menu when query is empty. Without this, cached
 5624        // completions from before the trigger char may be reused (#32774).
 5625        if query.is_none() && menu_is_open {
 5626            self.hide_context_menu(window, cx);
 5627        }
 5628
 5629        let mut ignore_word_threshold = false;
 5630        let provider = match requested_source {
 5631            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5632            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5633                ignore_word_threshold = ignore_threshold;
 5634                None
 5635            }
 5636            Some(CompletionsMenuSource::SnippetChoices)
 5637            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5638                log::error!("bug: SnippetChoices requested_source is not handled");
 5639                None
 5640            }
 5641        };
 5642
 5643        let sort_completions = provider
 5644            .as_ref()
 5645            .is_some_and(|provider| provider.sort_completions());
 5646
 5647        let filter_completions = provider
 5648            .as_ref()
 5649            .is_none_or(|provider| provider.filter_completions());
 5650
 5651        let was_snippets_only = matches!(
 5652            completions_source,
 5653            Some(CompletionsMenuSource::SnippetsOnly)
 5654        );
 5655
 5656        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5657            if filter_completions {
 5658                menu.filter(
 5659                    query.clone().unwrap_or_default(),
 5660                    buffer_position.text_anchor,
 5661                    &buffer,
 5662                    provider.clone(),
 5663                    window,
 5664                    cx,
 5665                );
 5666            }
 5667            // When `is_incomplete` is false, no need to re-query completions when the current query
 5668            // is a suffix of the initial query.
 5669            let was_complete = !menu.is_incomplete;
 5670            if was_complete && !was_snippets_only {
 5671                // If the new query is a suffix of the old query (typing more characters) and
 5672                // the previous result was complete, the existing completions can be filtered.
 5673                //
 5674                // Note that snippet completions are always complete.
 5675                let query_matches = match (&menu.initial_query, &query) {
 5676                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5677                    (None, _) => true,
 5678                    _ => false,
 5679                };
 5680                if query_matches {
 5681                    let position_matches = if menu.initial_position == position {
 5682                        true
 5683                    } else {
 5684                        let snapshot = self.buffer.read(cx).read(cx);
 5685                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5686                    };
 5687                    if position_matches {
 5688                        return;
 5689                    }
 5690                }
 5691            }
 5692        };
 5693
 5694        let Anchor {
 5695            excerpt_id: buffer_excerpt_id,
 5696            text_anchor: buffer_position,
 5697            ..
 5698        } = buffer_position;
 5699
 5700        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5701            buffer_snapshot.surrounding_word(buffer_position, None)
 5702        {
 5703            let word_to_exclude = buffer_snapshot
 5704                .text_for_range(word_range.clone())
 5705                .collect::<String>();
 5706            (
 5707                buffer_snapshot.anchor_before(word_range.start)
 5708                    ..buffer_snapshot.anchor_after(buffer_position),
 5709                Some(word_to_exclude),
 5710            )
 5711        } else {
 5712            (buffer_position..buffer_position, None)
 5713        };
 5714
 5715        let show_completion_documentation = buffer_snapshot
 5716            .settings_at(buffer_position, cx)
 5717            .show_completion_documentation;
 5718
 5719        // The document can be large, so stay in reasonable bounds when searching for words,
 5720        // otherwise completion pop-up might be slow to appear.
 5721        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5722        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5723        let min_word_search = buffer_snapshot.clip_point(
 5724            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5725            Bias::Left,
 5726        );
 5727        let max_word_search = buffer_snapshot.clip_point(
 5728            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5729            Bias::Right,
 5730        );
 5731        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5732            ..buffer_snapshot.point_to_offset(max_word_search);
 5733
 5734        let skip_digits = query
 5735            .as_ref()
 5736            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5737
 5738        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5739            trigger.as_ref().is_none_or(|trigger| {
 5740                provider.is_completion_trigger(
 5741                    &buffer,
 5742                    position.text_anchor,
 5743                    trigger,
 5744                    trigger_in_words,
 5745                    cx,
 5746                )
 5747            })
 5748        });
 5749
 5750        let provider_responses = if let Some(provider) = &provider
 5751            && load_provider_completions
 5752        {
 5753            let trigger_character =
 5754                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5755            let completion_context = CompletionContext {
 5756                trigger_kind: match &trigger_character {
 5757                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5758                    None => CompletionTriggerKind::INVOKED,
 5759                },
 5760                trigger_character,
 5761            };
 5762
 5763            provider.completions(
 5764                buffer_excerpt_id,
 5765                &buffer,
 5766                buffer_position,
 5767                completion_context,
 5768                window,
 5769                cx,
 5770            )
 5771        } else {
 5772            Task::ready(Ok(Vec::new()))
 5773        };
 5774
 5775        let load_word_completions = if !self.word_completions_enabled {
 5776            false
 5777        } else if requested_source
 5778            == Some(CompletionsMenuSource::Words {
 5779                ignore_threshold: true,
 5780            })
 5781        {
 5782            true
 5783        } else {
 5784            load_provider_completions
 5785                && completion_settings.words != WordsCompletionMode::Disabled
 5786                && (ignore_word_threshold || {
 5787                    let words_min_length = completion_settings.words_min_length;
 5788                    // check whether word has at least `words_min_length` characters
 5789                    let query_chars = query.iter().flat_map(|q| q.chars());
 5790                    query_chars.take(words_min_length).count() == words_min_length
 5791                })
 5792        };
 5793
 5794        let mut words = if load_word_completions {
 5795            cx.background_spawn({
 5796                let buffer_snapshot = buffer_snapshot.clone();
 5797                async move {
 5798                    buffer_snapshot.words_in_range(WordsQuery {
 5799                        fuzzy_contents: None,
 5800                        range: word_search_range,
 5801                        skip_digits,
 5802                    })
 5803                }
 5804            })
 5805        } else {
 5806            Task::ready(BTreeMap::default())
 5807        };
 5808
 5809        let snippets = if let Some(provider) = &provider
 5810            && provider.show_snippets()
 5811            && let Some(project) = self.project()
 5812        {
 5813            let char_classifier = buffer_snapshot
 5814                .char_classifier_at(buffer_position)
 5815                .scope_context(Some(CharScopeContext::Completion));
 5816            project.update(cx, |project, cx| {
 5817                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5818            })
 5819        } else {
 5820            Task::ready(Ok(CompletionResponse {
 5821                completions: Vec::new(),
 5822                display_options: Default::default(),
 5823                is_incomplete: false,
 5824            }))
 5825        };
 5826
 5827        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5828
 5829        let id = post_inc(&mut self.next_completion_id);
 5830        let task = cx.spawn_in(window, async move |editor, cx| {
 5831            let Ok(()) = editor.update(cx, |this, _| {
 5832                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5833            }) else {
 5834                return;
 5835            };
 5836
 5837            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5838            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5839            let mut completions = Vec::new();
 5840            let mut is_incomplete = false;
 5841            let mut display_options: Option<CompletionDisplayOptions> = None;
 5842            if let Some(provider_responses) = provider_responses.await.log_err()
 5843                && !provider_responses.is_empty()
 5844            {
 5845                for response in provider_responses {
 5846                    completions.extend(response.completions);
 5847                    is_incomplete = is_incomplete || response.is_incomplete;
 5848                    match display_options.as_mut() {
 5849                        None => {
 5850                            display_options = Some(response.display_options);
 5851                        }
 5852                        Some(options) => options.merge(&response.display_options),
 5853                    }
 5854                }
 5855                if completion_settings.words == WordsCompletionMode::Fallback {
 5856                    words = Task::ready(BTreeMap::default());
 5857                }
 5858            }
 5859            let display_options = display_options.unwrap_or_default();
 5860
 5861            let mut words = words.await;
 5862            if let Some(word_to_exclude) = &word_to_exclude {
 5863                words.remove(word_to_exclude);
 5864            }
 5865            for lsp_completion in &completions {
 5866                words.remove(&lsp_completion.new_text);
 5867            }
 5868            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5869                replace_range: word_replace_range.clone(),
 5870                new_text: word.clone(),
 5871                label: CodeLabel::plain(word, None),
 5872                match_start: None,
 5873                snippet_deduplication_key: None,
 5874                icon_path: None,
 5875                documentation: None,
 5876                source: CompletionSource::BufferWord {
 5877                    word_range,
 5878                    resolved: false,
 5879                },
 5880                insert_text_mode: Some(InsertTextMode::AS_IS),
 5881                confirm: None,
 5882            }));
 5883
 5884            completions.extend(
 5885                snippets
 5886                    .await
 5887                    .into_iter()
 5888                    .flat_map(|response| response.completions),
 5889            );
 5890
 5891            let menu = if completions.is_empty() {
 5892                None
 5893            } else {
 5894                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5895                    let languages = editor
 5896                        .workspace
 5897                        .as_ref()
 5898                        .and_then(|(workspace, _)| workspace.upgrade())
 5899                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5900                    let menu = CompletionsMenu::new(
 5901                        id,
 5902                        requested_source.unwrap_or(if load_provider_completions {
 5903                            CompletionsMenuSource::Normal
 5904                        } else {
 5905                            CompletionsMenuSource::SnippetsOnly
 5906                        }),
 5907                        sort_completions,
 5908                        show_completion_documentation,
 5909                        position,
 5910                        query.clone(),
 5911                        is_incomplete,
 5912                        buffer.clone(),
 5913                        completions.into(),
 5914                        editor
 5915                            .context_menu()
 5916                            .borrow_mut()
 5917                            .as_ref()
 5918                            .map(|menu| menu.primary_scroll_handle()),
 5919                        display_options,
 5920                        snippet_sort_order,
 5921                        languages,
 5922                        language,
 5923                        cx,
 5924                    );
 5925
 5926                    let query = if filter_completions { query } else { None };
 5927                    let matches_task = menu.do_async_filtering(
 5928                        query.unwrap_or_default(),
 5929                        buffer_position,
 5930                        &buffer,
 5931                        cx,
 5932                    );
 5933                    (menu, matches_task)
 5934                }) else {
 5935                    return;
 5936                };
 5937
 5938                let matches = matches_task.await;
 5939
 5940                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5941                    // Newer menu already set, so exit.
 5942                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5943                        editor.context_menu.borrow().as_ref()
 5944                        && prev_menu.id > id
 5945                    {
 5946                        return;
 5947                    };
 5948
 5949                    // Only valid to take prev_menu because either the new menu is immediately set
 5950                    // below, or the menu is hidden.
 5951                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5952                        editor.context_menu.borrow_mut().take()
 5953                    {
 5954                        let position_matches =
 5955                            if prev_menu.initial_position == menu.initial_position {
 5956                                true
 5957                            } else {
 5958                                let snapshot = editor.buffer.read(cx).read(cx);
 5959                                prev_menu.initial_position.to_offset(&snapshot)
 5960                                    == menu.initial_position.to_offset(&snapshot)
 5961                            };
 5962                        if position_matches {
 5963                            // Preserve markdown cache before `set_filter_results` because it will
 5964                            // try to populate the documentation cache.
 5965                            menu.preserve_markdown_cache(prev_menu);
 5966                        }
 5967                    };
 5968
 5969                    menu.set_filter_results(matches, provider, window, cx);
 5970                }) else {
 5971                    return;
 5972                };
 5973
 5974                menu.visible().then_some(menu)
 5975            };
 5976
 5977            editor
 5978                .update_in(cx, |editor, window, cx| {
 5979                    if editor.focus_handle.is_focused(window)
 5980                        && let Some(menu) = menu
 5981                    {
 5982                        *editor.context_menu.borrow_mut() =
 5983                            Some(CodeContextMenu::Completions(menu));
 5984
 5985                        crate::hover_popover::hide_hover(editor, cx);
 5986                        if editor.show_edit_predictions_in_menu() {
 5987                            editor.update_visible_edit_prediction(window, cx);
 5988                        } else {
 5989                            editor.discard_edit_prediction(false, cx);
 5990                        }
 5991
 5992                        cx.notify();
 5993                        return;
 5994                    }
 5995
 5996                    if editor.completion_tasks.len() <= 1 {
 5997                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5998                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5999                        // If it was already hidden and we don't show edit predictions in the menu,
 6000                        // we should also show the edit prediction when available.
 6001                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6002                            editor.update_visible_edit_prediction(window, cx);
 6003                        }
 6004                    }
 6005                })
 6006                .ok();
 6007        });
 6008
 6009        self.completion_tasks.push((id, task));
 6010    }
 6011
 6012    #[cfg(feature = "test-support")]
 6013    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6014        let menu = self.context_menu.borrow();
 6015        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6016            let completions = menu.completions.borrow();
 6017            Some(completions.to_vec())
 6018        } else {
 6019            None
 6020        }
 6021    }
 6022
 6023    pub fn with_completions_menu_matching_id<R>(
 6024        &self,
 6025        id: CompletionId,
 6026        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6027    ) -> R {
 6028        let mut context_menu = self.context_menu.borrow_mut();
 6029        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6030            return f(None);
 6031        };
 6032        if completions_menu.id != id {
 6033            return f(None);
 6034        }
 6035        f(Some(completions_menu))
 6036    }
 6037
 6038    pub fn confirm_completion(
 6039        &mut self,
 6040        action: &ConfirmCompletion,
 6041        window: &mut Window,
 6042        cx: &mut Context<Self>,
 6043    ) -> Option<Task<Result<()>>> {
 6044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6045        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6046    }
 6047
 6048    pub fn confirm_completion_insert(
 6049        &mut self,
 6050        _: &ConfirmCompletionInsert,
 6051        window: &mut Window,
 6052        cx: &mut Context<Self>,
 6053    ) -> Option<Task<Result<()>>> {
 6054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6055        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6056    }
 6057
 6058    pub fn confirm_completion_replace(
 6059        &mut self,
 6060        _: &ConfirmCompletionReplace,
 6061        window: &mut Window,
 6062        cx: &mut Context<Self>,
 6063    ) -> Option<Task<Result<()>>> {
 6064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6065        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6066    }
 6067
 6068    pub fn compose_completion(
 6069        &mut self,
 6070        action: &ComposeCompletion,
 6071        window: &mut Window,
 6072        cx: &mut Context<Self>,
 6073    ) -> Option<Task<Result<()>>> {
 6074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6075        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6076    }
 6077
 6078    fn do_completion(
 6079        &mut self,
 6080        item_ix: Option<usize>,
 6081        intent: CompletionIntent,
 6082        window: &mut Window,
 6083        cx: &mut Context<Editor>,
 6084    ) -> Option<Task<Result<()>>> {
 6085        use language::ToOffset as _;
 6086
 6087        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6088        else {
 6089            return None;
 6090        };
 6091
 6092        let candidate_id = {
 6093            let entries = completions_menu.entries.borrow();
 6094            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6095            if self.show_edit_predictions_in_menu() {
 6096                self.discard_edit_prediction(true, cx);
 6097            }
 6098            mat.candidate_id
 6099        };
 6100
 6101        let completion = completions_menu
 6102            .completions
 6103            .borrow()
 6104            .get(candidate_id)?
 6105            .clone();
 6106        cx.stop_propagation();
 6107
 6108        let buffer_handle = completions_menu.buffer.clone();
 6109
 6110        let CompletionEdit {
 6111            new_text,
 6112            snippet,
 6113            replace_range,
 6114        } = process_completion_for_edit(
 6115            &completion,
 6116            intent,
 6117            &buffer_handle,
 6118            &completions_menu.initial_position.text_anchor,
 6119            cx,
 6120        );
 6121
 6122        let buffer = buffer_handle.read(cx);
 6123        let snapshot = self.buffer.read(cx).snapshot(cx);
 6124        let newest_anchor = self.selections.newest_anchor();
 6125        let replace_range_multibuffer = {
 6126            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6127            excerpt.map_range_from_buffer(replace_range.clone())
 6128        };
 6129        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6130            return None;
 6131        }
 6132
 6133        let old_text = buffer
 6134            .text_for_range(replace_range.clone())
 6135            .collect::<String>();
 6136        let lookbehind = newest_anchor
 6137            .start
 6138            .text_anchor
 6139            .to_offset(buffer)
 6140            .saturating_sub(replace_range.start.0);
 6141        let lookahead = replace_range
 6142            .end
 6143            .0
 6144            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6145        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6146        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6147
 6148        let selections = self
 6149            .selections
 6150            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6151        let mut ranges = Vec::new();
 6152        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6153
 6154        for selection in &selections {
 6155            let range = if selection.id == newest_anchor.id {
 6156                replace_range_multibuffer.clone()
 6157            } else {
 6158                let mut range = selection.range();
 6159
 6160                // if prefix is present, don't duplicate it
 6161                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6162                    range.start = range.start.saturating_sub_usize(lookbehind);
 6163
 6164                    // if suffix is also present, mimic the newest cursor and replace it
 6165                    if selection.id != newest_anchor.id
 6166                        && snapshot.contains_str_at(range.end, suffix)
 6167                    {
 6168                        range.end += lookahead;
 6169                    }
 6170                }
 6171                range
 6172            };
 6173
 6174            ranges.push(range.clone());
 6175
 6176            if !self.linked_edit_ranges.is_empty() {
 6177                let start_anchor = snapshot.anchor_before(range.start);
 6178                let end_anchor = snapshot.anchor_after(range.end);
 6179                if let Some(ranges) = self
 6180                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6181                {
 6182                    for (buffer, edits) in ranges {
 6183                        linked_edits
 6184                            .entry(buffer.clone())
 6185                            .or_default()
 6186                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6187                    }
 6188                }
 6189            }
 6190        }
 6191
 6192        let common_prefix_len = old_text
 6193            .chars()
 6194            .zip(new_text.chars())
 6195            .take_while(|(a, b)| a == b)
 6196            .map(|(a, _)| a.len_utf8())
 6197            .sum::<usize>();
 6198
 6199        cx.emit(EditorEvent::InputHandled {
 6200            utf16_range_to_replace: None,
 6201            text: new_text[common_prefix_len..].into(),
 6202        });
 6203
 6204        self.transact(window, cx, |editor, window, cx| {
 6205            if let Some(mut snippet) = snippet {
 6206                snippet.text = new_text.to_string();
 6207                editor
 6208                    .insert_snippet(&ranges, snippet, window, cx)
 6209                    .log_err();
 6210            } else {
 6211                editor.buffer.update(cx, |multi_buffer, cx| {
 6212                    let auto_indent = match completion.insert_text_mode {
 6213                        Some(InsertTextMode::AS_IS) => None,
 6214                        _ => editor.autoindent_mode.clone(),
 6215                    };
 6216                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6217                    multi_buffer.edit(edits, auto_indent, cx);
 6218                });
 6219            }
 6220            for (buffer, edits) in linked_edits {
 6221                buffer.update(cx, |buffer, cx| {
 6222                    let snapshot = buffer.snapshot();
 6223                    let edits = edits
 6224                        .into_iter()
 6225                        .map(|(range, text)| {
 6226                            use text::ToPoint as TP;
 6227                            let end_point = TP::to_point(&range.end, &snapshot);
 6228                            let start_point = TP::to_point(&range.start, &snapshot);
 6229                            (start_point..end_point, text)
 6230                        })
 6231                        .sorted_by_key(|(range, _)| range.start);
 6232                    buffer.edit(edits, None, cx);
 6233                })
 6234            }
 6235
 6236            editor.refresh_edit_prediction(true, false, window, cx);
 6237        });
 6238        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6239
 6240        let show_new_completions_on_confirm = completion
 6241            .confirm
 6242            .as_ref()
 6243            .is_some_and(|confirm| confirm(intent, window, cx));
 6244        if show_new_completions_on_confirm {
 6245            self.open_or_update_completions_menu(None, None, false, window, cx);
 6246        }
 6247
 6248        let provider = self.completion_provider.as_ref()?;
 6249
 6250        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6251        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6252            let CompletionSource::Lsp {
 6253                lsp_completion,
 6254                server_id,
 6255                ..
 6256            } = &completion.source
 6257            else {
 6258                return None;
 6259            };
 6260            let lsp_command = lsp_completion.command.as_ref()?;
 6261            let available_commands = lsp_store
 6262                .read(cx)
 6263                .lsp_server_capabilities
 6264                .get(server_id)
 6265                .and_then(|server_capabilities| {
 6266                    server_capabilities
 6267                        .execute_command_provider
 6268                        .as_ref()
 6269                        .map(|options| options.commands.as_slice())
 6270                })?;
 6271            if available_commands.contains(&lsp_command.command) {
 6272                Some(CodeAction {
 6273                    server_id: *server_id,
 6274                    range: language::Anchor::MIN..language::Anchor::MIN,
 6275                    lsp_action: LspAction::Command(lsp_command.clone()),
 6276                    resolved: false,
 6277                })
 6278            } else {
 6279                None
 6280            }
 6281        });
 6282
 6283        drop(completion);
 6284        let apply_edits = provider.apply_additional_edits_for_completion(
 6285            buffer_handle.clone(),
 6286            completions_menu.completions.clone(),
 6287            candidate_id,
 6288            true,
 6289            cx,
 6290        );
 6291
 6292        let editor_settings = EditorSettings::get_global(cx);
 6293        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6294            // After the code completion is finished, users often want to know what signatures are needed.
 6295            // so we should automatically call signature_help
 6296            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6297        }
 6298
 6299        Some(cx.spawn_in(window, async move |editor, cx| {
 6300            apply_edits.await?;
 6301
 6302            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6303                let title = command.lsp_action.title().to_owned();
 6304                let project_transaction = lsp_store
 6305                    .update(cx, |lsp_store, cx| {
 6306                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6307                    })
 6308                    .await
 6309                    .context("applying post-completion command")?;
 6310                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6311                    Self::open_project_transaction(
 6312                        &editor,
 6313                        workspace.downgrade(),
 6314                        project_transaction,
 6315                        title,
 6316                        cx,
 6317                    )
 6318                    .await?;
 6319                }
 6320            }
 6321
 6322            Ok(())
 6323        }))
 6324    }
 6325
 6326    pub fn toggle_code_actions(
 6327        &mut self,
 6328        action: &ToggleCodeActions,
 6329        window: &mut Window,
 6330        cx: &mut Context<Self>,
 6331    ) {
 6332        let quick_launch = action.quick_launch;
 6333        let mut context_menu = self.context_menu.borrow_mut();
 6334        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6335            if code_actions.deployed_from == action.deployed_from {
 6336                // Toggle if we're selecting the same one
 6337                *context_menu = None;
 6338                cx.notify();
 6339                return;
 6340            } else {
 6341                // Otherwise, clear it and start a new one
 6342                *context_menu = None;
 6343                cx.notify();
 6344            }
 6345        }
 6346        drop(context_menu);
 6347        let snapshot = self.snapshot(window, cx);
 6348        let deployed_from = action.deployed_from.clone();
 6349        let action = action.clone();
 6350        self.completion_tasks.clear();
 6351        self.discard_edit_prediction(false, cx);
 6352
 6353        let multibuffer_point = match &action.deployed_from {
 6354            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6355                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6356            }
 6357            _ => self
 6358                .selections
 6359                .newest::<Point>(&snapshot.display_snapshot)
 6360                .head(),
 6361        };
 6362        let Some((buffer, buffer_row)) = snapshot
 6363            .buffer_snapshot()
 6364            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6365            .and_then(|(buffer_snapshot, range)| {
 6366                self.buffer()
 6367                    .read(cx)
 6368                    .buffer(buffer_snapshot.remote_id())
 6369                    .map(|buffer| (buffer, range.start.row))
 6370            })
 6371        else {
 6372            return;
 6373        };
 6374        let buffer_id = buffer.read(cx).remote_id();
 6375        let tasks = self
 6376            .tasks
 6377            .get(&(buffer_id, buffer_row))
 6378            .map(|t| Arc::new(t.to_owned()));
 6379
 6380        if !self.focus_handle.is_focused(window) {
 6381            return;
 6382        }
 6383        let project = self.project.clone();
 6384
 6385        let code_actions_task = match deployed_from {
 6386            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6387            _ => self.code_actions(buffer_row, window, cx),
 6388        };
 6389
 6390        let runnable_task = match deployed_from {
 6391            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6392            _ => {
 6393                let mut task_context_task = Task::ready(None);
 6394                if let Some(tasks) = &tasks
 6395                    && let Some(project) = project
 6396                {
 6397                    task_context_task =
 6398                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6399                }
 6400
 6401                cx.spawn_in(window, {
 6402                    let buffer = buffer.clone();
 6403                    async move |editor, cx| {
 6404                        let task_context = task_context_task.await;
 6405
 6406                        let resolved_tasks =
 6407                            tasks
 6408                                .zip(task_context.clone())
 6409                                .map(|(tasks, task_context)| ResolvedTasks {
 6410                                    templates: tasks.resolve(&task_context).collect(),
 6411                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6412                                        multibuffer_point.row,
 6413                                        tasks.column,
 6414                                    )),
 6415                                });
 6416                        let debug_scenarios = editor
 6417                            .update(cx, |editor, cx| {
 6418                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6419                            })?
 6420                            .await;
 6421                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6422                    }
 6423                })
 6424            }
 6425        };
 6426
 6427        cx.spawn_in(window, async move |editor, cx| {
 6428            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6429            let code_actions = code_actions_task.await;
 6430            let spawn_straight_away = quick_launch
 6431                && resolved_tasks
 6432                    .as_ref()
 6433                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6434                && code_actions
 6435                    .as_ref()
 6436                    .is_none_or(|actions| actions.is_empty())
 6437                && debug_scenarios.is_empty();
 6438
 6439            editor.update_in(cx, |editor, window, cx| {
 6440                crate::hover_popover::hide_hover(editor, cx);
 6441                let actions = CodeActionContents::new(
 6442                    resolved_tasks,
 6443                    code_actions,
 6444                    debug_scenarios,
 6445                    task_context.unwrap_or_default(),
 6446                );
 6447
 6448                // Don't show the menu if there are no actions available
 6449                if actions.is_empty() {
 6450                    cx.notify();
 6451                    return Task::ready(Ok(()));
 6452                }
 6453
 6454                *editor.context_menu.borrow_mut() =
 6455                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6456                        buffer,
 6457                        actions,
 6458                        selected_item: Default::default(),
 6459                        scroll_handle: UniformListScrollHandle::default(),
 6460                        deployed_from,
 6461                    }));
 6462                cx.notify();
 6463                if spawn_straight_away
 6464                    && let Some(task) = editor.confirm_code_action(
 6465                        &ConfirmCodeAction { item_ix: Some(0) },
 6466                        window,
 6467                        cx,
 6468                    )
 6469                {
 6470                    return task;
 6471                }
 6472
 6473                Task::ready(Ok(()))
 6474            })
 6475        })
 6476        .detach_and_log_err(cx);
 6477    }
 6478
 6479    fn debug_scenarios(
 6480        &mut self,
 6481        resolved_tasks: &Option<ResolvedTasks>,
 6482        buffer: &Entity<Buffer>,
 6483        cx: &mut App,
 6484    ) -> Task<Vec<task::DebugScenario>> {
 6485        maybe!({
 6486            let project = self.project()?;
 6487            let dap_store = project.read(cx).dap_store();
 6488            let mut scenarios = vec![];
 6489            let resolved_tasks = resolved_tasks.as_ref()?;
 6490            let buffer = buffer.read(cx);
 6491            let language = buffer.language()?;
 6492            let file = buffer.file();
 6493            let debug_adapter = language_settings(language.name().into(), file, cx)
 6494                .debuggers
 6495                .first()
 6496                .map(SharedString::from)
 6497                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6498
 6499            dap_store.update(cx, |dap_store, cx| {
 6500                for (_, task) in &resolved_tasks.templates {
 6501                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6502                        task.original_task().clone(),
 6503                        debug_adapter.clone().into(),
 6504                        task.display_label().to_owned().into(),
 6505                        cx,
 6506                    );
 6507                    scenarios.push(maybe_scenario);
 6508                }
 6509            });
 6510            Some(cx.background_spawn(async move {
 6511                futures::future::join_all(scenarios)
 6512                    .await
 6513                    .into_iter()
 6514                    .flatten()
 6515                    .collect::<Vec<_>>()
 6516            }))
 6517        })
 6518        .unwrap_or_else(|| Task::ready(vec![]))
 6519    }
 6520
 6521    fn code_actions(
 6522        &mut self,
 6523        buffer_row: u32,
 6524        window: &mut Window,
 6525        cx: &mut Context<Self>,
 6526    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6527        let mut task = self.code_actions_task.take();
 6528        cx.spawn_in(window, async move |editor, cx| {
 6529            while let Some(prev_task) = task {
 6530                prev_task.await.log_err();
 6531                task = editor
 6532                    .update(cx, |this, _| this.code_actions_task.take())
 6533                    .ok()?;
 6534            }
 6535
 6536            editor
 6537                .update(cx, |editor, cx| {
 6538                    editor
 6539                        .available_code_actions
 6540                        .clone()
 6541                        .and_then(|(location, code_actions)| {
 6542                            let snapshot = location.buffer.read(cx).snapshot();
 6543                            let point_range = location.range.to_point(&snapshot);
 6544                            let point_range = point_range.start.row..=point_range.end.row;
 6545                            if point_range.contains(&buffer_row) {
 6546                                Some(code_actions)
 6547                            } else {
 6548                                None
 6549                            }
 6550                        })
 6551                })
 6552                .ok()
 6553                .flatten()
 6554        })
 6555    }
 6556
 6557    pub fn confirm_code_action(
 6558        &mut self,
 6559        action: &ConfirmCodeAction,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) -> Option<Task<Result<()>>> {
 6563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6564
 6565        let actions_menu =
 6566            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6567                menu
 6568            } else {
 6569                return None;
 6570            };
 6571
 6572        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6573        let action = actions_menu.actions.get(action_ix)?;
 6574        let title = action.label();
 6575        let buffer = actions_menu.buffer;
 6576        let workspace = self.workspace()?;
 6577
 6578        match action {
 6579            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6580                workspace.update(cx, |workspace, cx| {
 6581                    workspace.schedule_resolved_task(
 6582                        task_source_kind,
 6583                        resolved_task,
 6584                        false,
 6585                        window,
 6586                        cx,
 6587                    );
 6588
 6589                    Some(Task::ready(Ok(())))
 6590                })
 6591            }
 6592            CodeActionsItem::CodeAction {
 6593                excerpt_id,
 6594                action,
 6595                provider,
 6596            } => {
 6597                let apply_code_action =
 6598                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6599                let workspace = workspace.downgrade();
 6600                Some(cx.spawn_in(window, async move |editor, cx| {
 6601                    let project_transaction = apply_code_action.await?;
 6602                    Self::open_project_transaction(
 6603                        &editor,
 6604                        workspace,
 6605                        project_transaction,
 6606                        title,
 6607                        cx,
 6608                    )
 6609                    .await
 6610                }))
 6611            }
 6612            CodeActionsItem::DebugScenario(scenario) => {
 6613                let context = actions_menu.actions.context;
 6614
 6615                workspace.update(cx, |workspace, cx| {
 6616                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6617                    workspace.start_debug_session(
 6618                        scenario,
 6619                        context,
 6620                        Some(buffer),
 6621                        None,
 6622                        window,
 6623                        cx,
 6624                    );
 6625                });
 6626                Some(Task::ready(Ok(())))
 6627            }
 6628        }
 6629    }
 6630
 6631    fn open_transaction_for_hidden_buffers(
 6632        workspace: Entity<Workspace>,
 6633        transaction: ProjectTransaction,
 6634        title: String,
 6635        window: &mut Window,
 6636        cx: &mut Context<Self>,
 6637    ) {
 6638        if transaction.0.is_empty() {
 6639            return;
 6640        }
 6641
 6642        let edited_buffers_already_open = {
 6643            let other_editors: Vec<Entity<Editor>> = workspace
 6644                .read(cx)
 6645                .panes()
 6646                .iter()
 6647                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6648                .filter(|editor| editor.entity_id() != cx.entity_id())
 6649                .collect();
 6650
 6651            transaction.0.keys().all(|buffer| {
 6652                other_editors.iter().any(|editor| {
 6653                    let multi_buffer = editor.read(cx).buffer();
 6654                    multi_buffer.read(cx).is_singleton()
 6655                        && multi_buffer
 6656                            .read(cx)
 6657                            .as_singleton()
 6658                            .map_or(false, |singleton| {
 6659                                singleton.entity_id() == buffer.entity_id()
 6660                            })
 6661                })
 6662            })
 6663        };
 6664        if !edited_buffers_already_open {
 6665            let workspace = workspace.downgrade();
 6666            cx.defer_in(window, move |_, window, cx| {
 6667                cx.spawn_in(window, async move |editor, cx| {
 6668                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6669                        .await
 6670                        .ok()
 6671                })
 6672                .detach();
 6673            });
 6674        }
 6675    }
 6676
 6677    pub async fn open_project_transaction(
 6678        editor: &WeakEntity<Editor>,
 6679        workspace: WeakEntity<Workspace>,
 6680        transaction: ProjectTransaction,
 6681        title: String,
 6682        cx: &mut AsyncWindowContext,
 6683    ) -> Result<()> {
 6684        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6685        cx.update(|_, cx| {
 6686            entries.sort_unstable_by_key(|(buffer, _)| {
 6687                buffer.read(cx).file().map(|f| f.path().clone())
 6688            });
 6689        })?;
 6690        if entries.is_empty() {
 6691            return Ok(());
 6692        }
 6693
 6694        // If the project transaction's edits are all contained within this editor, then
 6695        // avoid opening a new editor to display them.
 6696
 6697        if let [(buffer, transaction)] = &*entries {
 6698            let excerpt = editor.update(cx, |editor, cx| {
 6699                editor
 6700                    .buffer()
 6701                    .read(cx)
 6702                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6703            })?;
 6704            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6705                && excerpted_buffer == *buffer
 6706            {
 6707                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6708                    let excerpt_range = excerpt_range.to_offset(buffer);
 6709                    buffer
 6710                        .edited_ranges_for_transaction::<usize>(transaction)
 6711                        .all(|range| {
 6712                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6713                        })
 6714                });
 6715
 6716                if all_edits_within_excerpt {
 6717                    return Ok(());
 6718                }
 6719            }
 6720        }
 6721
 6722        let mut ranges_to_highlight = Vec::new();
 6723        let excerpt_buffer = cx.new(|cx| {
 6724            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6725            for (buffer_handle, transaction) in &entries {
 6726                let edited_ranges = buffer_handle
 6727                    .read(cx)
 6728                    .edited_ranges_for_transaction::<Point>(transaction)
 6729                    .collect::<Vec<_>>();
 6730                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6731                    PathKey::for_buffer(buffer_handle, cx),
 6732                    buffer_handle.clone(),
 6733                    edited_ranges,
 6734                    multibuffer_context_lines(cx),
 6735                    cx,
 6736                );
 6737
 6738                ranges_to_highlight.extend(ranges);
 6739            }
 6740            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6741            multibuffer
 6742        });
 6743
 6744        workspace.update_in(cx, |workspace, window, cx| {
 6745            let project = workspace.project().clone();
 6746            let editor =
 6747                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6748            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6749            editor.update(cx, |editor, cx| {
 6750                editor.highlight_background::<Self>(
 6751                    &ranges_to_highlight,
 6752                    |_, theme| theme.colors().editor_highlighted_line_background,
 6753                    cx,
 6754                );
 6755            });
 6756        })?;
 6757
 6758        Ok(())
 6759    }
 6760
 6761    pub fn clear_code_action_providers(&mut self) {
 6762        self.code_action_providers.clear();
 6763        self.available_code_actions.take();
 6764    }
 6765
 6766    pub fn add_code_action_provider(
 6767        &mut self,
 6768        provider: Rc<dyn CodeActionProvider>,
 6769        window: &mut Window,
 6770        cx: &mut Context<Self>,
 6771    ) {
 6772        if self
 6773            .code_action_providers
 6774            .iter()
 6775            .any(|existing_provider| existing_provider.id() == provider.id())
 6776        {
 6777            return;
 6778        }
 6779
 6780        self.code_action_providers.push(provider);
 6781        self.refresh_code_actions(window, cx);
 6782    }
 6783
 6784    pub fn remove_code_action_provider(
 6785        &mut self,
 6786        id: Arc<str>,
 6787        window: &mut Window,
 6788        cx: &mut Context<Self>,
 6789    ) {
 6790        self.code_action_providers
 6791            .retain(|provider| provider.id() != id);
 6792        self.refresh_code_actions(window, cx);
 6793    }
 6794
 6795    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6796        !self.code_action_providers.is_empty()
 6797            && EditorSettings::get_global(cx).toolbar.code_actions
 6798    }
 6799
 6800    pub fn has_available_code_actions(&self) -> bool {
 6801        self.available_code_actions
 6802            .as_ref()
 6803            .is_some_and(|(_, actions)| !actions.is_empty())
 6804    }
 6805
 6806    fn render_inline_code_actions(
 6807        &self,
 6808        icon_size: ui::IconSize,
 6809        display_row: DisplayRow,
 6810        is_active: bool,
 6811        cx: &mut Context<Self>,
 6812    ) -> AnyElement {
 6813        let show_tooltip = !self.context_menu_visible();
 6814        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6815            .icon_size(icon_size)
 6816            .shape(ui::IconButtonShape::Square)
 6817            .icon_color(ui::Color::Hidden)
 6818            .toggle_state(is_active)
 6819            .when(show_tooltip, |this| {
 6820                this.tooltip({
 6821                    let focus_handle = self.focus_handle.clone();
 6822                    move |_window, cx| {
 6823                        Tooltip::for_action_in(
 6824                            "Toggle Code Actions",
 6825                            &ToggleCodeActions {
 6826                                deployed_from: None,
 6827                                quick_launch: false,
 6828                            },
 6829                            &focus_handle,
 6830                            cx,
 6831                        )
 6832                    }
 6833                })
 6834            })
 6835            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6836                window.focus(&editor.focus_handle(cx), cx);
 6837                editor.toggle_code_actions(
 6838                    &crate::actions::ToggleCodeActions {
 6839                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6840                            display_row,
 6841                        )),
 6842                        quick_launch: false,
 6843                    },
 6844                    window,
 6845                    cx,
 6846                );
 6847            }))
 6848            .into_any_element()
 6849    }
 6850
 6851    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6852        &self.context_menu
 6853    }
 6854
 6855    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6856        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6857            cx.background_executor()
 6858                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6859                .await;
 6860
 6861            let (start_buffer, start, _, end, newest_selection) = this
 6862                .update(cx, |this, cx| {
 6863                    let newest_selection = this.selections.newest_anchor().clone();
 6864                    if newest_selection.head().diff_base_anchor.is_some() {
 6865                        return None;
 6866                    }
 6867                    let display_snapshot = this.display_snapshot(cx);
 6868                    let newest_selection_adjusted =
 6869                        this.selections.newest_adjusted(&display_snapshot);
 6870                    let buffer = this.buffer.read(cx);
 6871
 6872                    let (start_buffer, start) =
 6873                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6874                    let (end_buffer, end) =
 6875                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6876
 6877                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6878                })?
 6879                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6880                .context(
 6881                    "Expected selection to lie in a single buffer when refreshing code actions",
 6882                )?;
 6883            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6884                let providers = this.code_action_providers.clone();
 6885                let tasks = this
 6886                    .code_action_providers
 6887                    .iter()
 6888                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6889                    .collect::<Vec<_>>();
 6890                (providers, tasks)
 6891            })?;
 6892
 6893            let mut actions = Vec::new();
 6894            for (provider, provider_actions) in
 6895                providers.into_iter().zip(future::join_all(tasks).await)
 6896            {
 6897                if let Some(provider_actions) = provider_actions.log_err() {
 6898                    actions.extend(provider_actions.into_iter().map(|action| {
 6899                        AvailableCodeAction {
 6900                            excerpt_id: newest_selection.start.excerpt_id,
 6901                            action,
 6902                            provider: provider.clone(),
 6903                        }
 6904                    }));
 6905                }
 6906            }
 6907
 6908            this.update(cx, |this, cx| {
 6909                this.available_code_actions = if actions.is_empty() {
 6910                    None
 6911                } else {
 6912                    Some((
 6913                        Location {
 6914                            buffer: start_buffer,
 6915                            range: start..end,
 6916                        },
 6917                        actions.into(),
 6918                    ))
 6919                };
 6920                cx.notify();
 6921            })
 6922        }));
 6923    }
 6924
 6925    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6926        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6927            self.show_git_blame_inline = false;
 6928
 6929            self.show_git_blame_inline_delay_task =
 6930                Some(cx.spawn_in(window, async move |this, cx| {
 6931                    cx.background_executor().timer(delay).await;
 6932
 6933                    this.update(cx, |this, cx| {
 6934                        this.show_git_blame_inline = true;
 6935                        cx.notify();
 6936                    })
 6937                    .log_err();
 6938                }));
 6939        }
 6940    }
 6941
 6942    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6943        let snapshot = self.snapshot(window, cx);
 6944        let cursor = self
 6945            .selections
 6946            .newest::<Point>(&snapshot.display_snapshot)
 6947            .head();
 6948        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6949        else {
 6950            return;
 6951        };
 6952
 6953        if self.blame.is_none() {
 6954            self.start_git_blame(true, window, cx);
 6955        }
 6956        let Some(blame) = self.blame.as_ref() else {
 6957            return;
 6958        };
 6959
 6960        let row_info = RowInfo {
 6961            buffer_id: Some(buffer.remote_id()),
 6962            buffer_row: Some(point.row),
 6963            ..Default::default()
 6964        };
 6965        let Some((buffer, blame_entry)) = blame
 6966            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6967            .flatten()
 6968        else {
 6969            return;
 6970        };
 6971
 6972        let anchor = self.selections.newest_anchor().head();
 6973        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6974        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6975            self.show_blame_popover(
 6976                buffer,
 6977                &blame_entry,
 6978                position + last_bounds.origin,
 6979                true,
 6980                cx,
 6981            );
 6982        };
 6983    }
 6984
 6985    fn show_blame_popover(
 6986        &mut self,
 6987        buffer: BufferId,
 6988        blame_entry: &BlameEntry,
 6989        position: gpui::Point<Pixels>,
 6990        ignore_timeout: bool,
 6991        cx: &mut Context<Self>,
 6992    ) {
 6993        if let Some(state) = &mut self.inline_blame_popover {
 6994            state.hide_task.take();
 6995        } else {
 6996            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6997            let blame_entry = blame_entry.clone();
 6998            let show_task = cx.spawn(async move |editor, cx| {
 6999                if !ignore_timeout {
 7000                    cx.background_executor()
 7001                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7002                        .await;
 7003                }
 7004                editor
 7005                    .update(cx, |editor, cx| {
 7006                        editor.inline_blame_popover_show_task.take();
 7007                        let Some(blame) = editor.blame.as_ref() else {
 7008                            return;
 7009                        };
 7010                        let blame = blame.read(cx);
 7011                        let details = blame.details_for_entry(buffer, &blame_entry);
 7012                        let markdown = cx.new(|cx| {
 7013                            Markdown::new(
 7014                                details
 7015                                    .as_ref()
 7016                                    .map(|message| message.message.clone())
 7017                                    .unwrap_or_default(),
 7018                                None,
 7019                                None,
 7020                                cx,
 7021                            )
 7022                        });
 7023                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7024                            position,
 7025                            hide_task: None,
 7026                            popover_bounds: None,
 7027                            popover_state: InlineBlamePopoverState {
 7028                                scroll_handle: ScrollHandle::new(),
 7029                                commit_message: details,
 7030                                markdown,
 7031                            },
 7032                            keyboard_grace: ignore_timeout,
 7033                        });
 7034                        cx.notify();
 7035                    })
 7036                    .ok();
 7037            });
 7038            self.inline_blame_popover_show_task = Some(show_task);
 7039        }
 7040    }
 7041
 7042    pub fn has_mouse_context_menu(&self) -> bool {
 7043        self.mouse_context_menu.is_some()
 7044    }
 7045
 7046    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7047        self.inline_blame_popover_show_task.take();
 7048        if let Some(state) = &mut self.inline_blame_popover {
 7049            let hide_task = cx.spawn(async move |editor, cx| {
 7050                if !ignore_timeout {
 7051                    cx.background_executor()
 7052                        .timer(std::time::Duration::from_millis(100))
 7053                        .await;
 7054                }
 7055                editor
 7056                    .update(cx, |editor, cx| {
 7057                        editor.inline_blame_popover.take();
 7058                        cx.notify();
 7059                    })
 7060                    .ok();
 7061            });
 7062            state.hide_task = Some(hide_task);
 7063            true
 7064        } else {
 7065            false
 7066        }
 7067    }
 7068
 7069    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7070        if self.pending_rename.is_some() {
 7071            return None;
 7072        }
 7073
 7074        let provider = self.semantics_provider.clone()?;
 7075        let buffer = self.buffer.read(cx);
 7076        let newest_selection = self.selections.newest_anchor().clone();
 7077        let cursor_position = newest_selection.head();
 7078        let (cursor_buffer, cursor_buffer_position) =
 7079            buffer.text_anchor_for_position(cursor_position, cx)?;
 7080        let (tail_buffer, tail_buffer_position) =
 7081            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7082        if cursor_buffer != tail_buffer {
 7083            return None;
 7084        }
 7085
 7086        let snapshot = cursor_buffer.read(cx).snapshot();
 7087        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7088        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7089        if start_word_range != end_word_range {
 7090            self.document_highlights_task.take();
 7091            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7092            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7093            return None;
 7094        }
 7095
 7096        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7097        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7098            cx.background_executor()
 7099                .timer(Duration::from_millis(debounce))
 7100                .await;
 7101
 7102            let highlights = if let Some(highlights) = cx.update(|cx| {
 7103                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7104            }) {
 7105                highlights.await.log_err()
 7106            } else {
 7107                None
 7108            };
 7109
 7110            if let Some(highlights) = highlights {
 7111                this.update(cx, |this, cx| {
 7112                    if this.pending_rename.is_some() {
 7113                        return;
 7114                    }
 7115
 7116                    let buffer = this.buffer.read(cx);
 7117                    if buffer
 7118                        .text_anchor_for_position(cursor_position, cx)
 7119                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7120                    {
 7121                        return;
 7122                    }
 7123
 7124                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7125                    let mut write_ranges = Vec::new();
 7126                    let mut read_ranges = Vec::new();
 7127                    for highlight in highlights {
 7128                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7129                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7130                        {
 7131                            let start = highlight
 7132                                .range
 7133                                .start
 7134                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7135                            let end = highlight
 7136                                .range
 7137                                .end
 7138                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7139                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7140                                continue;
 7141                            }
 7142
 7143                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7144                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7145                                write_ranges.push(range);
 7146                            } else {
 7147                                read_ranges.push(range);
 7148                            }
 7149                        }
 7150                    }
 7151
 7152                    this.highlight_background::<DocumentHighlightRead>(
 7153                        &read_ranges,
 7154                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7155                        cx,
 7156                    );
 7157                    this.highlight_background::<DocumentHighlightWrite>(
 7158                        &write_ranges,
 7159                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7160                        cx,
 7161                    );
 7162                    cx.notify();
 7163                })
 7164                .log_err();
 7165            }
 7166        }));
 7167        None
 7168    }
 7169
 7170    fn prepare_highlight_query_from_selection(
 7171        &mut self,
 7172        window: &Window,
 7173        cx: &mut Context<Editor>,
 7174    ) -> Option<(String, Range<Anchor>)> {
 7175        if matches!(self.mode, EditorMode::SingleLine) {
 7176            return None;
 7177        }
 7178        if !EditorSettings::get_global(cx).selection_highlight {
 7179            return None;
 7180        }
 7181        if self.selections.count() != 1 || self.selections.line_mode() {
 7182            return None;
 7183        }
 7184        let snapshot = self.snapshot(window, cx);
 7185        let selection = self.selections.newest::<Point>(&snapshot);
 7186        // If the selection spans multiple rows OR it is empty
 7187        if selection.start.row != selection.end.row
 7188            || selection.start.column == selection.end.column
 7189        {
 7190            return None;
 7191        }
 7192        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7193        let query = snapshot
 7194            .buffer_snapshot()
 7195            .text_for_range(selection_anchor_range.clone())
 7196            .collect::<String>();
 7197        if query.trim().is_empty() {
 7198            return None;
 7199        }
 7200        Some((query, selection_anchor_range))
 7201    }
 7202
 7203    #[ztracing::instrument(skip_all)]
 7204    fn update_selection_occurrence_highlights(
 7205        &mut self,
 7206        query_text: String,
 7207        query_range: Range<Anchor>,
 7208        multi_buffer_range_to_query: Range<Point>,
 7209        use_debounce: bool,
 7210        window: &mut Window,
 7211        cx: &mut Context<Editor>,
 7212    ) -> Task<()> {
 7213        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7214        cx.spawn_in(window, async move |editor, cx| {
 7215            if use_debounce {
 7216                cx.background_executor()
 7217                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7218                    .await;
 7219            }
 7220            let match_task = cx.background_spawn(async move {
 7221                let buffer_ranges = multi_buffer_snapshot
 7222                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7223                    .into_iter()
 7224                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7225                let mut match_ranges = Vec::new();
 7226                let Ok(regex) = project::search::SearchQuery::text(
 7227                    query_text.clone(),
 7228                    false,
 7229                    false,
 7230                    false,
 7231                    Default::default(),
 7232                    Default::default(),
 7233                    false,
 7234                    None,
 7235                ) else {
 7236                    return Vec::default();
 7237                };
 7238                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7239                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7240                    match_ranges.extend(
 7241                        regex
 7242                            .search(
 7243                                buffer_snapshot,
 7244                                Some(search_range.start.0..search_range.end.0),
 7245                            )
 7246                            .await
 7247                            .into_iter()
 7248                            .filter_map(|match_range| {
 7249                                let match_start = buffer_snapshot
 7250                                    .anchor_after(search_range.start + match_range.start);
 7251                                let match_end = buffer_snapshot
 7252                                    .anchor_before(search_range.start + match_range.end);
 7253                                let match_anchor_range =
 7254                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7255                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7256                            }),
 7257                    );
 7258                }
 7259                match_ranges
 7260            });
 7261            let match_ranges = match_task.await;
 7262            editor
 7263                .update_in(cx, |editor, _, cx| {
 7264                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7265                    if !match_ranges.is_empty() {
 7266                        editor.highlight_background::<SelectedTextHighlight>(
 7267                            &match_ranges,
 7268                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7269                            cx,
 7270                        )
 7271                    }
 7272                })
 7273                .log_err();
 7274        })
 7275    }
 7276
 7277    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7278        struct NewlineFold;
 7279        let type_id = std::any::TypeId::of::<NewlineFold>();
 7280        if !self.mode.is_single_line() {
 7281            return;
 7282        }
 7283        let snapshot = self.snapshot(window, cx);
 7284        if snapshot.buffer_snapshot().max_point().row == 0 {
 7285            return;
 7286        }
 7287        let task = cx.background_spawn(async move {
 7288            let new_newlines = snapshot
 7289                .buffer_chars_at(MultiBufferOffset(0))
 7290                .filter_map(|(c, i)| {
 7291                    if c == '\n' {
 7292                        Some(
 7293                            snapshot.buffer_snapshot().anchor_after(i)
 7294                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7295                        )
 7296                    } else {
 7297                        None
 7298                    }
 7299                })
 7300                .collect::<Vec<_>>();
 7301            let existing_newlines = snapshot
 7302                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7303                .filter_map(|fold| {
 7304                    if fold.placeholder.type_tag == Some(type_id) {
 7305                        Some(fold.range.start..fold.range.end)
 7306                    } else {
 7307                        None
 7308                    }
 7309                })
 7310                .collect::<Vec<_>>();
 7311
 7312            (new_newlines, existing_newlines)
 7313        });
 7314        self.folding_newlines = cx.spawn(async move |this, cx| {
 7315            let (new_newlines, existing_newlines) = task.await;
 7316            if new_newlines == existing_newlines {
 7317                return;
 7318            }
 7319            let placeholder = FoldPlaceholder {
 7320                render: Arc::new(move |_, _, cx| {
 7321                    div()
 7322                        .bg(cx.theme().status().hint_background)
 7323                        .border_b_1()
 7324                        .size_full()
 7325                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7326                        .border_color(cx.theme().status().hint)
 7327                        .child("\\n")
 7328                        .into_any()
 7329                }),
 7330                constrain_width: false,
 7331                merge_adjacent: false,
 7332                type_tag: Some(type_id),
 7333            };
 7334            let creases = new_newlines
 7335                .into_iter()
 7336                .map(|range| Crease::simple(range, placeholder.clone()))
 7337                .collect();
 7338            this.update(cx, |this, cx| {
 7339                this.display_map.update(cx, |display_map, cx| {
 7340                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7341                    display_map.fold(creases, cx);
 7342                });
 7343            })
 7344            .ok();
 7345        });
 7346    }
 7347
 7348    #[ztracing::instrument(skip_all)]
 7349    fn refresh_selected_text_highlights(
 7350        &mut self,
 7351        on_buffer_edit: bool,
 7352        window: &mut Window,
 7353        cx: &mut Context<Editor>,
 7354    ) {
 7355        let Some((query_text, query_range)) =
 7356            self.prepare_highlight_query_from_selection(window, cx)
 7357        else {
 7358            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7359            self.quick_selection_highlight_task.take();
 7360            self.debounced_selection_highlight_task.take();
 7361            return;
 7362        };
 7363        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7364        if on_buffer_edit
 7365            || self
 7366                .quick_selection_highlight_task
 7367                .as_ref()
 7368                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7369        {
 7370            let multi_buffer_visible_start = self
 7371                .scroll_manager
 7372                .anchor()
 7373                .anchor
 7374                .to_point(&multi_buffer_snapshot);
 7375            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7376                multi_buffer_visible_start
 7377                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7378                Bias::Left,
 7379            );
 7380            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7381            self.quick_selection_highlight_task = Some((
 7382                query_range.clone(),
 7383                self.update_selection_occurrence_highlights(
 7384                    query_text.clone(),
 7385                    query_range.clone(),
 7386                    multi_buffer_visible_range,
 7387                    false,
 7388                    window,
 7389                    cx,
 7390                ),
 7391            ));
 7392        }
 7393        if on_buffer_edit
 7394            || self
 7395                .debounced_selection_highlight_task
 7396                .as_ref()
 7397                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7398        {
 7399            let multi_buffer_start = multi_buffer_snapshot
 7400                .anchor_before(MultiBufferOffset(0))
 7401                .to_point(&multi_buffer_snapshot);
 7402            let multi_buffer_end = multi_buffer_snapshot
 7403                .anchor_after(multi_buffer_snapshot.len())
 7404                .to_point(&multi_buffer_snapshot);
 7405            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7406            self.debounced_selection_highlight_task = Some((
 7407                query_range.clone(),
 7408                self.update_selection_occurrence_highlights(
 7409                    query_text,
 7410                    query_range,
 7411                    multi_buffer_full_range,
 7412                    true,
 7413                    window,
 7414                    cx,
 7415                ),
 7416            ));
 7417        }
 7418    }
 7419
 7420    pub fn refresh_edit_prediction(
 7421        &mut self,
 7422        debounce: bool,
 7423        user_requested: bool,
 7424        window: &mut Window,
 7425        cx: &mut Context<Self>,
 7426    ) -> Option<()> {
 7427        if DisableAiSettings::get_global(cx).disable_ai {
 7428            return None;
 7429        }
 7430
 7431        let provider = self.edit_prediction_provider()?;
 7432        let cursor = self.selections.newest_anchor().head();
 7433        let (buffer, cursor_buffer_position) =
 7434            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7435
 7436        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7437            self.discard_edit_prediction(false, cx);
 7438            return None;
 7439        }
 7440
 7441        self.update_visible_edit_prediction(window, cx);
 7442
 7443        if !user_requested
 7444            && (!self.should_show_edit_predictions()
 7445                || !self.is_focused(window)
 7446                || buffer.read(cx).is_empty())
 7447        {
 7448            self.discard_edit_prediction(false, cx);
 7449            return None;
 7450        }
 7451
 7452        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7453        Some(())
 7454    }
 7455
 7456    fn show_edit_predictions_in_menu(&self) -> bool {
 7457        match self.edit_prediction_settings {
 7458            EditPredictionSettings::Disabled => false,
 7459            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7460        }
 7461    }
 7462
 7463    pub fn edit_predictions_enabled(&self) -> bool {
 7464        match self.edit_prediction_settings {
 7465            EditPredictionSettings::Disabled => false,
 7466            EditPredictionSettings::Enabled { .. } => true,
 7467        }
 7468    }
 7469
 7470    fn edit_prediction_requires_modifier(&self) -> bool {
 7471        match self.edit_prediction_settings {
 7472            EditPredictionSettings::Disabled => false,
 7473            EditPredictionSettings::Enabled {
 7474                preview_requires_modifier,
 7475                ..
 7476            } => preview_requires_modifier,
 7477        }
 7478    }
 7479
 7480    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7481        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7482            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7483            self.discard_edit_prediction(false, cx);
 7484        } else {
 7485            let selection = self.selections.newest_anchor();
 7486            let cursor = selection.head();
 7487
 7488            if let Some((buffer, cursor_buffer_position)) =
 7489                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7490            {
 7491                self.edit_prediction_settings =
 7492                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7493            }
 7494        }
 7495    }
 7496
 7497    fn edit_prediction_settings_at_position(
 7498        &self,
 7499        buffer: &Entity<Buffer>,
 7500        buffer_position: language::Anchor,
 7501        cx: &App,
 7502    ) -> EditPredictionSettings {
 7503        if !self.mode.is_full()
 7504            || !self.show_edit_predictions_override.unwrap_or(true)
 7505            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7506        {
 7507            return EditPredictionSettings::Disabled;
 7508        }
 7509
 7510        let buffer = buffer.read(cx);
 7511
 7512        let file = buffer.file();
 7513
 7514        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7515            return EditPredictionSettings::Disabled;
 7516        };
 7517
 7518        let by_provider = matches!(
 7519            self.menu_edit_predictions_policy,
 7520            MenuEditPredictionsPolicy::ByProvider
 7521        );
 7522
 7523        let show_in_menu = by_provider
 7524            && self
 7525                .edit_prediction_provider
 7526                .as_ref()
 7527                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7528
 7529        let preview_requires_modifier =
 7530            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7531
 7532        EditPredictionSettings::Enabled {
 7533            show_in_menu,
 7534            preview_requires_modifier,
 7535        }
 7536    }
 7537
 7538    fn should_show_edit_predictions(&self) -> bool {
 7539        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7540    }
 7541
 7542    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7543        matches!(
 7544            self.edit_prediction_preview,
 7545            EditPredictionPreview::Active { .. }
 7546        )
 7547    }
 7548
 7549    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7550        let cursor = self.selections.newest_anchor().head();
 7551        if let Some((buffer, cursor_position)) =
 7552            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7553        {
 7554            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7555        } else {
 7556            false
 7557        }
 7558    }
 7559
 7560    pub fn supports_minimap(&self, cx: &App) -> bool {
 7561        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7562    }
 7563
 7564    fn edit_predictions_enabled_in_buffer(
 7565        &self,
 7566        buffer: &Entity<Buffer>,
 7567        buffer_position: language::Anchor,
 7568        cx: &App,
 7569    ) -> bool {
 7570        maybe!({
 7571            if self.read_only(cx) {
 7572                return Some(false);
 7573            }
 7574            let provider = self.edit_prediction_provider()?;
 7575            if !provider.is_enabled(buffer, buffer_position, cx) {
 7576                return Some(false);
 7577            }
 7578            let buffer = buffer.read(cx);
 7579            let Some(file) = buffer.file() else {
 7580                return Some(true);
 7581            };
 7582            let settings = all_language_settings(Some(file), cx);
 7583            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7584        })
 7585        .unwrap_or(false)
 7586    }
 7587
 7588    pub fn show_edit_prediction(
 7589        &mut self,
 7590        _: &ShowEditPrediction,
 7591        window: &mut Window,
 7592        cx: &mut Context<Self>,
 7593    ) {
 7594        if !self.has_active_edit_prediction() {
 7595            self.refresh_edit_prediction(false, true, window, cx);
 7596            return;
 7597        }
 7598
 7599        self.update_visible_edit_prediction(window, cx);
 7600    }
 7601
 7602    pub fn display_cursor_names(
 7603        &mut self,
 7604        _: &DisplayCursorNames,
 7605        window: &mut Window,
 7606        cx: &mut Context<Self>,
 7607    ) {
 7608        self.show_cursor_names(window, cx);
 7609    }
 7610
 7611    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7612        self.show_cursor_names = true;
 7613        cx.notify();
 7614        cx.spawn_in(window, async move |this, cx| {
 7615            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7616            this.update(cx, |this, cx| {
 7617                this.show_cursor_names = false;
 7618                cx.notify()
 7619            })
 7620            .ok()
 7621        })
 7622        .detach();
 7623    }
 7624
 7625    pub fn accept_partial_edit_prediction(
 7626        &mut self,
 7627        granularity: EditPredictionGranularity,
 7628        window: &mut Window,
 7629        cx: &mut Context<Self>,
 7630    ) {
 7631        if self.show_edit_predictions_in_menu() {
 7632            self.hide_context_menu(window, cx);
 7633        }
 7634
 7635        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7636            return;
 7637        };
 7638
 7639        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7640            return;
 7641        }
 7642
 7643        match &active_edit_prediction.completion {
 7644            EditPrediction::MoveWithin { target, .. } => {
 7645                let target = *target;
 7646
 7647                if matches!(granularity, EditPredictionGranularity::Full) {
 7648                    if let Some(position_map) = &self.last_position_map {
 7649                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7650                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7651
 7652                        if is_visible || !self.edit_prediction_requires_modifier() {
 7653                            self.unfold_ranges(&[target..target], true, false, cx);
 7654                            self.change_selections(
 7655                                SelectionEffects::scroll(Autoscroll::newest()),
 7656                                window,
 7657                                cx,
 7658                                |selections| {
 7659                                    selections.select_anchor_ranges([target..target]);
 7660                                },
 7661                            );
 7662                            self.clear_row_highlights::<EditPredictionPreview>();
 7663                            self.edit_prediction_preview
 7664                                .set_previous_scroll_position(None);
 7665                        } else {
 7666                            // Highlight and request scroll
 7667                            self.edit_prediction_preview
 7668                                .set_previous_scroll_position(Some(
 7669                                    position_map.snapshot.scroll_anchor,
 7670                                ));
 7671                            self.highlight_rows::<EditPredictionPreview>(
 7672                                target..target,
 7673                                cx.theme().colors().editor_highlighted_line_background,
 7674                                RowHighlightOptions {
 7675                                    autoscroll: true,
 7676                                    ..Default::default()
 7677                                },
 7678                                cx,
 7679                            );
 7680                            self.request_autoscroll(Autoscroll::fit(), cx);
 7681                        }
 7682                    }
 7683                } else {
 7684                    self.change_selections(
 7685                        SelectionEffects::scroll(Autoscroll::newest()),
 7686                        window,
 7687                        cx,
 7688                        |selections| {
 7689                            selections.select_anchor_ranges([target..target]);
 7690                        },
 7691                    );
 7692                }
 7693            }
 7694            EditPrediction::MoveOutside { snapshot, target } => {
 7695                if let Some(workspace) = self.workspace() {
 7696                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7697                        .detach_and_log_err(cx);
 7698                }
 7699            }
 7700            EditPrediction::Edit { edits, .. } => {
 7701                self.report_edit_prediction_event(
 7702                    active_edit_prediction.completion_id.clone(),
 7703                    true,
 7704                    cx,
 7705                );
 7706
 7707                match granularity {
 7708                    EditPredictionGranularity::Full => {
 7709                        if let Some(provider) = self.edit_prediction_provider() {
 7710                            provider.accept(cx);
 7711                        }
 7712
 7713                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7714                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7715                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7716
 7717                        self.buffer.update(cx, |buffer, cx| {
 7718                            buffer.edit(edits.iter().cloned(), None, cx)
 7719                        });
 7720
 7721                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7722                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7723                        });
 7724
 7725                        let selections = self.selections.disjoint_anchors_arc();
 7726                        if let Some(transaction_id_now) =
 7727                            self.buffer.read(cx).last_transaction_id(cx)
 7728                        {
 7729                            if transaction_id_prev != Some(transaction_id_now) {
 7730                                self.selection_history
 7731                                    .insert_transaction(transaction_id_now, selections);
 7732                            }
 7733                        }
 7734
 7735                        self.update_visible_edit_prediction(window, cx);
 7736                        if self.active_edit_prediction.is_none() {
 7737                            self.refresh_edit_prediction(true, true, window, cx);
 7738                        }
 7739                        cx.notify();
 7740                    }
 7741                    _ => {
 7742                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7743                        let cursor_offset = self
 7744                            .selections
 7745                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7746                            .head();
 7747
 7748                        let insertion = edits.iter().find_map(|(range, text)| {
 7749                            let range = range.to_offset(&snapshot);
 7750                            if range.is_empty() && range.start == cursor_offset {
 7751                                Some(text)
 7752                            } else {
 7753                                None
 7754                            }
 7755                        });
 7756
 7757                        if let Some(text) = insertion {
 7758                            let text_to_insert = match granularity {
 7759                                EditPredictionGranularity::Word => {
 7760                                    let mut partial = text
 7761                                        .chars()
 7762                                        .by_ref()
 7763                                        .take_while(|c| c.is_alphabetic())
 7764                                        .collect::<String>();
 7765                                    if partial.is_empty() {
 7766                                        partial = text
 7767                                            .chars()
 7768                                            .by_ref()
 7769                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7770                                            .collect::<String>();
 7771                                    }
 7772                                    partial
 7773                                }
 7774                                EditPredictionGranularity::Line => {
 7775                                    if let Some(line) = text.split_inclusive('\n').next() {
 7776                                        line.to_string()
 7777                                    } else {
 7778                                        text.to_string()
 7779                                    }
 7780                                }
 7781                                EditPredictionGranularity::Full => unreachable!(),
 7782                            };
 7783
 7784                            cx.emit(EditorEvent::InputHandled {
 7785                                utf16_range_to_replace: None,
 7786                                text: text_to_insert.clone().into(),
 7787                            });
 7788
 7789                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7790                            self.refresh_edit_prediction(true, true, window, cx);
 7791                            cx.notify();
 7792                        } else {
 7793                            self.accept_partial_edit_prediction(
 7794                                EditPredictionGranularity::Full,
 7795                                window,
 7796                                cx,
 7797                            );
 7798                        }
 7799                    }
 7800                }
 7801            }
 7802        }
 7803
 7804        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7805    }
 7806
 7807    pub fn accept_next_word_edit_prediction(
 7808        &mut self,
 7809        _: &AcceptNextWordEditPrediction,
 7810        window: &mut Window,
 7811        cx: &mut Context<Self>,
 7812    ) {
 7813        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7814    }
 7815
 7816    pub fn accept_next_line_edit_prediction(
 7817        &mut self,
 7818        _: &AcceptNextLineEditPrediction,
 7819        window: &mut Window,
 7820        cx: &mut Context<Self>,
 7821    ) {
 7822        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7823    }
 7824
 7825    pub fn accept_edit_prediction(
 7826        &mut self,
 7827        _: &AcceptEditPrediction,
 7828        window: &mut Window,
 7829        cx: &mut Context<Self>,
 7830    ) {
 7831        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7832    }
 7833
 7834    fn discard_edit_prediction(
 7835        &mut self,
 7836        should_report_edit_prediction_event: bool,
 7837        cx: &mut Context<Self>,
 7838    ) -> bool {
 7839        if should_report_edit_prediction_event {
 7840            let completion_id = self
 7841                .active_edit_prediction
 7842                .as_ref()
 7843                .and_then(|active_completion| active_completion.completion_id.clone());
 7844
 7845            self.report_edit_prediction_event(completion_id, false, cx);
 7846        }
 7847
 7848        if let Some(provider) = self.edit_prediction_provider() {
 7849            provider.discard(cx);
 7850        }
 7851
 7852        self.take_active_edit_prediction(cx)
 7853    }
 7854
 7855    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7856        let Some(provider) = self.edit_prediction_provider() else {
 7857            return;
 7858        };
 7859
 7860        let Some((_, buffer, _)) = self
 7861            .buffer
 7862            .read(cx)
 7863            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7864        else {
 7865            return;
 7866        };
 7867
 7868        let extension = buffer
 7869            .read(cx)
 7870            .file()
 7871            .and_then(|file| Some(file.path().extension()?.to_string()));
 7872
 7873        let event_type = match accepted {
 7874            true => "Edit Prediction Accepted",
 7875            false => "Edit Prediction Discarded",
 7876        };
 7877        telemetry::event!(
 7878            event_type,
 7879            provider = provider.name(),
 7880            prediction_id = id,
 7881            suggestion_accepted = accepted,
 7882            file_extension = extension,
 7883        );
 7884    }
 7885
 7886    fn open_editor_at_anchor(
 7887        snapshot: &language::BufferSnapshot,
 7888        target: language::Anchor,
 7889        workspace: &Entity<Workspace>,
 7890        window: &mut Window,
 7891        cx: &mut App,
 7892    ) -> Task<Result<()>> {
 7893        workspace.update(cx, |workspace, cx| {
 7894            let path = snapshot.file().map(|file| file.full_path(cx));
 7895            let Some(path) =
 7896                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7897            else {
 7898                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7899            };
 7900            let target = text::ToPoint::to_point(&target, snapshot);
 7901            let item = workspace.open_path(path, None, true, window, cx);
 7902            window.spawn(cx, async move |cx| {
 7903                let Some(editor) = item.await?.downcast::<Editor>() else {
 7904                    return Ok(());
 7905                };
 7906                editor
 7907                    .update_in(cx, |editor, window, cx| {
 7908                        editor.go_to_singleton_buffer_point(target, window, cx);
 7909                    })
 7910                    .ok();
 7911                anyhow::Ok(())
 7912            })
 7913        })
 7914    }
 7915
 7916    pub fn has_active_edit_prediction(&self) -> bool {
 7917        self.active_edit_prediction.is_some()
 7918    }
 7919
 7920    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7921        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7922            return false;
 7923        };
 7924
 7925        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7926        self.clear_highlights::<EditPredictionHighlight>(cx);
 7927        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7928        true
 7929    }
 7930
 7931    /// Returns true when we're displaying the edit prediction popover below the cursor
 7932    /// like we are not previewing and the LSP autocomplete menu is visible
 7933    /// or we are in `when_holding_modifier` mode.
 7934    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7935        if self.edit_prediction_preview_is_active()
 7936            || !self.show_edit_predictions_in_menu()
 7937            || !self.edit_predictions_enabled()
 7938        {
 7939            return false;
 7940        }
 7941
 7942        if self.has_visible_completions_menu() {
 7943            return true;
 7944        }
 7945
 7946        has_completion && self.edit_prediction_requires_modifier()
 7947    }
 7948
 7949    fn handle_modifiers_changed(
 7950        &mut self,
 7951        modifiers: Modifiers,
 7952        position_map: &PositionMap,
 7953        window: &mut Window,
 7954        cx: &mut Context<Self>,
 7955    ) {
 7956        // Ensure that the edit prediction preview is updated, even when not
 7957        // enabled, if there's an active edit prediction preview.
 7958        if self.show_edit_predictions_in_menu()
 7959            || matches!(
 7960                self.edit_prediction_preview,
 7961                EditPredictionPreview::Active { .. }
 7962            )
 7963        {
 7964            self.update_edit_prediction_preview(&modifiers, window, cx);
 7965        }
 7966
 7967        self.update_selection_mode(&modifiers, position_map, window, cx);
 7968
 7969        let mouse_position = window.mouse_position();
 7970        if !position_map.text_hitbox.is_hovered(window) {
 7971            return;
 7972        }
 7973
 7974        self.update_hovered_link(
 7975            position_map.point_for_position(mouse_position),
 7976            &position_map.snapshot,
 7977            modifiers,
 7978            window,
 7979            cx,
 7980        )
 7981    }
 7982
 7983    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7984        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7985            MultiCursorModifier::Alt => modifiers.secondary(),
 7986            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7987        }
 7988    }
 7989
 7990    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7991        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7992            MultiCursorModifier::Alt => modifiers.alt,
 7993            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7994        }
 7995    }
 7996
 7997    fn columnar_selection_mode(
 7998        modifiers: &Modifiers,
 7999        cx: &mut Context<Self>,
 8000    ) -> Option<ColumnarMode> {
 8001        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8002            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8003                Some(ColumnarMode::FromMouse)
 8004            } else if Self::is_alt_pressed(modifiers, cx) {
 8005                Some(ColumnarMode::FromSelection)
 8006            } else {
 8007                None
 8008            }
 8009        } else {
 8010            None
 8011        }
 8012    }
 8013
 8014    fn update_selection_mode(
 8015        &mut self,
 8016        modifiers: &Modifiers,
 8017        position_map: &PositionMap,
 8018        window: &mut Window,
 8019        cx: &mut Context<Self>,
 8020    ) {
 8021        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8022            return;
 8023        };
 8024        if self.selections.pending_anchor().is_none() {
 8025            return;
 8026        }
 8027
 8028        let mouse_position = window.mouse_position();
 8029        let point_for_position = position_map.point_for_position(mouse_position);
 8030        let position = point_for_position.previous_valid;
 8031
 8032        self.select(
 8033            SelectPhase::BeginColumnar {
 8034                position,
 8035                reset: false,
 8036                mode,
 8037                goal_column: point_for_position.exact_unclipped.column(),
 8038            },
 8039            window,
 8040            cx,
 8041        );
 8042    }
 8043
 8044    fn update_edit_prediction_preview(
 8045        &mut self,
 8046        modifiers: &Modifiers,
 8047        window: &mut Window,
 8048        cx: &mut Context<Self>,
 8049    ) {
 8050        let mut modifiers_held = false;
 8051
 8052        // Check bindings for all granularities.
 8053        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8054        let granularities = [
 8055            EditPredictionGranularity::Full,
 8056            EditPredictionGranularity::Line,
 8057            EditPredictionGranularity::Word,
 8058        ];
 8059
 8060        for granularity in granularities {
 8061            if let Some(keystroke) = self
 8062                .accept_edit_prediction_keybind(granularity, window, cx)
 8063                .keystroke()
 8064            {
 8065                modifiers_held = modifiers_held
 8066                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8067            }
 8068        }
 8069
 8070        if modifiers_held {
 8071            if matches!(
 8072                self.edit_prediction_preview,
 8073                EditPredictionPreview::Inactive { .. }
 8074            ) {
 8075                self.edit_prediction_preview = EditPredictionPreview::Active {
 8076                    previous_scroll_position: None,
 8077                    since: Instant::now(),
 8078                };
 8079
 8080                self.update_visible_edit_prediction(window, cx);
 8081                cx.notify();
 8082            }
 8083        } else if let EditPredictionPreview::Active {
 8084            previous_scroll_position,
 8085            since,
 8086        } = self.edit_prediction_preview
 8087        {
 8088            if let (Some(previous_scroll_position), Some(position_map)) =
 8089                (previous_scroll_position, self.last_position_map.as_ref())
 8090            {
 8091                self.set_scroll_position(
 8092                    previous_scroll_position
 8093                        .scroll_position(&position_map.snapshot.display_snapshot),
 8094                    window,
 8095                    cx,
 8096                );
 8097            }
 8098
 8099            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8100                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8101            };
 8102            self.clear_row_highlights::<EditPredictionPreview>();
 8103            self.update_visible_edit_prediction(window, cx);
 8104            cx.notify();
 8105        }
 8106    }
 8107
 8108    fn update_visible_edit_prediction(
 8109        &mut self,
 8110        _window: &mut Window,
 8111        cx: &mut Context<Self>,
 8112    ) -> Option<()> {
 8113        if DisableAiSettings::get_global(cx).disable_ai {
 8114            return None;
 8115        }
 8116
 8117        if self.ime_transaction.is_some() {
 8118            self.discard_edit_prediction(false, cx);
 8119            return None;
 8120        }
 8121
 8122        let selection = self.selections.newest_anchor();
 8123        let cursor = selection.head();
 8124        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8125        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8126        let excerpt_id = cursor.excerpt_id;
 8127
 8128        let show_in_menu = self.show_edit_predictions_in_menu();
 8129        let completions_menu_has_precedence = !show_in_menu
 8130            && (self.context_menu.borrow().is_some()
 8131                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8132
 8133        if completions_menu_has_precedence
 8134            || !offset_selection.is_empty()
 8135            || self
 8136                .active_edit_prediction
 8137                .as_ref()
 8138                .is_some_and(|completion| {
 8139                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8140                        return false;
 8141                    };
 8142                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8143                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8144                    !invalidation_range.contains(&offset_selection.head())
 8145                })
 8146        {
 8147            self.discard_edit_prediction(false, cx);
 8148            return None;
 8149        }
 8150
 8151        self.take_active_edit_prediction(cx);
 8152        let Some(provider) = self.edit_prediction_provider() else {
 8153            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8154            return None;
 8155        };
 8156
 8157        let (buffer, cursor_buffer_position) =
 8158            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8159
 8160        self.edit_prediction_settings =
 8161            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8162
 8163        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8164
 8165        if self.edit_prediction_indent_conflict {
 8166            let cursor_point = cursor.to_point(&multibuffer);
 8167            let mut suggested_indent = None;
 8168            multibuffer.suggested_indents_callback(
 8169                cursor_point.row..cursor_point.row + 1,
 8170                |_, indent| {
 8171                    suggested_indent = Some(indent);
 8172                    ControlFlow::Break(())
 8173                },
 8174                cx,
 8175            );
 8176
 8177            if let Some(indent) = suggested_indent
 8178                && indent.len == cursor_point.column
 8179            {
 8180                self.edit_prediction_indent_conflict = false;
 8181            }
 8182        }
 8183
 8184        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8185
 8186        let (completion_id, edits, edit_preview) = match edit_prediction {
 8187            edit_prediction_types::EditPrediction::Local {
 8188                id,
 8189                edits,
 8190                edit_preview,
 8191            } => (id, edits, edit_preview),
 8192            edit_prediction_types::EditPrediction::Jump {
 8193                id,
 8194                snapshot,
 8195                target,
 8196            } => {
 8197                if let Some(provider) = &self.edit_prediction_provider {
 8198                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8199                }
 8200                self.stale_edit_prediction_in_menu = None;
 8201                self.active_edit_prediction = Some(EditPredictionState {
 8202                    inlay_ids: vec![],
 8203                    completion: EditPrediction::MoveOutside { snapshot, target },
 8204                    completion_id: id,
 8205                    invalidation_range: None,
 8206                });
 8207                cx.notify();
 8208                return Some(());
 8209            }
 8210        };
 8211
 8212        let edits = edits
 8213            .into_iter()
 8214            .flat_map(|(range, new_text)| {
 8215                Some((
 8216                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8217                    new_text,
 8218                ))
 8219            })
 8220            .collect::<Vec<_>>();
 8221        if edits.is_empty() {
 8222            return None;
 8223        }
 8224
 8225        let first_edit_start = edits.first().unwrap().0.start;
 8226        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8227        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8228
 8229        let last_edit_end = edits.last().unwrap().0.end;
 8230        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8231        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8232
 8233        let cursor_row = cursor.to_point(&multibuffer).row;
 8234
 8235        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8236
 8237        let mut inlay_ids = Vec::new();
 8238        let invalidation_row_range;
 8239        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8240            Some(cursor_row..edit_end_row)
 8241        } else if cursor_row > edit_end_row {
 8242            Some(edit_start_row..cursor_row)
 8243        } else {
 8244            None
 8245        };
 8246        let supports_jump = self
 8247            .edit_prediction_provider
 8248            .as_ref()
 8249            .map(|provider| provider.provider.supports_jump_to_edit())
 8250            .unwrap_or(true);
 8251
 8252        let is_move = supports_jump
 8253            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8254        let completion = if is_move {
 8255            if let Some(provider) = &self.edit_prediction_provider {
 8256                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8257            }
 8258            invalidation_row_range =
 8259                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8260            let target = first_edit_start;
 8261            EditPrediction::MoveWithin { target, snapshot }
 8262        } else {
 8263            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8264                && !self.edit_predictions_hidden_for_vim_mode;
 8265
 8266            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8267                if provider.show_tab_accept_marker() {
 8268                    EditDisplayMode::TabAccept
 8269                } else {
 8270                    EditDisplayMode::Inline
 8271                }
 8272            } else {
 8273                EditDisplayMode::DiffPopover
 8274            };
 8275
 8276            if show_completions_in_buffer {
 8277                if let Some(provider) = &self.edit_prediction_provider {
 8278                    let suggestion_display_type = match display_mode {
 8279                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8280                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8281                            SuggestionDisplayType::GhostText
 8282                        }
 8283                    };
 8284                    provider.provider.did_show(suggestion_display_type, cx);
 8285                }
 8286                if edits
 8287                    .iter()
 8288                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8289                {
 8290                    let mut inlays = Vec::new();
 8291                    for (range, new_text) in &edits {
 8292                        let inlay = Inlay::edit_prediction(
 8293                            post_inc(&mut self.next_inlay_id),
 8294                            range.start,
 8295                            new_text.as_ref(),
 8296                        );
 8297                        inlay_ids.push(inlay.id);
 8298                        inlays.push(inlay);
 8299                    }
 8300
 8301                    self.splice_inlays(&[], inlays, cx);
 8302                } else {
 8303                    let background_color = cx.theme().status().deleted_background;
 8304                    self.highlight_text::<EditPredictionHighlight>(
 8305                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8306                        HighlightStyle {
 8307                            background_color: Some(background_color),
 8308                            ..Default::default()
 8309                        },
 8310                        cx,
 8311                    );
 8312                }
 8313            }
 8314
 8315            invalidation_row_range = edit_start_row..edit_end_row;
 8316
 8317            EditPrediction::Edit {
 8318                edits,
 8319                edit_preview,
 8320                display_mode,
 8321                snapshot,
 8322            }
 8323        };
 8324
 8325        let invalidation_range = multibuffer
 8326            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8327            ..multibuffer.anchor_after(Point::new(
 8328                invalidation_row_range.end,
 8329                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8330            ));
 8331
 8332        self.stale_edit_prediction_in_menu = None;
 8333        self.active_edit_prediction = Some(EditPredictionState {
 8334            inlay_ids,
 8335            completion,
 8336            completion_id,
 8337            invalidation_range: Some(invalidation_range),
 8338        });
 8339
 8340        cx.notify();
 8341
 8342        Some(())
 8343    }
 8344
 8345    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8346        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8347    }
 8348
 8349    fn clear_tasks(&mut self) {
 8350        self.tasks.clear()
 8351    }
 8352
 8353    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8354        if self.tasks.insert(key, value).is_some() {
 8355            // This case should hopefully be rare, but just in case...
 8356            log::error!(
 8357                "multiple different run targets found on a single line, only the last target will be rendered"
 8358            )
 8359        }
 8360    }
 8361
 8362    /// Get all display points of breakpoints that will be rendered within editor
 8363    ///
 8364    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8365    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8366    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8367    fn active_breakpoints(
 8368        &self,
 8369        range: Range<DisplayRow>,
 8370        window: &mut Window,
 8371        cx: &mut Context<Self>,
 8372    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8373        let mut breakpoint_display_points = HashMap::default();
 8374
 8375        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8376            return breakpoint_display_points;
 8377        };
 8378
 8379        let snapshot = self.snapshot(window, cx);
 8380
 8381        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8382        let Some(project) = self.project() else {
 8383            return breakpoint_display_points;
 8384        };
 8385
 8386        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8387            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8388
 8389        for (buffer_snapshot, range, excerpt_id) in
 8390            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8391        {
 8392            let Some(buffer) = project
 8393                .read(cx)
 8394                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8395            else {
 8396                continue;
 8397            };
 8398            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8399                &buffer,
 8400                Some(
 8401                    buffer_snapshot.anchor_before(range.start)
 8402                        ..buffer_snapshot.anchor_after(range.end),
 8403                ),
 8404                buffer_snapshot,
 8405                cx,
 8406            );
 8407            for (breakpoint, state) in breakpoints {
 8408                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8409                let position = multi_buffer_anchor
 8410                    .to_point(&multi_buffer_snapshot)
 8411                    .to_display_point(&snapshot);
 8412
 8413                breakpoint_display_points.insert(
 8414                    position.row(),
 8415                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8416                );
 8417            }
 8418        }
 8419
 8420        breakpoint_display_points
 8421    }
 8422
 8423    fn breakpoint_context_menu(
 8424        &self,
 8425        anchor: Anchor,
 8426        window: &mut Window,
 8427        cx: &mut Context<Self>,
 8428    ) -> Entity<ui::ContextMenu> {
 8429        let weak_editor = cx.weak_entity();
 8430        let focus_handle = self.focus_handle(cx);
 8431
 8432        let row = self
 8433            .buffer
 8434            .read(cx)
 8435            .snapshot(cx)
 8436            .summary_for_anchor::<Point>(&anchor)
 8437            .row;
 8438
 8439        let breakpoint = self
 8440            .breakpoint_at_row(row, window, cx)
 8441            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8442
 8443        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8444            "Edit Log Breakpoint"
 8445        } else {
 8446            "Set Log Breakpoint"
 8447        };
 8448
 8449        let condition_breakpoint_msg = if breakpoint
 8450            .as_ref()
 8451            .is_some_and(|bp| bp.1.condition.is_some())
 8452        {
 8453            "Edit Condition Breakpoint"
 8454        } else {
 8455            "Set Condition Breakpoint"
 8456        };
 8457
 8458        let hit_condition_breakpoint_msg = if breakpoint
 8459            .as_ref()
 8460            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8461        {
 8462            "Edit Hit Condition Breakpoint"
 8463        } else {
 8464            "Set Hit Condition Breakpoint"
 8465        };
 8466
 8467        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8468            "Unset Breakpoint"
 8469        } else {
 8470            "Set Breakpoint"
 8471        };
 8472
 8473        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8474
 8475        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8476            BreakpointState::Enabled => Some("Disable"),
 8477            BreakpointState::Disabled => Some("Enable"),
 8478        });
 8479
 8480        let (anchor, breakpoint) =
 8481            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8482
 8483        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8484            menu.on_blur_subscription(Subscription::new(|| {}))
 8485                .context(focus_handle)
 8486                .when(run_to_cursor, |this| {
 8487                    let weak_editor = weak_editor.clone();
 8488                    this.entry("Run to cursor", None, move |window, cx| {
 8489                        weak_editor
 8490                            .update(cx, |editor, cx| {
 8491                                editor.change_selections(
 8492                                    SelectionEffects::no_scroll(),
 8493                                    window,
 8494                                    cx,
 8495                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8496                                );
 8497                            })
 8498                            .ok();
 8499
 8500                        window.dispatch_action(Box::new(RunToCursor), cx);
 8501                    })
 8502                    .separator()
 8503                })
 8504                .when_some(toggle_state_msg, |this, msg| {
 8505                    this.entry(msg, None, {
 8506                        let weak_editor = weak_editor.clone();
 8507                        let breakpoint = breakpoint.clone();
 8508                        move |_window, cx| {
 8509                            weak_editor
 8510                                .update(cx, |this, cx| {
 8511                                    this.edit_breakpoint_at_anchor(
 8512                                        anchor,
 8513                                        breakpoint.as_ref().clone(),
 8514                                        BreakpointEditAction::InvertState,
 8515                                        cx,
 8516                                    );
 8517                                })
 8518                                .log_err();
 8519                        }
 8520                    })
 8521                })
 8522                .entry(set_breakpoint_msg, None, {
 8523                    let weak_editor = weak_editor.clone();
 8524                    let breakpoint = breakpoint.clone();
 8525                    move |_window, cx| {
 8526                        weak_editor
 8527                            .update(cx, |this, cx| {
 8528                                this.edit_breakpoint_at_anchor(
 8529                                    anchor,
 8530                                    breakpoint.as_ref().clone(),
 8531                                    BreakpointEditAction::Toggle,
 8532                                    cx,
 8533                                );
 8534                            })
 8535                            .log_err();
 8536                    }
 8537                })
 8538                .entry(log_breakpoint_msg, None, {
 8539                    let breakpoint = breakpoint.clone();
 8540                    let weak_editor = weak_editor.clone();
 8541                    move |window, cx| {
 8542                        weak_editor
 8543                            .update(cx, |this, cx| {
 8544                                this.add_edit_breakpoint_block(
 8545                                    anchor,
 8546                                    breakpoint.as_ref(),
 8547                                    BreakpointPromptEditAction::Log,
 8548                                    window,
 8549                                    cx,
 8550                                );
 8551                            })
 8552                            .log_err();
 8553                    }
 8554                })
 8555                .entry(condition_breakpoint_msg, None, {
 8556                    let breakpoint = breakpoint.clone();
 8557                    let weak_editor = weak_editor.clone();
 8558                    move |window, cx| {
 8559                        weak_editor
 8560                            .update(cx, |this, cx| {
 8561                                this.add_edit_breakpoint_block(
 8562                                    anchor,
 8563                                    breakpoint.as_ref(),
 8564                                    BreakpointPromptEditAction::Condition,
 8565                                    window,
 8566                                    cx,
 8567                                );
 8568                            })
 8569                            .log_err();
 8570                    }
 8571                })
 8572                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8573                    weak_editor
 8574                        .update(cx, |this, cx| {
 8575                            this.add_edit_breakpoint_block(
 8576                                anchor,
 8577                                breakpoint.as_ref(),
 8578                                BreakpointPromptEditAction::HitCondition,
 8579                                window,
 8580                                cx,
 8581                            );
 8582                        })
 8583                        .log_err();
 8584                })
 8585        })
 8586    }
 8587
 8588    fn render_breakpoint(
 8589        &self,
 8590        position: Anchor,
 8591        row: DisplayRow,
 8592        breakpoint: &Breakpoint,
 8593        state: Option<BreakpointSessionState>,
 8594        cx: &mut Context<Self>,
 8595    ) -> IconButton {
 8596        let is_rejected = state.is_some_and(|s| !s.verified);
 8597        // Is it a breakpoint that shows up when hovering over gutter?
 8598        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8599            (false, false),
 8600            |PhantomBreakpointIndicator {
 8601                 is_active,
 8602                 display_row,
 8603                 collides_with_existing_breakpoint,
 8604             }| {
 8605                (
 8606                    is_active && display_row == row,
 8607                    collides_with_existing_breakpoint,
 8608                )
 8609            },
 8610        );
 8611
 8612        let (color, icon) = {
 8613            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8614                (false, false) => ui::IconName::DebugBreakpoint,
 8615                (true, false) => ui::IconName::DebugLogBreakpoint,
 8616                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8617                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8618            };
 8619
 8620            let color = cx.theme().colors();
 8621
 8622            let color = if is_phantom {
 8623                if collides_with_existing {
 8624                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8625                } else {
 8626                    Color::Hint
 8627                }
 8628            } else if is_rejected {
 8629                Color::Disabled
 8630            } else {
 8631                Color::Debugger
 8632            };
 8633
 8634            (color, icon)
 8635        };
 8636
 8637        let breakpoint = Arc::from(breakpoint.clone());
 8638
 8639        let alt_as_text = gpui::Keystroke {
 8640            modifiers: Modifiers::secondary_key(),
 8641            ..Default::default()
 8642        };
 8643        let primary_action_text = if breakpoint.is_disabled() {
 8644            "Enable breakpoint"
 8645        } else if is_phantom && !collides_with_existing {
 8646            "Set breakpoint"
 8647        } else {
 8648            "Unset breakpoint"
 8649        };
 8650        let focus_handle = self.focus_handle.clone();
 8651
 8652        let meta = if is_rejected {
 8653            SharedString::from("No executable code is associated with this line.")
 8654        } else if collides_with_existing && !breakpoint.is_disabled() {
 8655            SharedString::from(format!(
 8656                "{alt_as_text}-click to disable,\nright-click for more options."
 8657            ))
 8658        } else {
 8659            SharedString::from("Right-click for more options.")
 8660        };
 8661        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8662            .icon_size(IconSize::XSmall)
 8663            .size(ui::ButtonSize::None)
 8664            .when(is_rejected, |this| {
 8665                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8666            })
 8667            .icon_color(color)
 8668            .style(ButtonStyle::Transparent)
 8669            .on_click(cx.listener({
 8670                move |editor, event: &ClickEvent, window, cx| {
 8671                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8672                        BreakpointEditAction::InvertState
 8673                    } else {
 8674                        BreakpointEditAction::Toggle
 8675                    };
 8676
 8677                    window.focus(&editor.focus_handle(cx), cx);
 8678                    editor.edit_breakpoint_at_anchor(
 8679                        position,
 8680                        breakpoint.as_ref().clone(),
 8681                        edit_action,
 8682                        cx,
 8683                    );
 8684                }
 8685            }))
 8686            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8687                editor.set_breakpoint_context_menu(
 8688                    row,
 8689                    Some(position),
 8690                    event.position(),
 8691                    window,
 8692                    cx,
 8693                );
 8694            }))
 8695            .tooltip(move |_window, cx| {
 8696                Tooltip::with_meta_in(
 8697                    primary_action_text,
 8698                    Some(&ToggleBreakpoint),
 8699                    meta.clone(),
 8700                    &focus_handle,
 8701                    cx,
 8702                )
 8703            })
 8704    }
 8705
 8706    fn build_tasks_context(
 8707        project: &Entity<Project>,
 8708        buffer: &Entity<Buffer>,
 8709        buffer_row: u32,
 8710        tasks: &Arc<RunnableTasks>,
 8711        cx: &mut Context<Self>,
 8712    ) -> Task<Option<task::TaskContext>> {
 8713        let position = Point::new(buffer_row, tasks.column);
 8714        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8715        let location = Location {
 8716            buffer: buffer.clone(),
 8717            range: range_start..range_start,
 8718        };
 8719        // Fill in the environmental variables from the tree-sitter captures
 8720        let mut captured_task_variables = TaskVariables::default();
 8721        for (capture_name, value) in tasks.extra_variables.clone() {
 8722            captured_task_variables.insert(
 8723                task::VariableName::Custom(capture_name.into()),
 8724                value.clone(),
 8725            );
 8726        }
 8727        project.update(cx, |project, cx| {
 8728            project.task_store().update(cx, |task_store, cx| {
 8729                task_store.task_context_for_location(captured_task_variables, location, cx)
 8730            })
 8731        })
 8732    }
 8733
 8734    pub fn spawn_nearest_task(
 8735        &mut self,
 8736        action: &SpawnNearestTask,
 8737        window: &mut Window,
 8738        cx: &mut Context<Self>,
 8739    ) {
 8740        let Some((workspace, _)) = self.workspace.clone() else {
 8741            return;
 8742        };
 8743        let Some(project) = self.project.clone() else {
 8744            return;
 8745        };
 8746
 8747        // Try to find a closest, enclosing node using tree-sitter that has a task
 8748        let Some((buffer, buffer_row, tasks)) = self
 8749            .find_enclosing_node_task(cx)
 8750            // Or find the task that's closest in row-distance.
 8751            .or_else(|| self.find_closest_task(cx))
 8752        else {
 8753            return;
 8754        };
 8755
 8756        let reveal_strategy = action.reveal;
 8757        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8758        cx.spawn_in(window, async move |_, cx| {
 8759            let context = task_context.await?;
 8760            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8761
 8762            let resolved = &mut resolved_task.resolved;
 8763            resolved.reveal = reveal_strategy;
 8764
 8765            workspace
 8766                .update_in(cx, |workspace, window, cx| {
 8767                    workspace.schedule_resolved_task(
 8768                        task_source_kind,
 8769                        resolved_task,
 8770                        false,
 8771                        window,
 8772                        cx,
 8773                    );
 8774                })
 8775                .ok()
 8776        })
 8777        .detach();
 8778    }
 8779
 8780    fn find_closest_task(
 8781        &mut self,
 8782        cx: &mut Context<Self>,
 8783    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8784        let cursor_row = self
 8785            .selections
 8786            .newest_adjusted(&self.display_snapshot(cx))
 8787            .head()
 8788            .row;
 8789
 8790        let ((buffer_id, row), tasks) = self
 8791            .tasks
 8792            .iter()
 8793            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8794
 8795        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8796        let tasks = Arc::new(tasks.to_owned());
 8797        Some((buffer, *row, tasks))
 8798    }
 8799
 8800    fn find_enclosing_node_task(
 8801        &mut self,
 8802        cx: &mut Context<Self>,
 8803    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8804        let snapshot = self.buffer.read(cx).snapshot(cx);
 8805        let offset = self
 8806            .selections
 8807            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8808            .head();
 8809        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8810        let offset = excerpt.map_offset_to_buffer(offset);
 8811        let buffer_id = excerpt.buffer().remote_id();
 8812
 8813        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8814        let mut cursor = layer.node().walk();
 8815
 8816        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8817            if cursor.node().end_byte() == offset.0 {
 8818                cursor.goto_next_sibling();
 8819            }
 8820        }
 8821
 8822        // Ascend to the smallest ancestor that contains the range and has a task.
 8823        loop {
 8824            let node = cursor.node();
 8825            let node_range = node.byte_range();
 8826            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8827
 8828            // Check if this node contains our offset
 8829            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8830                // If it contains offset, check for task
 8831                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8832                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8833                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8834                }
 8835            }
 8836
 8837            if !cursor.goto_parent() {
 8838                break;
 8839            }
 8840        }
 8841        None
 8842    }
 8843
 8844    fn render_run_indicator(
 8845        &self,
 8846        _style: &EditorStyle,
 8847        is_active: bool,
 8848        row: DisplayRow,
 8849        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8850        cx: &mut Context<Self>,
 8851    ) -> IconButton {
 8852        let color = Color::Muted;
 8853        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8854
 8855        IconButton::new(
 8856            ("run_indicator", row.0 as usize),
 8857            ui::IconName::PlayOutlined,
 8858        )
 8859        .shape(ui::IconButtonShape::Square)
 8860        .icon_size(IconSize::XSmall)
 8861        .icon_color(color)
 8862        .toggle_state(is_active)
 8863        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8864            let quick_launch = match e {
 8865                ClickEvent::Keyboard(_) => true,
 8866                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8867            };
 8868
 8869            window.focus(&editor.focus_handle(cx), cx);
 8870            editor.toggle_code_actions(
 8871                &ToggleCodeActions {
 8872                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8873                    quick_launch,
 8874                },
 8875                window,
 8876                cx,
 8877            );
 8878        }))
 8879        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8880            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8881        }))
 8882    }
 8883
 8884    pub fn context_menu_visible(&self) -> bool {
 8885        !self.edit_prediction_preview_is_active()
 8886            && self
 8887                .context_menu
 8888                .borrow()
 8889                .as_ref()
 8890                .is_some_and(|menu| menu.visible())
 8891    }
 8892
 8893    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8894        self.context_menu
 8895            .borrow()
 8896            .as_ref()
 8897            .map(|menu| menu.origin())
 8898    }
 8899
 8900    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8901        self.context_menu_options = Some(options);
 8902    }
 8903
 8904    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8905    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8906
 8907    fn render_edit_prediction_popover(
 8908        &mut self,
 8909        text_bounds: &Bounds<Pixels>,
 8910        content_origin: gpui::Point<Pixels>,
 8911        right_margin: Pixels,
 8912        editor_snapshot: &EditorSnapshot,
 8913        visible_row_range: Range<DisplayRow>,
 8914        scroll_top: ScrollOffset,
 8915        scroll_bottom: ScrollOffset,
 8916        line_layouts: &[LineWithInvisibles],
 8917        line_height: Pixels,
 8918        scroll_position: gpui::Point<ScrollOffset>,
 8919        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8920        newest_selection_head: Option<DisplayPoint>,
 8921        editor_width: Pixels,
 8922        style: &EditorStyle,
 8923        window: &mut Window,
 8924        cx: &mut App,
 8925    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8926        if self.mode().is_minimap() {
 8927            return None;
 8928        }
 8929        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8930
 8931        if self.edit_prediction_visible_in_cursor_popover(true) {
 8932            return None;
 8933        }
 8934
 8935        match &active_edit_prediction.completion {
 8936            EditPrediction::MoveWithin { target, .. } => {
 8937                let target_display_point = target.to_display_point(editor_snapshot);
 8938
 8939                if self.edit_prediction_requires_modifier() {
 8940                    if !self.edit_prediction_preview_is_active() {
 8941                        return None;
 8942                    }
 8943
 8944                    self.render_edit_prediction_modifier_jump_popover(
 8945                        text_bounds,
 8946                        content_origin,
 8947                        visible_row_range,
 8948                        line_layouts,
 8949                        line_height,
 8950                        scroll_pixel_position,
 8951                        newest_selection_head,
 8952                        target_display_point,
 8953                        window,
 8954                        cx,
 8955                    )
 8956                } else {
 8957                    self.render_edit_prediction_eager_jump_popover(
 8958                        text_bounds,
 8959                        content_origin,
 8960                        editor_snapshot,
 8961                        visible_row_range,
 8962                        scroll_top,
 8963                        scroll_bottom,
 8964                        line_height,
 8965                        scroll_pixel_position,
 8966                        target_display_point,
 8967                        editor_width,
 8968                        window,
 8969                        cx,
 8970                    )
 8971                }
 8972            }
 8973            EditPrediction::Edit {
 8974                display_mode: EditDisplayMode::Inline,
 8975                ..
 8976            } => None,
 8977            EditPrediction::Edit {
 8978                display_mode: EditDisplayMode::TabAccept,
 8979                edits,
 8980                ..
 8981            } => {
 8982                let range = &edits.first()?.0;
 8983                let target_display_point = range.end.to_display_point(editor_snapshot);
 8984
 8985                self.render_edit_prediction_end_of_line_popover(
 8986                    "Accept",
 8987                    editor_snapshot,
 8988                    visible_row_range,
 8989                    target_display_point,
 8990                    line_height,
 8991                    scroll_pixel_position,
 8992                    content_origin,
 8993                    editor_width,
 8994                    window,
 8995                    cx,
 8996                )
 8997            }
 8998            EditPrediction::Edit {
 8999                edits,
 9000                edit_preview,
 9001                display_mode: EditDisplayMode::DiffPopover,
 9002                snapshot,
 9003            } => self.render_edit_prediction_diff_popover(
 9004                text_bounds,
 9005                content_origin,
 9006                right_margin,
 9007                editor_snapshot,
 9008                visible_row_range,
 9009                line_layouts,
 9010                line_height,
 9011                scroll_position,
 9012                scroll_pixel_position,
 9013                newest_selection_head,
 9014                editor_width,
 9015                style,
 9016                edits,
 9017                edit_preview,
 9018                snapshot,
 9019                window,
 9020                cx,
 9021            ),
 9022            EditPrediction::MoveOutside { snapshot, .. } => {
 9023                let mut element = self
 9024                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9025                    .into_any();
 9026
 9027                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9028                let origin_x = text_bounds.size.width - size.width - px(30.);
 9029                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9030                element.prepaint_at(origin, window, cx);
 9031
 9032                Some((element, origin))
 9033            }
 9034        }
 9035    }
 9036
 9037    fn render_edit_prediction_modifier_jump_popover(
 9038        &mut self,
 9039        text_bounds: &Bounds<Pixels>,
 9040        content_origin: gpui::Point<Pixels>,
 9041        visible_row_range: Range<DisplayRow>,
 9042        line_layouts: &[LineWithInvisibles],
 9043        line_height: Pixels,
 9044        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9045        newest_selection_head: Option<DisplayPoint>,
 9046        target_display_point: DisplayPoint,
 9047        window: &mut Window,
 9048        cx: &mut App,
 9049    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9050        let scrolled_content_origin =
 9051            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9052
 9053        const SCROLL_PADDING_Y: Pixels = px(12.);
 9054
 9055        if target_display_point.row() < visible_row_range.start {
 9056            return self.render_edit_prediction_scroll_popover(
 9057                |_| SCROLL_PADDING_Y,
 9058                IconName::ArrowUp,
 9059                visible_row_range,
 9060                line_layouts,
 9061                newest_selection_head,
 9062                scrolled_content_origin,
 9063                window,
 9064                cx,
 9065            );
 9066        } else if target_display_point.row() >= visible_row_range.end {
 9067            return self.render_edit_prediction_scroll_popover(
 9068                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9069                IconName::ArrowDown,
 9070                visible_row_range,
 9071                line_layouts,
 9072                newest_selection_head,
 9073                scrolled_content_origin,
 9074                window,
 9075                cx,
 9076            );
 9077        }
 9078
 9079        const POLE_WIDTH: Pixels = px(2.);
 9080
 9081        let line_layout =
 9082            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9083        let target_column = target_display_point.column() as usize;
 9084
 9085        let target_x = line_layout.x_for_index(target_column);
 9086        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9087            - scroll_pixel_position.y;
 9088
 9089        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9090
 9091        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9092        border_color.l += 0.001;
 9093
 9094        let mut element = v_flex()
 9095            .items_end()
 9096            .when(flag_on_right, |el| el.items_start())
 9097            .child(if flag_on_right {
 9098                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9099                    .rounded_bl(px(0.))
 9100                    .rounded_tl(px(0.))
 9101                    .border_l_2()
 9102                    .border_color(border_color)
 9103            } else {
 9104                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9105                    .rounded_br(px(0.))
 9106                    .rounded_tr(px(0.))
 9107                    .border_r_2()
 9108                    .border_color(border_color)
 9109            })
 9110            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9111            .into_any();
 9112
 9113        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9114
 9115        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9116            - point(
 9117                if flag_on_right {
 9118                    POLE_WIDTH
 9119                } else {
 9120                    size.width - POLE_WIDTH
 9121                },
 9122                size.height - line_height,
 9123            );
 9124
 9125        origin.x = origin.x.max(content_origin.x);
 9126
 9127        element.prepaint_at(origin, window, cx);
 9128
 9129        Some((element, origin))
 9130    }
 9131
 9132    fn render_edit_prediction_scroll_popover(
 9133        &mut self,
 9134        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9135        scroll_icon: IconName,
 9136        visible_row_range: Range<DisplayRow>,
 9137        line_layouts: &[LineWithInvisibles],
 9138        newest_selection_head: Option<DisplayPoint>,
 9139        scrolled_content_origin: gpui::Point<Pixels>,
 9140        window: &mut Window,
 9141        cx: &mut App,
 9142    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9143        let mut element = self
 9144            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9145            .into_any();
 9146
 9147        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9148
 9149        let cursor = newest_selection_head?;
 9150        let cursor_row_layout =
 9151            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9152        let cursor_column = cursor.column() as usize;
 9153
 9154        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9155
 9156        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9157
 9158        element.prepaint_at(origin, window, cx);
 9159        Some((element, origin))
 9160    }
 9161
 9162    fn render_edit_prediction_eager_jump_popover(
 9163        &mut self,
 9164        text_bounds: &Bounds<Pixels>,
 9165        content_origin: gpui::Point<Pixels>,
 9166        editor_snapshot: &EditorSnapshot,
 9167        visible_row_range: Range<DisplayRow>,
 9168        scroll_top: ScrollOffset,
 9169        scroll_bottom: ScrollOffset,
 9170        line_height: Pixels,
 9171        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9172        target_display_point: DisplayPoint,
 9173        editor_width: Pixels,
 9174        window: &mut Window,
 9175        cx: &mut App,
 9176    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9177        if target_display_point.row().as_f64() < scroll_top {
 9178            let mut element = self
 9179                .render_edit_prediction_line_popover(
 9180                    "Jump to Edit",
 9181                    Some(IconName::ArrowUp),
 9182                    window,
 9183                    cx,
 9184                )
 9185                .into_any();
 9186
 9187            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9188            let offset = point(
 9189                (text_bounds.size.width - size.width) / 2.,
 9190                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9191            );
 9192
 9193            let origin = text_bounds.origin + offset;
 9194            element.prepaint_at(origin, window, cx);
 9195            Some((element, origin))
 9196        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9197            let mut element = self
 9198                .render_edit_prediction_line_popover(
 9199                    "Jump to Edit",
 9200                    Some(IconName::ArrowDown),
 9201                    window,
 9202                    cx,
 9203                )
 9204                .into_any();
 9205
 9206            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9207            let offset = point(
 9208                (text_bounds.size.width - size.width) / 2.,
 9209                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9210            );
 9211
 9212            let origin = text_bounds.origin + offset;
 9213            element.prepaint_at(origin, window, cx);
 9214            Some((element, origin))
 9215        } else {
 9216            self.render_edit_prediction_end_of_line_popover(
 9217                "Jump to Edit",
 9218                editor_snapshot,
 9219                visible_row_range,
 9220                target_display_point,
 9221                line_height,
 9222                scroll_pixel_position,
 9223                content_origin,
 9224                editor_width,
 9225                window,
 9226                cx,
 9227            )
 9228        }
 9229    }
 9230
 9231    fn render_edit_prediction_end_of_line_popover(
 9232        self: &mut Editor,
 9233        label: &'static str,
 9234        editor_snapshot: &EditorSnapshot,
 9235        visible_row_range: Range<DisplayRow>,
 9236        target_display_point: DisplayPoint,
 9237        line_height: Pixels,
 9238        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9239        content_origin: gpui::Point<Pixels>,
 9240        editor_width: Pixels,
 9241        window: &mut Window,
 9242        cx: &mut App,
 9243    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9244        let target_line_end = DisplayPoint::new(
 9245            target_display_point.row(),
 9246            editor_snapshot.line_len(target_display_point.row()),
 9247        );
 9248
 9249        let mut element = self
 9250            .render_edit_prediction_line_popover(label, None, window, cx)
 9251            .into_any();
 9252
 9253        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9254
 9255        let line_origin =
 9256            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9257
 9258        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9259        let mut origin = start_point
 9260            + line_origin
 9261            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9262        origin.x = origin.x.max(content_origin.x);
 9263
 9264        let max_x = content_origin.x + editor_width - size.width;
 9265
 9266        if origin.x > max_x {
 9267            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9268
 9269            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9270                origin.y += offset;
 9271                IconName::ArrowUp
 9272            } else {
 9273                origin.y -= offset;
 9274                IconName::ArrowDown
 9275            };
 9276
 9277            element = self
 9278                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9279                .into_any();
 9280
 9281            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9282
 9283            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9284        }
 9285
 9286        element.prepaint_at(origin, window, cx);
 9287        Some((element, origin))
 9288    }
 9289
 9290    fn render_edit_prediction_diff_popover(
 9291        self: &Editor,
 9292        text_bounds: &Bounds<Pixels>,
 9293        content_origin: gpui::Point<Pixels>,
 9294        right_margin: Pixels,
 9295        editor_snapshot: &EditorSnapshot,
 9296        visible_row_range: Range<DisplayRow>,
 9297        line_layouts: &[LineWithInvisibles],
 9298        line_height: Pixels,
 9299        scroll_position: gpui::Point<ScrollOffset>,
 9300        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9301        newest_selection_head: Option<DisplayPoint>,
 9302        editor_width: Pixels,
 9303        style: &EditorStyle,
 9304        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9305        edit_preview: &Option<language::EditPreview>,
 9306        snapshot: &language::BufferSnapshot,
 9307        window: &mut Window,
 9308        cx: &mut App,
 9309    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9310        let edit_start = edits
 9311            .first()
 9312            .unwrap()
 9313            .0
 9314            .start
 9315            .to_display_point(editor_snapshot);
 9316        let edit_end = edits
 9317            .last()
 9318            .unwrap()
 9319            .0
 9320            .end
 9321            .to_display_point(editor_snapshot);
 9322
 9323        let is_visible = visible_row_range.contains(&edit_start.row())
 9324            || visible_row_range.contains(&edit_end.row());
 9325        if !is_visible {
 9326            return None;
 9327        }
 9328
 9329        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9330            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9331        } else {
 9332            // Fallback for providers without edit_preview
 9333            crate::edit_prediction_fallback_text(edits, cx)
 9334        };
 9335
 9336        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9337        let line_count = highlighted_edits.text.lines().count();
 9338
 9339        const BORDER_WIDTH: Pixels = px(1.);
 9340
 9341        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9342        let has_keybind = keybind.is_some();
 9343
 9344        let mut element = h_flex()
 9345            .items_start()
 9346            .child(
 9347                h_flex()
 9348                    .bg(cx.theme().colors().editor_background)
 9349                    .border(BORDER_WIDTH)
 9350                    .shadow_xs()
 9351                    .border_color(cx.theme().colors().border)
 9352                    .rounded_l_lg()
 9353                    .when(line_count > 1, |el| el.rounded_br_lg())
 9354                    .pr_1()
 9355                    .child(styled_text),
 9356            )
 9357            .child(
 9358                h_flex()
 9359                    .h(line_height + BORDER_WIDTH * 2.)
 9360                    .px_1p5()
 9361                    .gap_1()
 9362                    // Workaround: For some reason, there's a gap if we don't do this
 9363                    .ml(-BORDER_WIDTH)
 9364                    .shadow(vec![gpui::BoxShadow {
 9365                        color: gpui::black().opacity(0.05),
 9366                        offset: point(px(1.), px(1.)),
 9367                        blur_radius: px(2.),
 9368                        spread_radius: px(0.),
 9369                    }])
 9370                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9371                    .border(BORDER_WIDTH)
 9372                    .border_color(cx.theme().colors().border)
 9373                    .rounded_r_lg()
 9374                    .id("edit_prediction_diff_popover_keybind")
 9375                    .when(!has_keybind, |el| {
 9376                        let status_colors = cx.theme().status();
 9377
 9378                        el.bg(status_colors.error_background)
 9379                            .border_color(status_colors.error.opacity(0.6))
 9380                            .child(Icon::new(IconName::Info).color(Color::Error))
 9381                            .cursor_default()
 9382                            .hoverable_tooltip(move |_window, cx| {
 9383                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9384                            })
 9385                    })
 9386                    .children(keybind),
 9387            )
 9388            .into_any();
 9389
 9390        let longest_row =
 9391            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9392        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9393            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9394        } else {
 9395            layout_line(
 9396                longest_row,
 9397                editor_snapshot,
 9398                style,
 9399                editor_width,
 9400                |_| false,
 9401                window,
 9402                cx,
 9403            )
 9404            .width
 9405        };
 9406
 9407        let viewport_bounds =
 9408            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9409                right: -right_margin,
 9410                ..Default::default()
 9411            });
 9412
 9413        let x_after_longest = Pixels::from(
 9414            ScrollPixelOffset::from(
 9415                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9416            ) - scroll_pixel_position.x,
 9417        );
 9418
 9419        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9420
 9421        // Fully visible if it can be displayed within the window (allow overlapping other
 9422        // panes). However, this is only allowed if the popover starts within text_bounds.
 9423        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9424            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9425
 9426        let mut origin = if can_position_to_the_right {
 9427            point(
 9428                x_after_longest,
 9429                text_bounds.origin.y
 9430                    + Pixels::from(
 9431                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9432                            - scroll_pixel_position.y,
 9433                    ),
 9434            )
 9435        } else {
 9436            let cursor_row = newest_selection_head.map(|head| head.row());
 9437            let above_edit = edit_start
 9438                .row()
 9439                .0
 9440                .checked_sub(line_count as u32)
 9441                .map(DisplayRow);
 9442            let below_edit = Some(edit_end.row() + 1);
 9443            let above_cursor =
 9444                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9445            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9446
 9447            // Place the edit popover adjacent to the edit if there is a location
 9448            // available that is onscreen and does not obscure the cursor. Otherwise,
 9449            // place it adjacent to the cursor.
 9450            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9451                .into_iter()
 9452                .flatten()
 9453                .find(|&start_row| {
 9454                    let end_row = start_row + line_count as u32;
 9455                    visible_row_range.contains(&start_row)
 9456                        && visible_row_range.contains(&end_row)
 9457                        && cursor_row
 9458                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9459                })?;
 9460
 9461            content_origin
 9462                + point(
 9463                    Pixels::from(-scroll_pixel_position.x),
 9464                    Pixels::from(
 9465                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9466                    ),
 9467                )
 9468        };
 9469
 9470        origin.x -= BORDER_WIDTH;
 9471
 9472        window.defer_draw(element, origin, 1);
 9473
 9474        // Do not return an element, since it will already be drawn due to defer_draw.
 9475        None
 9476    }
 9477
 9478    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9479        px(30.)
 9480    }
 9481
 9482    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9483        if self.read_only(cx) {
 9484            cx.theme().players().read_only()
 9485        } else {
 9486            self.style.as_ref().unwrap().local_player
 9487        }
 9488    }
 9489
 9490    fn render_edit_prediction_accept_keybind(
 9491        &self,
 9492        window: &mut Window,
 9493        cx: &mut App,
 9494    ) -> Option<AnyElement> {
 9495        let accept_binding =
 9496            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9497        let accept_keystroke = accept_binding.keystroke()?;
 9498
 9499        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9500
 9501        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9502            Color::Accent
 9503        } else {
 9504            Color::Muted
 9505        };
 9506
 9507        h_flex()
 9508            .px_0p5()
 9509            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9510            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9511            .text_size(TextSize::XSmall.rems(cx))
 9512            .child(h_flex().children(ui::render_modifiers(
 9513                accept_keystroke.modifiers(),
 9514                PlatformStyle::platform(),
 9515                Some(modifiers_color),
 9516                Some(IconSize::XSmall.rems().into()),
 9517                true,
 9518            )))
 9519            .when(is_platform_style_mac, |parent| {
 9520                parent.child(accept_keystroke.key().to_string())
 9521            })
 9522            .when(!is_platform_style_mac, |parent| {
 9523                parent.child(
 9524                    Key::new(
 9525                        util::capitalize(accept_keystroke.key()),
 9526                        Some(Color::Default),
 9527                    )
 9528                    .size(Some(IconSize::XSmall.rems().into())),
 9529                )
 9530            })
 9531            .into_any()
 9532            .into()
 9533    }
 9534
 9535    fn render_edit_prediction_line_popover(
 9536        &self,
 9537        label: impl Into<SharedString>,
 9538        icon: Option<IconName>,
 9539        window: &mut Window,
 9540        cx: &mut App,
 9541    ) -> Stateful<Div> {
 9542        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9543
 9544        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9545        let has_keybind = keybind.is_some();
 9546
 9547        h_flex()
 9548            .id("ep-line-popover")
 9549            .py_0p5()
 9550            .pl_1()
 9551            .pr(padding_right)
 9552            .gap_1()
 9553            .rounded_md()
 9554            .border_1()
 9555            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9556            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9557            .shadow_xs()
 9558            .when(!has_keybind, |el| {
 9559                let status_colors = cx.theme().status();
 9560
 9561                el.bg(status_colors.error_background)
 9562                    .border_color(status_colors.error.opacity(0.6))
 9563                    .pl_2()
 9564                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9565                    .cursor_default()
 9566                    .hoverable_tooltip(move |_window, cx| {
 9567                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9568                    })
 9569            })
 9570            .children(keybind)
 9571            .child(
 9572                Label::new(label)
 9573                    .size(LabelSize::Small)
 9574                    .when(!has_keybind, |el| {
 9575                        el.color(cx.theme().status().error.into()).strikethrough()
 9576                    }),
 9577            )
 9578            .when(!has_keybind, |el| {
 9579                el.child(
 9580                    h_flex().ml_1().child(
 9581                        Icon::new(IconName::Info)
 9582                            .size(IconSize::Small)
 9583                            .color(cx.theme().status().error.into()),
 9584                    ),
 9585                )
 9586            })
 9587            .when_some(icon, |element, icon| {
 9588                element.child(
 9589                    div()
 9590                        .mt(px(1.5))
 9591                        .child(Icon::new(icon).size(IconSize::Small)),
 9592                )
 9593            })
 9594    }
 9595
 9596    fn render_edit_prediction_jump_outside_popover(
 9597        &self,
 9598        snapshot: &BufferSnapshot,
 9599        window: &mut Window,
 9600        cx: &mut App,
 9601    ) -> Stateful<Div> {
 9602        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9603        let has_keybind = keybind.is_some();
 9604
 9605        let file_name = snapshot
 9606            .file()
 9607            .map(|file| SharedString::new(file.file_name(cx)))
 9608            .unwrap_or(SharedString::new_static("untitled"));
 9609
 9610        h_flex()
 9611            .id("ep-jump-outside-popover")
 9612            .py_1()
 9613            .px_2()
 9614            .gap_1()
 9615            .rounded_md()
 9616            .border_1()
 9617            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9618            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9619            .shadow_xs()
 9620            .when(!has_keybind, |el| {
 9621                let status_colors = cx.theme().status();
 9622
 9623                el.bg(status_colors.error_background)
 9624                    .border_color(status_colors.error.opacity(0.6))
 9625                    .pl_2()
 9626                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9627                    .cursor_default()
 9628                    .hoverable_tooltip(move |_window, cx| {
 9629                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9630                    })
 9631            })
 9632            .children(keybind)
 9633            .child(
 9634                Label::new(file_name)
 9635                    .size(LabelSize::Small)
 9636                    .buffer_font(cx)
 9637                    .when(!has_keybind, |el| {
 9638                        el.color(cx.theme().status().error.into()).strikethrough()
 9639                    }),
 9640            )
 9641            .when(!has_keybind, |el| {
 9642                el.child(
 9643                    h_flex().ml_1().child(
 9644                        Icon::new(IconName::Info)
 9645                            .size(IconSize::Small)
 9646                            .color(cx.theme().status().error.into()),
 9647                    ),
 9648                )
 9649            })
 9650            .child(
 9651                div()
 9652                    .mt(px(1.5))
 9653                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9654            )
 9655    }
 9656
 9657    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9658        let accent_color = cx.theme().colors().text_accent;
 9659        let editor_bg_color = cx.theme().colors().editor_background;
 9660        editor_bg_color.blend(accent_color.opacity(0.1))
 9661    }
 9662
 9663    fn edit_prediction_callout_popover_border_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.6))
 9667    }
 9668    fn get_prediction_provider_icon_name(
 9669        provider: &Option<RegisteredEditPredictionDelegate>,
 9670    ) -> IconName {
 9671        match provider {
 9672            Some(provider) => match provider.provider.name() {
 9673                "copilot" => IconName::Copilot,
 9674                "supermaven" => IconName::Supermaven,
 9675                _ => IconName::ZedPredict,
 9676            },
 9677            None => IconName::ZedPredict,
 9678        }
 9679    }
 9680
 9681    fn render_edit_prediction_cursor_popover(
 9682        &self,
 9683        min_width: Pixels,
 9684        max_width: Pixels,
 9685        cursor_point: Point,
 9686        style: &EditorStyle,
 9687        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9688        _window: &Window,
 9689        cx: &mut Context<Editor>,
 9690    ) -> Option<AnyElement> {
 9691        let provider = self.edit_prediction_provider.as_ref()?;
 9692        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9693
 9694        let is_refreshing = provider.provider.is_refreshing(cx);
 9695
 9696        fn pending_completion_container(icon: IconName) -> Div {
 9697            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9698        }
 9699
 9700        let completion = match &self.active_edit_prediction {
 9701            Some(prediction) => {
 9702                if !self.has_visible_completions_menu() {
 9703                    const RADIUS: Pixels = px(6.);
 9704                    const BORDER_WIDTH: Pixels = px(1.);
 9705
 9706                    return Some(
 9707                        h_flex()
 9708                            .elevation_2(cx)
 9709                            .border(BORDER_WIDTH)
 9710                            .border_color(cx.theme().colors().border)
 9711                            .when(accept_keystroke.is_none(), |el| {
 9712                                el.border_color(cx.theme().status().error)
 9713                            })
 9714                            .rounded(RADIUS)
 9715                            .rounded_tl(px(0.))
 9716                            .overflow_hidden()
 9717                            .child(div().px_1p5().child(match &prediction.completion {
 9718                                EditPrediction::MoveWithin { target, snapshot } => {
 9719                                    use text::ToPoint as _;
 9720                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9721                                    {
 9722                                        Icon::new(IconName::ZedPredictDown)
 9723                                    } else {
 9724                                        Icon::new(IconName::ZedPredictUp)
 9725                                    }
 9726                                }
 9727                                EditPrediction::MoveOutside { .. } => {
 9728                                    // TODO [zeta2] custom icon for external jump?
 9729                                    Icon::new(provider_icon)
 9730                                }
 9731                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9732                            }))
 9733                            .child(
 9734                                h_flex()
 9735                                    .gap_1()
 9736                                    .py_1()
 9737                                    .px_2()
 9738                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9739                                    .border_l_1()
 9740                                    .border_color(cx.theme().colors().border)
 9741                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9742                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9743                                        el.child(
 9744                                            Label::new("Hold")
 9745                                                .size(LabelSize::Small)
 9746                                                .when(accept_keystroke.is_none(), |el| {
 9747                                                    el.strikethrough()
 9748                                                })
 9749                                                .line_height_style(LineHeightStyle::UiLabel),
 9750                                        )
 9751                                    })
 9752                                    .id("edit_prediction_cursor_popover_keybind")
 9753                                    .when(accept_keystroke.is_none(), |el| {
 9754                                        let status_colors = cx.theme().status();
 9755
 9756                                        el.bg(status_colors.error_background)
 9757                                            .border_color(status_colors.error.opacity(0.6))
 9758                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9759                                            .cursor_default()
 9760                                            .hoverable_tooltip(move |_window, cx| {
 9761                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9762                                                    .into()
 9763                                            })
 9764                                    })
 9765                                    .when_some(
 9766                                        accept_keystroke.as_ref(),
 9767                                        |el, accept_keystroke| {
 9768                                            el.child(h_flex().children(ui::render_modifiers(
 9769                                                accept_keystroke.modifiers(),
 9770                                                PlatformStyle::platform(),
 9771                                                Some(Color::Default),
 9772                                                Some(IconSize::XSmall.rems().into()),
 9773                                                false,
 9774                                            )))
 9775                                        },
 9776                                    ),
 9777                            )
 9778                            .into_any(),
 9779                    );
 9780                }
 9781
 9782                self.render_edit_prediction_cursor_popover_preview(
 9783                    prediction,
 9784                    cursor_point,
 9785                    style,
 9786                    cx,
 9787                )?
 9788            }
 9789
 9790            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9791                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9792                    stale_completion,
 9793                    cursor_point,
 9794                    style,
 9795                    cx,
 9796                )?,
 9797
 9798                None => pending_completion_container(provider_icon)
 9799                    .child(Label::new("...").size(LabelSize::Small)),
 9800            },
 9801
 9802            None => pending_completion_container(provider_icon)
 9803                .child(Label::new("...").size(LabelSize::Small)),
 9804        };
 9805
 9806        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9807            completion
 9808                .with_animation(
 9809                    "loading-completion",
 9810                    Animation::new(Duration::from_secs(2))
 9811                        .repeat()
 9812                        .with_easing(pulsating_between(0.4, 0.8)),
 9813                    |label, delta| label.opacity(delta),
 9814                )
 9815                .into_any_element()
 9816        } else {
 9817            completion.into_any_element()
 9818        };
 9819
 9820        let has_completion = self.active_edit_prediction.is_some();
 9821
 9822        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9823        Some(
 9824            h_flex()
 9825                .min_w(min_width)
 9826                .max_w(max_width)
 9827                .flex_1()
 9828                .elevation_2(cx)
 9829                .border_color(cx.theme().colors().border)
 9830                .child(
 9831                    div()
 9832                        .flex_1()
 9833                        .py_1()
 9834                        .px_2()
 9835                        .overflow_hidden()
 9836                        .child(completion),
 9837                )
 9838                .when_some(accept_keystroke, |el, accept_keystroke| {
 9839                    if !accept_keystroke.modifiers().modified() {
 9840                        return el;
 9841                    }
 9842
 9843                    el.child(
 9844                        h_flex()
 9845                            .h_full()
 9846                            .border_l_1()
 9847                            .rounded_r_lg()
 9848                            .border_color(cx.theme().colors().border)
 9849                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9850                            .gap_1()
 9851                            .py_1()
 9852                            .px_2()
 9853                            .child(
 9854                                h_flex()
 9855                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9856                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9857                                    .child(h_flex().children(ui::render_modifiers(
 9858                                        accept_keystroke.modifiers(),
 9859                                        PlatformStyle::platform(),
 9860                                        Some(if !has_completion {
 9861                                            Color::Muted
 9862                                        } else {
 9863                                            Color::Default
 9864                                        }),
 9865                                        None,
 9866                                        false,
 9867                                    ))),
 9868                            )
 9869                            .child(Label::new("Preview").into_any_element())
 9870                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9871                    )
 9872                })
 9873                .into_any(),
 9874        )
 9875    }
 9876
 9877    fn render_edit_prediction_cursor_popover_preview(
 9878        &self,
 9879        completion: &EditPredictionState,
 9880        cursor_point: Point,
 9881        style: &EditorStyle,
 9882        cx: &mut Context<Editor>,
 9883    ) -> Option<Div> {
 9884        use text::ToPoint as _;
 9885
 9886        fn render_relative_row_jump(
 9887            prefix: impl Into<String>,
 9888            current_row: u32,
 9889            target_row: u32,
 9890        ) -> Div {
 9891            let (row_diff, arrow) = if target_row < current_row {
 9892                (current_row - target_row, IconName::ArrowUp)
 9893            } else {
 9894                (target_row - current_row, IconName::ArrowDown)
 9895            };
 9896
 9897            h_flex()
 9898                .child(
 9899                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9900                        .color(Color::Muted)
 9901                        .size(LabelSize::Small),
 9902                )
 9903                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9904        }
 9905
 9906        let supports_jump = self
 9907            .edit_prediction_provider
 9908            .as_ref()
 9909            .map(|provider| provider.provider.supports_jump_to_edit())
 9910            .unwrap_or(true);
 9911
 9912        match &completion.completion {
 9913            EditPrediction::MoveWithin {
 9914                target, snapshot, ..
 9915            } => {
 9916                if !supports_jump {
 9917                    return None;
 9918                }
 9919
 9920                Some(
 9921                    h_flex()
 9922                        .px_2()
 9923                        .gap_2()
 9924                        .flex_1()
 9925                        .child(
 9926                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9927                                Icon::new(IconName::ZedPredictDown)
 9928                            } else {
 9929                                Icon::new(IconName::ZedPredictUp)
 9930                            },
 9931                        )
 9932                        .child(Label::new("Jump to Edit")),
 9933                )
 9934            }
 9935            EditPrediction::MoveOutside { snapshot, .. } => {
 9936                let file_name = snapshot
 9937                    .file()
 9938                    .map(|file| file.file_name(cx))
 9939                    .unwrap_or("untitled");
 9940                Some(
 9941                    h_flex()
 9942                        .px_2()
 9943                        .gap_2()
 9944                        .flex_1()
 9945                        .child(Icon::new(IconName::ZedPredict))
 9946                        .child(Label::new(format!("Jump to {file_name}"))),
 9947                )
 9948            }
 9949            EditPrediction::Edit {
 9950                edits,
 9951                edit_preview,
 9952                snapshot,
 9953                display_mode: _,
 9954            } => {
 9955                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9956
 9957                let (highlighted_edits, has_more_lines) =
 9958                    if let Some(edit_preview) = edit_preview.as_ref() {
 9959                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9960                            .first_line_preview()
 9961                    } else {
 9962                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9963                    };
 9964
 9965                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9966                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9967
 9968                let preview = h_flex()
 9969                    .gap_1()
 9970                    .min_w_16()
 9971                    .child(styled_text)
 9972                    .when(has_more_lines, |parent| parent.child(""));
 9973
 9974                let left = if supports_jump && first_edit_row != cursor_point.row {
 9975                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9976                        .into_any_element()
 9977                } else {
 9978                    let icon_name =
 9979                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9980                    Icon::new(icon_name).into_any_element()
 9981                };
 9982
 9983                Some(
 9984                    h_flex()
 9985                        .h_full()
 9986                        .flex_1()
 9987                        .gap_2()
 9988                        .pr_1()
 9989                        .overflow_x_hidden()
 9990                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9991                        .child(left)
 9992                        .child(preview),
 9993                )
 9994            }
 9995        }
 9996    }
 9997
 9998    pub fn render_context_menu(
 9999        &mut self,
10000        max_height_in_lines: u32,
10001        window: &mut Window,
10002        cx: &mut Context<Editor>,
10003    ) -> Option<AnyElement> {
10004        let menu = self.context_menu.borrow();
10005        let menu = menu.as_ref()?;
10006        if !menu.visible() {
10007            return None;
10008        };
10009        self.style
10010            .as_ref()
10011            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10012    }
10013
10014    fn render_context_menu_aside(
10015        &mut self,
10016        max_size: Size<Pixels>,
10017        window: &mut Window,
10018        cx: &mut Context<Editor>,
10019    ) -> Option<AnyElement> {
10020        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10021            if menu.visible() {
10022                menu.render_aside(max_size, window, cx)
10023            } else {
10024                None
10025            }
10026        })
10027    }
10028
10029    fn hide_context_menu(
10030        &mut self,
10031        window: &mut Window,
10032        cx: &mut Context<Self>,
10033    ) -> Option<CodeContextMenu> {
10034        cx.notify();
10035        self.completion_tasks.clear();
10036        let context_menu = self.context_menu.borrow_mut().take();
10037        self.stale_edit_prediction_in_menu.take();
10038        self.update_visible_edit_prediction(window, cx);
10039        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10040            && let Some(completion_provider) = &self.completion_provider
10041        {
10042            completion_provider.selection_changed(None, window, cx);
10043        }
10044        context_menu
10045    }
10046
10047    fn show_snippet_choices(
10048        &mut self,
10049        choices: &Vec<String>,
10050        selection: Range<Anchor>,
10051        cx: &mut Context<Self>,
10052    ) {
10053        let Some((_, buffer, _)) = self
10054            .buffer()
10055            .read(cx)
10056            .excerpt_containing(selection.start, cx)
10057        else {
10058            return;
10059        };
10060        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10061        else {
10062            return;
10063        };
10064        if buffer != end_buffer {
10065            log::error!("expected anchor range to have matching buffer IDs");
10066            return;
10067        }
10068
10069        let id = post_inc(&mut self.next_completion_id);
10070        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10071        let mut context_menu = self.context_menu.borrow_mut();
10072        let old_menu = context_menu.take();
10073        *context_menu = Some(CodeContextMenu::Completions(
10074            CompletionsMenu::new_snippet_choices(
10075                id,
10076                true,
10077                choices,
10078                selection,
10079                buffer,
10080                old_menu.map(|menu| menu.primary_scroll_handle()),
10081                snippet_sort_order,
10082            ),
10083        ));
10084    }
10085
10086    pub fn insert_snippet(
10087        &mut self,
10088        insertion_ranges: &[Range<MultiBufferOffset>],
10089        snippet: Snippet,
10090        window: &mut Window,
10091        cx: &mut Context<Self>,
10092    ) -> Result<()> {
10093        struct Tabstop<T> {
10094            is_end_tabstop: bool,
10095            ranges: Vec<Range<T>>,
10096            choices: Option<Vec<String>>,
10097        }
10098
10099        let tabstops = self.buffer.update(cx, |buffer, cx| {
10100            let snippet_text: Arc<str> = snippet.text.clone().into();
10101            let edits = insertion_ranges
10102                .iter()
10103                .cloned()
10104                .map(|range| (range, snippet_text.clone()));
10105            let autoindent_mode = AutoindentMode::Block {
10106                original_indent_columns: Vec::new(),
10107            };
10108            buffer.edit(edits, Some(autoindent_mode), cx);
10109
10110            let snapshot = &*buffer.read(cx);
10111            let snippet = &snippet;
10112            snippet
10113                .tabstops
10114                .iter()
10115                .map(|tabstop| {
10116                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10117                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10118                    });
10119                    let mut tabstop_ranges = tabstop
10120                        .ranges
10121                        .iter()
10122                        .flat_map(|tabstop_range| {
10123                            let mut delta = 0_isize;
10124                            insertion_ranges.iter().map(move |insertion_range| {
10125                                let insertion_start = insertion_range.start + delta;
10126                                delta += snippet.text.len() as isize
10127                                    - (insertion_range.end - insertion_range.start) as isize;
10128
10129                                let start =
10130                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10131                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10132                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10133                            })
10134                        })
10135                        .collect::<Vec<_>>();
10136                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10137
10138                    Tabstop {
10139                        is_end_tabstop,
10140                        ranges: tabstop_ranges,
10141                        choices: tabstop.choices.clone(),
10142                    }
10143                })
10144                .collect::<Vec<_>>()
10145        });
10146        if let Some(tabstop) = tabstops.first() {
10147            self.change_selections(Default::default(), window, cx, |s| {
10148                // Reverse order so that the first range is the newest created selection.
10149                // Completions will use it and autoscroll will prioritize it.
10150                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10151            });
10152
10153            if let Some(choices) = &tabstop.choices
10154                && let Some(selection) = tabstop.ranges.first()
10155            {
10156                self.show_snippet_choices(choices, selection.clone(), cx)
10157            }
10158
10159            // If we're already at the last tabstop and it's at the end of the snippet,
10160            // we're done, we don't need to keep the state around.
10161            if !tabstop.is_end_tabstop {
10162                let choices = tabstops
10163                    .iter()
10164                    .map(|tabstop| tabstop.choices.clone())
10165                    .collect();
10166
10167                let ranges = tabstops
10168                    .into_iter()
10169                    .map(|tabstop| tabstop.ranges)
10170                    .collect::<Vec<_>>();
10171
10172                self.snippet_stack.push(SnippetState {
10173                    active_index: 0,
10174                    ranges,
10175                    choices,
10176                });
10177            }
10178
10179            // Check whether the just-entered snippet ends with an auto-closable bracket.
10180            if self.autoclose_regions.is_empty() {
10181                let snapshot = self.buffer.read(cx).snapshot(cx);
10182                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10183                    let selection_head = selection.head();
10184                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10185                        continue;
10186                    };
10187
10188                    let mut bracket_pair = None;
10189                    let max_lookup_length = scope
10190                        .brackets()
10191                        .map(|(pair, _)| {
10192                            pair.start
10193                                .as_str()
10194                                .chars()
10195                                .count()
10196                                .max(pair.end.as_str().chars().count())
10197                        })
10198                        .max();
10199                    if let Some(max_lookup_length) = max_lookup_length {
10200                        let next_text = snapshot
10201                            .chars_at(selection_head)
10202                            .take(max_lookup_length)
10203                            .collect::<String>();
10204                        let prev_text = snapshot
10205                            .reversed_chars_at(selection_head)
10206                            .take(max_lookup_length)
10207                            .collect::<String>();
10208
10209                        for (pair, enabled) in scope.brackets() {
10210                            if enabled
10211                                && pair.close
10212                                && prev_text.starts_with(pair.start.as_str())
10213                                && next_text.starts_with(pair.end.as_str())
10214                            {
10215                                bracket_pair = Some(pair.clone());
10216                                break;
10217                            }
10218                        }
10219                    }
10220
10221                    if let Some(pair) = bracket_pair {
10222                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10223                        let autoclose_enabled =
10224                            self.use_autoclose && snapshot_settings.use_autoclose;
10225                        if autoclose_enabled {
10226                            let start = snapshot.anchor_after(selection_head);
10227                            let end = snapshot.anchor_after(selection_head);
10228                            self.autoclose_regions.push(AutocloseRegion {
10229                                selection_id: selection.id,
10230                                range: start..end,
10231                                pair,
10232                            });
10233                        }
10234                    }
10235                }
10236            }
10237        }
10238        Ok(())
10239    }
10240
10241    pub fn move_to_next_snippet_tabstop(
10242        &mut self,
10243        window: &mut Window,
10244        cx: &mut Context<Self>,
10245    ) -> bool {
10246        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10247    }
10248
10249    pub fn move_to_prev_snippet_tabstop(
10250        &mut self,
10251        window: &mut Window,
10252        cx: &mut Context<Self>,
10253    ) -> bool {
10254        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10255    }
10256
10257    pub fn move_to_snippet_tabstop(
10258        &mut self,
10259        bias: Bias,
10260        window: &mut Window,
10261        cx: &mut Context<Self>,
10262    ) -> bool {
10263        if let Some(mut snippet) = self.snippet_stack.pop() {
10264            match bias {
10265                Bias::Left => {
10266                    if snippet.active_index > 0 {
10267                        snippet.active_index -= 1;
10268                    } else {
10269                        self.snippet_stack.push(snippet);
10270                        return false;
10271                    }
10272                }
10273                Bias::Right => {
10274                    if snippet.active_index + 1 < snippet.ranges.len() {
10275                        snippet.active_index += 1;
10276                    } else {
10277                        self.snippet_stack.push(snippet);
10278                        return false;
10279                    }
10280                }
10281            }
10282            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10283                self.change_selections(Default::default(), window, cx, |s| {
10284                    // Reverse order so that the first range is the newest created selection.
10285                    // Completions will use it and autoscroll will prioritize it.
10286                    s.select_ranges(current_ranges.iter().rev().cloned())
10287                });
10288
10289                if let Some(choices) = &snippet.choices[snippet.active_index]
10290                    && let Some(selection) = current_ranges.first()
10291                {
10292                    self.show_snippet_choices(choices, selection.clone(), cx);
10293                }
10294
10295                // If snippet state is not at the last tabstop, push it back on the stack
10296                if snippet.active_index + 1 < snippet.ranges.len() {
10297                    self.snippet_stack.push(snippet);
10298                }
10299                return true;
10300            }
10301        }
10302
10303        false
10304    }
10305
10306    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10307        self.transact(window, cx, |this, window, cx| {
10308            this.select_all(&SelectAll, window, cx);
10309            this.insert("", window, cx);
10310        });
10311    }
10312
10313    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10314        if self.read_only(cx) {
10315            return;
10316        }
10317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10318        self.transact(window, cx, |this, window, cx| {
10319            this.select_autoclose_pair(window, cx);
10320
10321            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10322
10323            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10324            if !this.linked_edit_ranges.is_empty() {
10325                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10326                let snapshot = this.buffer.read(cx).snapshot(cx);
10327
10328                for selection in selections.iter() {
10329                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10330                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10331                    if selection_start.buffer_id != selection_end.buffer_id {
10332                        continue;
10333                    }
10334                    if let Some(ranges) =
10335                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10336                    {
10337                        for (buffer, entries) in ranges {
10338                            linked_ranges.entry(buffer).or_default().extend(entries);
10339                        }
10340                    }
10341                }
10342            }
10343
10344            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10345            for selection in &mut selections {
10346                if selection.is_empty() {
10347                    let old_head = selection.head();
10348                    let mut new_head =
10349                        movement::left(&display_map, old_head.to_display_point(&display_map))
10350                            .to_point(&display_map);
10351                    if let Some((buffer, line_buffer_range)) = display_map
10352                        .buffer_snapshot()
10353                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10354                    {
10355                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10356                        let indent_len = match indent_size.kind {
10357                            IndentKind::Space => {
10358                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10359                            }
10360                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10361                        };
10362                        if old_head.column <= indent_size.len && old_head.column > 0 {
10363                            let indent_len = indent_len.get();
10364                            new_head = cmp::min(
10365                                new_head,
10366                                MultiBufferPoint::new(
10367                                    old_head.row,
10368                                    ((old_head.column - 1) / indent_len) * indent_len,
10369                                ),
10370                            );
10371                        }
10372                    }
10373
10374                    selection.set_head(new_head, SelectionGoal::None);
10375                }
10376            }
10377
10378            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10379            this.insert("", window, cx);
10380            let empty_str: Arc<str> = Arc::from("");
10381            for (buffer, edits) in linked_ranges {
10382                let snapshot = buffer.read(cx).snapshot();
10383                use text::ToPoint as TP;
10384
10385                let edits = edits
10386                    .into_iter()
10387                    .map(|range| {
10388                        let end_point = TP::to_point(&range.end, &snapshot);
10389                        let mut start_point = TP::to_point(&range.start, &snapshot);
10390
10391                        if end_point == start_point {
10392                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10393                                .saturating_sub(1);
10394                            start_point =
10395                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10396                        };
10397
10398                        (start_point..end_point, empty_str.clone())
10399                    })
10400                    .sorted_by_key(|(range, _)| range.start)
10401                    .collect::<Vec<_>>();
10402                buffer.update(cx, |this, cx| {
10403                    this.edit(edits, None, cx);
10404                })
10405            }
10406            this.refresh_edit_prediction(true, false, window, cx);
10407            refresh_linked_ranges(this, window, cx);
10408        });
10409    }
10410
10411    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10412        if self.read_only(cx) {
10413            return;
10414        }
10415        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10416        self.transact(window, cx, |this, window, cx| {
10417            this.change_selections(Default::default(), window, cx, |s| {
10418                s.move_with(|map, selection| {
10419                    if selection.is_empty() {
10420                        let cursor = movement::right(map, selection.head());
10421                        selection.end = cursor;
10422                        selection.reversed = true;
10423                        selection.goal = SelectionGoal::None;
10424                    }
10425                })
10426            });
10427            this.insert("", window, cx);
10428            this.refresh_edit_prediction(true, false, window, cx);
10429        });
10430    }
10431
10432    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10433        if self.mode.is_single_line() {
10434            cx.propagate();
10435            return;
10436        }
10437
10438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10439        if self.move_to_prev_snippet_tabstop(window, cx) {
10440            return;
10441        }
10442        self.outdent(&Outdent, window, cx);
10443    }
10444
10445    pub fn next_snippet_tabstop(
10446        &mut self,
10447        _: &NextSnippetTabstop,
10448        window: &mut Window,
10449        cx: &mut Context<Self>,
10450    ) {
10451        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10452            cx.propagate();
10453            return;
10454        }
10455
10456        if self.move_to_next_snippet_tabstop(window, cx) {
10457            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10458            return;
10459        }
10460        cx.propagate();
10461    }
10462
10463    pub fn previous_snippet_tabstop(
10464        &mut self,
10465        _: &PreviousSnippetTabstop,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10470            cx.propagate();
10471            return;
10472        }
10473
10474        if self.move_to_prev_snippet_tabstop(window, cx) {
10475            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10476            return;
10477        }
10478        cx.propagate();
10479    }
10480
10481    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10482        if self.mode.is_single_line() {
10483            cx.propagate();
10484            return;
10485        }
10486
10487        if self.move_to_next_snippet_tabstop(window, cx) {
10488            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10489            return;
10490        }
10491        if self.read_only(cx) {
10492            return;
10493        }
10494        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10495        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10496        let buffer = self.buffer.read(cx);
10497        let snapshot = buffer.snapshot(cx);
10498        let rows_iter = selections.iter().map(|s| s.head().row);
10499        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10500
10501        let has_some_cursor_in_whitespace = selections
10502            .iter()
10503            .filter(|selection| selection.is_empty())
10504            .any(|selection| {
10505                let cursor = selection.head();
10506                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10507                cursor.column < current_indent.len
10508            });
10509
10510        let mut edits = Vec::new();
10511        let mut prev_edited_row = 0;
10512        let mut row_delta = 0;
10513        for selection in &mut selections {
10514            if selection.start.row != prev_edited_row {
10515                row_delta = 0;
10516            }
10517            prev_edited_row = selection.end.row;
10518
10519            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10520            if selection.is_empty() {
10521                let cursor = selection.head();
10522                let settings = buffer.language_settings_at(cursor, cx);
10523                if settings.indent_list_on_tab {
10524                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10525                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10526                            row_delta = Self::indent_selection(
10527                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10528                            );
10529                            continue;
10530                        }
10531                    }
10532                }
10533            }
10534
10535            // If the selection is non-empty, then increase the indentation of the selected lines.
10536            if !selection.is_empty() {
10537                row_delta =
10538                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10539                continue;
10540            }
10541
10542            let cursor = selection.head();
10543            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10544            if let Some(suggested_indent) =
10545                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10546            {
10547                // Don't do anything if already at suggested indent
10548                // and there is any other cursor which is not
10549                if has_some_cursor_in_whitespace
10550                    && cursor.column == current_indent.len
10551                    && current_indent.len == suggested_indent.len
10552                {
10553                    continue;
10554                }
10555
10556                // Adjust line and move cursor to suggested indent
10557                // if cursor is not at suggested indent
10558                if cursor.column < suggested_indent.len
10559                    && cursor.column <= current_indent.len
10560                    && current_indent.len <= suggested_indent.len
10561                {
10562                    selection.start = Point::new(cursor.row, suggested_indent.len);
10563                    selection.end = selection.start;
10564                    if row_delta == 0 {
10565                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10566                            cursor.row,
10567                            current_indent,
10568                            suggested_indent,
10569                        ));
10570                        row_delta = suggested_indent.len - current_indent.len;
10571                    }
10572                    continue;
10573                }
10574
10575                // If current indent is more than suggested indent
10576                // only move cursor to current indent and skip indent
10577                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10578                    selection.start = Point::new(cursor.row, current_indent.len);
10579                    selection.end = selection.start;
10580                    continue;
10581                }
10582            }
10583
10584            // Otherwise, insert a hard or soft tab.
10585            let settings = buffer.language_settings_at(cursor, cx);
10586            let tab_size = if settings.hard_tabs {
10587                IndentSize::tab()
10588            } else {
10589                let tab_size = settings.tab_size.get();
10590                let indent_remainder = snapshot
10591                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10592                    .flat_map(str::chars)
10593                    .fold(row_delta % tab_size, |counter: u32, c| {
10594                        if c == '\t' {
10595                            0
10596                        } else {
10597                            (counter + 1) % tab_size
10598                        }
10599                    });
10600
10601                let chars_to_next_tab_stop = tab_size - indent_remainder;
10602                IndentSize::spaces(chars_to_next_tab_stop)
10603            };
10604            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10605            selection.end = selection.start;
10606            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10607            row_delta += tab_size.len;
10608        }
10609
10610        self.transact(window, cx, |this, window, cx| {
10611            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10612            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10613            this.refresh_edit_prediction(true, false, window, cx);
10614        });
10615    }
10616
10617    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10618        if self.read_only(cx) {
10619            return;
10620        }
10621        if self.mode.is_single_line() {
10622            cx.propagate();
10623            return;
10624        }
10625
10626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10627        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10628        let mut prev_edited_row = 0;
10629        let mut row_delta = 0;
10630        let mut edits = Vec::new();
10631        let buffer = self.buffer.read(cx);
10632        let snapshot = buffer.snapshot(cx);
10633        for selection in &mut selections {
10634            if selection.start.row != prev_edited_row {
10635                row_delta = 0;
10636            }
10637            prev_edited_row = selection.end.row;
10638
10639            row_delta =
10640                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10641        }
10642
10643        self.transact(window, cx, |this, window, cx| {
10644            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10645            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10646        });
10647    }
10648
10649    fn indent_selection(
10650        buffer: &MultiBuffer,
10651        snapshot: &MultiBufferSnapshot,
10652        selection: &mut Selection<Point>,
10653        edits: &mut Vec<(Range<Point>, String)>,
10654        delta_for_start_row: u32,
10655        cx: &App,
10656    ) -> u32 {
10657        let settings = buffer.language_settings_at(selection.start, cx);
10658        let tab_size = settings.tab_size.get();
10659        let indent_kind = if settings.hard_tabs {
10660            IndentKind::Tab
10661        } else {
10662            IndentKind::Space
10663        };
10664        let mut start_row = selection.start.row;
10665        let mut end_row = selection.end.row + 1;
10666
10667        // If a selection ends at the beginning of a line, don't indent
10668        // that last line.
10669        if selection.end.column == 0 && selection.end.row > selection.start.row {
10670            end_row -= 1;
10671        }
10672
10673        // Avoid re-indenting a row that has already been indented by a
10674        // previous selection, but still update this selection's column
10675        // to reflect that indentation.
10676        if delta_for_start_row > 0 {
10677            start_row += 1;
10678            selection.start.column += delta_for_start_row;
10679            if selection.end.row == selection.start.row {
10680                selection.end.column += delta_for_start_row;
10681            }
10682        }
10683
10684        let mut delta_for_end_row = 0;
10685        let has_multiple_rows = start_row + 1 != end_row;
10686        for row in start_row..end_row {
10687            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10688            let indent_delta = match (current_indent.kind, indent_kind) {
10689                (IndentKind::Space, IndentKind::Space) => {
10690                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10691                    IndentSize::spaces(columns_to_next_tab_stop)
10692                }
10693                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10694                (_, IndentKind::Tab) => IndentSize::tab(),
10695            };
10696
10697            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10698                0
10699            } else {
10700                selection.start.column
10701            };
10702            let row_start = Point::new(row, start);
10703            edits.push((
10704                row_start..row_start,
10705                indent_delta.chars().collect::<String>(),
10706            ));
10707
10708            // Update this selection's endpoints to reflect the indentation.
10709            if row == selection.start.row {
10710                selection.start.column += indent_delta.len;
10711            }
10712            if row == selection.end.row {
10713                selection.end.column += indent_delta.len;
10714                delta_for_end_row = indent_delta.len;
10715            }
10716        }
10717
10718        if selection.start.row == selection.end.row {
10719            delta_for_start_row + delta_for_end_row
10720        } else {
10721            delta_for_end_row
10722        }
10723    }
10724
10725    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10726        if self.read_only(cx) {
10727            return;
10728        }
10729        if self.mode.is_single_line() {
10730            cx.propagate();
10731            return;
10732        }
10733
10734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10735        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10736        let selections = self.selections.all::<Point>(&display_map);
10737        let mut deletion_ranges = Vec::new();
10738        let mut last_outdent = None;
10739        {
10740            let buffer = self.buffer.read(cx);
10741            let snapshot = buffer.snapshot(cx);
10742            for selection in &selections {
10743                let settings = buffer.language_settings_at(selection.start, cx);
10744                let tab_size = settings.tab_size.get();
10745                let mut rows = selection.spanned_rows(false, &display_map);
10746
10747                // Avoid re-outdenting a row that has already been outdented by a
10748                // previous selection.
10749                if let Some(last_row) = last_outdent
10750                    && last_row == rows.start
10751                {
10752                    rows.start = rows.start.next_row();
10753                }
10754                let has_multiple_rows = rows.len() > 1;
10755                for row in rows.iter_rows() {
10756                    let indent_size = snapshot.indent_size_for_line(row);
10757                    if indent_size.len > 0 {
10758                        let deletion_len = match indent_size.kind {
10759                            IndentKind::Space => {
10760                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10761                                if columns_to_prev_tab_stop == 0 {
10762                                    tab_size
10763                                } else {
10764                                    columns_to_prev_tab_stop
10765                                }
10766                            }
10767                            IndentKind::Tab => 1,
10768                        };
10769                        let start = if has_multiple_rows
10770                            || deletion_len > selection.start.column
10771                            || indent_size.len < selection.start.column
10772                        {
10773                            0
10774                        } else {
10775                            selection.start.column - deletion_len
10776                        };
10777                        deletion_ranges.push(
10778                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10779                        );
10780                        last_outdent = Some(row);
10781                    }
10782                }
10783            }
10784        }
10785
10786        self.transact(window, cx, |this, window, cx| {
10787            this.buffer.update(cx, |buffer, cx| {
10788                let empty_str: Arc<str> = Arc::default();
10789                buffer.edit(
10790                    deletion_ranges
10791                        .into_iter()
10792                        .map(|range| (range, empty_str.clone())),
10793                    None,
10794                    cx,
10795                );
10796            });
10797            let selections = this
10798                .selections
10799                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10800            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10801        });
10802    }
10803
10804    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10805        if self.read_only(cx) {
10806            return;
10807        }
10808        if self.mode.is_single_line() {
10809            cx.propagate();
10810            return;
10811        }
10812
10813        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10814        let selections = self
10815            .selections
10816            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10817            .into_iter()
10818            .map(|s| s.range());
10819
10820        self.transact(window, cx, |this, window, cx| {
10821            this.buffer.update(cx, |buffer, cx| {
10822                buffer.autoindent_ranges(selections, cx);
10823            });
10824            let selections = this
10825                .selections
10826                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10827            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10828        });
10829    }
10830
10831    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10833        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10834        let selections = self.selections.all::<Point>(&display_map);
10835
10836        let mut new_cursors = Vec::new();
10837        let mut edit_ranges = Vec::new();
10838        let mut selections = selections.iter().peekable();
10839        while let Some(selection) = selections.next() {
10840            let mut rows = selection.spanned_rows(false, &display_map);
10841
10842            // Accumulate contiguous regions of rows that we want to delete.
10843            while let Some(next_selection) = selections.peek() {
10844                let next_rows = next_selection.spanned_rows(false, &display_map);
10845                if next_rows.start <= rows.end {
10846                    rows.end = next_rows.end;
10847                    selections.next().unwrap();
10848                } else {
10849                    break;
10850                }
10851            }
10852
10853            let buffer = display_map.buffer_snapshot();
10854            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10855            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10856                // If there's a line after the range, delete the \n from the end of the row range
10857                (
10858                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10859                    rows.end,
10860                )
10861            } else {
10862                // If there isn't a line after the range, delete the \n from the line before the
10863                // start of the row range
10864                edit_start = edit_start.saturating_sub_usize(1);
10865                (buffer.len(), rows.start.previous_row())
10866            };
10867
10868            let text_layout_details = self.text_layout_details(window);
10869            let x = display_map.x_for_display_point(
10870                selection.head().to_display_point(&display_map),
10871                &text_layout_details,
10872            );
10873            let row = Point::new(target_row.0, 0)
10874                .to_display_point(&display_map)
10875                .row();
10876            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10877
10878            new_cursors.push((
10879                selection.id,
10880                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10881                SelectionGoal::None,
10882            ));
10883            edit_ranges.push(edit_start..edit_end);
10884        }
10885
10886        self.transact(window, cx, |this, window, cx| {
10887            let buffer = this.buffer.update(cx, |buffer, cx| {
10888                let empty_str: Arc<str> = Arc::default();
10889                buffer.edit(
10890                    edit_ranges
10891                        .into_iter()
10892                        .map(|range| (range, empty_str.clone())),
10893                    None,
10894                    cx,
10895                );
10896                buffer.snapshot(cx)
10897            });
10898            let new_selections = new_cursors
10899                .into_iter()
10900                .map(|(id, cursor, goal)| {
10901                    let cursor = cursor.to_point(&buffer);
10902                    Selection {
10903                        id,
10904                        start: cursor,
10905                        end: cursor,
10906                        reversed: false,
10907                        goal,
10908                    }
10909                })
10910                .collect();
10911
10912            this.change_selections(Default::default(), window, cx, |s| {
10913                s.select(new_selections);
10914            });
10915        });
10916    }
10917
10918    pub fn join_lines_impl(
10919        &mut self,
10920        insert_whitespace: bool,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        if self.read_only(cx) {
10925            return;
10926        }
10927        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10928        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10929            let start = MultiBufferRow(selection.start.row);
10930            // Treat single line selections as if they include the next line. Otherwise this action
10931            // would do nothing for single line selections individual cursors.
10932            let end = if selection.start.row == selection.end.row {
10933                MultiBufferRow(selection.start.row + 1)
10934            } else {
10935                MultiBufferRow(selection.end.row)
10936            };
10937
10938            if let Some(last_row_range) = row_ranges.last_mut()
10939                && start <= last_row_range.end
10940            {
10941                last_row_range.end = end;
10942                continue;
10943            }
10944            row_ranges.push(start..end);
10945        }
10946
10947        let snapshot = self.buffer.read(cx).snapshot(cx);
10948        let mut cursor_positions = Vec::new();
10949        for row_range in &row_ranges {
10950            let anchor = snapshot.anchor_before(Point::new(
10951                row_range.end.previous_row().0,
10952                snapshot.line_len(row_range.end.previous_row()),
10953            ));
10954            cursor_positions.push(anchor..anchor);
10955        }
10956
10957        self.transact(window, cx, |this, window, cx| {
10958            for row_range in row_ranges.into_iter().rev() {
10959                for row in row_range.iter_rows().rev() {
10960                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10961                    let next_line_row = row.next_row();
10962                    let indent = snapshot.indent_size_for_line(next_line_row);
10963                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10964
10965                    let replace =
10966                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10967                            " "
10968                        } else {
10969                            ""
10970                        };
10971
10972                    this.buffer.update(cx, |buffer, cx| {
10973                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10974                    });
10975                }
10976            }
10977
10978            this.change_selections(Default::default(), window, cx, |s| {
10979                s.select_anchor_ranges(cursor_positions)
10980            });
10981        });
10982    }
10983
10984    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10986        self.join_lines_impl(true, window, cx);
10987    }
10988
10989    pub fn sort_lines_case_sensitive(
10990        &mut self,
10991        _: &SortLinesCaseSensitive,
10992        window: &mut Window,
10993        cx: &mut Context<Self>,
10994    ) {
10995        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10996    }
10997
10998    pub fn sort_lines_by_length(
10999        &mut self,
11000        _: &SortLinesByLength,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003    ) {
11004        self.manipulate_immutable_lines(window, cx, |lines| {
11005            lines.sort_by_key(|&line| line.chars().count())
11006        })
11007    }
11008
11009    pub fn sort_lines_case_insensitive(
11010        &mut self,
11011        _: &SortLinesCaseInsensitive,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014    ) {
11015        self.manipulate_immutable_lines(window, cx, |lines| {
11016            lines.sort_by_key(|line| line.to_lowercase())
11017        })
11018    }
11019
11020    pub fn unique_lines_case_insensitive(
11021        &mut self,
11022        _: &UniqueLinesCaseInsensitive,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025    ) {
11026        self.manipulate_immutable_lines(window, cx, |lines| {
11027            let mut seen = HashSet::default();
11028            lines.retain(|line| seen.insert(line.to_lowercase()));
11029        })
11030    }
11031
11032    pub fn unique_lines_case_sensitive(
11033        &mut self,
11034        _: &UniqueLinesCaseSensitive,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        self.manipulate_immutable_lines(window, cx, |lines| {
11039            let mut seen = HashSet::default();
11040            lines.retain(|line| seen.insert(*line));
11041        })
11042    }
11043
11044    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11045        let snapshot = self.buffer.read(cx).snapshot(cx);
11046        for selection in self.selections.disjoint_anchors_arc().iter() {
11047            if snapshot
11048                .language_at(selection.start)
11049                .and_then(|lang| lang.config().wrap_characters.as_ref())
11050                .is_some()
11051            {
11052                return true;
11053            }
11054        }
11055        false
11056    }
11057
11058    fn wrap_selections_in_tag(
11059        &mut self,
11060        _: &WrapSelectionsInTag,
11061        window: &mut Window,
11062        cx: &mut Context<Self>,
11063    ) {
11064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11065
11066        let snapshot = self.buffer.read(cx).snapshot(cx);
11067
11068        let mut edits = Vec::new();
11069        let mut boundaries = Vec::new();
11070
11071        for selection in self
11072            .selections
11073            .all_adjusted(&self.display_snapshot(cx))
11074            .iter()
11075        {
11076            let Some(wrap_config) = snapshot
11077                .language_at(selection.start)
11078                .and_then(|lang| lang.config().wrap_characters.clone())
11079            else {
11080                continue;
11081            };
11082
11083            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11084            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11085
11086            let start_before = snapshot.anchor_before(selection.start);
11087            let end_after = snapshot.anchor_after(selection.end);
11088
11089            edits.push((start_before..start_before, open_tag));
11090            edits.push((end_after..end_after, close_tag));
11091
11092            boundaries.push((
11093                start_before,
11094                end_after,
11095                wrap_config.start_prefix.len(),
11096                wrap_config.end_suffix.len(),
11097            ));
11098        }
11099
11100        if edits.is_empty() {
11101            return;
11102        }
11103
11104        self.transact(window, cx, |this, window, cx| {
11105            let buffer = this.buffer.update(cx, |buffer, cx| {
11106                buffer.edit(edits, None, cx);
11107                buffer.snapshot(cx)
11108            });
11109
11110            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11111            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11112                boundaries.into_iter()
11113            {
11114                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11115                let close_offset = end_after
11116                    .to_offset(&buffer)
11117                    .saturating_sub_usize(end_suffix_len);
11118                new_selections.push(open_offset..open_offset);
11119                new_selections.push(close_offset..close_offset);
11120            }
11121
11122            this.change_selections(Default::default(), window, cx, |s| {
11123                s.select_ranges(new_selections);
11124            });
11125
11126            this.request_autoscroll(Autoscroll::fit(), cx);
11127        });
11128    }
11129
11130    pub fn toggle_read_only(
11131        &mut self,
11132        _: &workspace::ToggleReadOnlyFile,
11133        _: &mut Window,
11134        cx: &mut Context<Self>,
11135    ) {
11136        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11137            buffer.update(cx, |buffer, cx| {
11138                buffer.set_capability(
11139                    match buffer.capability() {
11140                        Capability::ReadWrite => Capability::Read,
11141                        Capability::Read => Capability::ReadWrite,
11142                        Capability::ReadOnly => Capability::ReadOnly,
11143                    },
11144                    cx,
11145                );
11146            })
11147        }
11148    }
11149
11150    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11151        let Some(project) = self.project.clone() else {
11152            return;
11153        };
11154        self.reload(project, window, cx)
11155            .detach_and_notify_err(window, cx);
11156    }
11157
11158    pub fn restore_file(
11159        &mut self,
11160        _: &::git::RestoreFile,
11161        window: &mut Window,
11162        cx: &mut Context<Self>,
11163    ) {
11164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11165        let mut buffer_ids = HashSet::default();
11166        let snapshot = self.buffer().read(cx).snapshot(cx);
11167        for selection in self
11168            .selections
11169            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11170        {
11171            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11172        }
11173
11174        let buffer = self.buffer().read(cx);
11175        let ranges = buffer_ids
11176            .into_iter()
11177            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11178            .collect::<Vec<_>>();
11179
11180        self.restore_hunks_in_ranges(ranges, window, cx);
11181    }
11182
11183    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11185        let selections = self
11186            .selections
11187            .all(&self.display_snapshot(cx))
11188            .into_iter()
11189            .map(|s| s.range())
11190            .collect();
11191        self.restore_hunks_in_ranges(selections, window, cx);
11192    }
11193
11194    pub fn restore_hunks_in_ranges(
11195        &mut self,
11196        ranges: Vec<Range<Point>>,
11197        window: &mut Window,
11198        cx: &mut Context<Editor>,
11199    ) {
11200        let mut revert_changes = HashMap::default();
11201        let chunk_by = self
11202            .snapshot(window, cx)
11203            .hunks_for_ranges(ranges)
11204            .into_iter()
11205            .chunk_by(|hunk| hunk.buffer_id);
11206        for (buffer_id, hunks) in &chunk_by {
11207            let hunks = hunks.collect::<Vec<_>>();
11208            for hunk in &hunks {
11209                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11210            }
11211            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11212        }
11213        drop(chunk_by);
11214        if !revert_changes.is_empty() {
11215            self.transact(window, cx, |editor, window, cx| {
11216                editor.restore(revert_changes, window, cx);
11217            });
11218        }
11219    }
11220
11221    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11222        if let Some(status) = self
11223            .addons
11224            .iter()
11225            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11226        {
11227            return Some(status);
11228        }
11229        self.project
11230            .as_ref()?
11231            .read(cx)
11232            .status_for_buffer_id(buffer_id, cx)
11233    }
11234
11235    pub fn open_active_item_in_terminal(
11236        &mut self,
11237        _: &OpenInTerminal,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11242            let project_path = buffer.read(cx).project_path(cx)?;
11243            let project = self.project()?.read(cx);
11244            let entry = project.entry_for_path(&project_path, cx)?;
11245            let parent = match &entry.canonical_path {
11246                Some(canonical_path) => canonical_path.to_path_buf(),
11247                None => project.absolute_path(&project_path, cx)?,
11248            }
11249            .parent()?
11250            .to_path_buf();
11251            Some(parent)
11252        }) {
11253            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11254        }
11255    }
11256
11257    fn set_breakpoint_context_menu(
11258        &mut self,
11259        display_row: DisplayRow,
11260        position: Option<Anchor>,
11261        clicked_point: gpui::Point<Pixels>,
11262        window: &mut Window,
11263        cx: &mut Context<Self>,
11264    ) {
11265        let source = self
11266            .buffer
11267            .read(cx)
11268            .snapshot(cx)
11269            .anchor_before(Point::new(display_row.0, 0u32));
11270
11271        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11272
11273        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11274            self,
11275            source,
11276            clicked_point,
11277            context_menu,
11278            window,
11279            cx,
11280        );
11281    }
11282
11283    fn add_edit_breakpoint_block(
11284        &mut self,
11285        anchor: Anchor,
11286        breakpoint: &Breakpoint,
11287        edit_action: BreakpointPromptEditAction,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        let weak_editor = cx.weak_entity();
11292        let bp_prompt = cx.new(|cx| {
11293            BreakpointPromptEditor::new(
11294                weak_editor,
11295                anchor,
11296                breakpoint.clone(),
11297                edit_action,
11298                window,
11299                cx,
11300            )
11301        });
11302
11303        let height = bp_prompt.update(cx, |this, cx| {
11304            this.prompt
11305                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11306        });
11307        let cloned_prompt = bp_prompt.clone();
11308        let blocks = vec![BlockProperties {
11309            style: BlockStyle::Sticky,
11310            placement: BlockPlacement::Above(anchor),
11311            height: Some(height),
11312            render: Arc::new(move |cx| {
11313                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11314                cloned_prompt.clone().into_any_element()
11315            }),
11316            priority: 0,
11317        }];
11318
11319        let focus_handle = bp_prompt.focus_handle(cx);
11320        window.focus(&focus_handle, cx);
11321
11322        let block_ids = self.insert_blocks(blocks, None, cx);
11323        bp_prompt.update(cx, |prompt, _| {
11324            prompt.add_block_ids(block_ids);
11325        });
11326    }
11327
11328    pub(crate) fn breakpoint_at_row(
11329        &self,
11330        row: u32,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) -> Option<(Anchor, Breakpoint)> {
11334        let snapshot = self.snapshot(window, cx);
11335        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11336
11337        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11338    }
11339
11340    pub(crate) fn breakpoint_at_anchor(
11341        &self,
11342        breakpoint_position: Anchor,
11343        snapshot: &EditorSnapshot,
11344        cx: &mut Context<Self>,
11345    ) -> Option<(Anchor, Breakpoint)> {
11346        let buffer = self
11347            .buffer
11348            .read(cx)
11349            .buffer_for_anchor(breakpoint_position, cx)?;
11350
11351        let enclosing_excerpt = breakpoint_position.excerpt_id;
11352        let buffer_snapshot = buffer.read(cx).snapshot();
11353
11354        let row = buffer_snapshot
11355            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11356            .row;
11357
11358        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11359        let anchor_end = snapshot
11360            .buffer_snapshot()
11361            .anchor_after(Point::new(row, line_len));
11362
11363        self.breakpoint_store
11364            .as_ref()?
11365            .read_with(cx, |breakpoint_store, cx| {
11366                breakpoint_store
11367                    .breakpoints(
11368                        &buffer,
11369                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11370                        &buffer_snapshot,
11371                        cx,
11372                    )
11373                    .next()
11374                    .and_then(|(bp, _)| {
11375                        let breakpoint_row = buffer_snapshot
11376                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11377                            .row;
11378
11379                        if breakpoint_row == row {
11380                            snapshot
11381                                .buffer_snapshot()
11382                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11383                                .map(|position| (position, bp.bp.clone()))
11384                        } else {
11385                            None
11386                        }
11387                    })
11388            })
11389    }
11390
11391    pub fn edit_log_breakpoint(
11392        &mut self,
11393        _: &EditLogBreakpoint,
11394        window: &mut Window,
11395        cx: &mut Context<Self>,
11396    ) {
11397        if self.breakpoint_store.is_none() {
11398            return;
11399        }
11400
11401        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11402            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11403                message: None,
11404                state: BreakpointState::Enabled,
11405                condition: None,
11406                hit_condition: None,
11407            });
11408
11409            self.add_edit_breakpoint_block(
11410                anchor,
11411                &breakpoint,
11412                BreakpointPromptEditAction::Log,
11413                window,
11414                cx,
11415            );
11416        }
11417    }
11418
11419    fn breakpoints_at_cursors(
11420        &self,
11421        window: &mut Window,
11422        cx: &mut Context<Self>,
11423    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11424        let snapshot = self.snapshot(window, cx);
11425        let cursors = self
11426            .selections
11427            .disjoint_anchors_arc()
11428            .iter()
11429            .map(|selection| {
11430                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11431
11432                let breakpoint_position = self
11433                    .breakpoint_at_row(cursor_position.row, window, cx)
11434                    .map(|bp| bp.0)
11435                    .unwrap_or_else(|| {
11436                        snapshot
11437                            .display_snapshot
11438                            .buffer_snapshot()
11439                            .anchor_after(Point::new(cursor_position.row, 0))
11440                    });
11441
11442                let breakpoint = self
11443                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11444                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11445
11446                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11447            })
11448            // 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.
11449            .collect::<HashMap<Anchor, _>>();
11450
11451        cursors.into_iter().collect()
11452    }
11453
11454    pub fn enable_breakpoint(
11455        &mut self,
11456        _: &crate::actions::EnableBreakpoint,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        if self.breakpoint_store.is_none() {
11461            return;
11462        }
11463
11464        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11465            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11466                continue;
11467            };
11468            self.edit_breakpoint_at_anchor(
11469                anchor,
11470                breakpoint,
11471                BreakpointEditAction::InvertState,
11472                cx,
11473            );
11474        }
11475    }
11476
11477    pub fn disable_breakpoint(
11478        &mut self,
11479        _: &crate::actions::DisableBreakpoint,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        if self.breakpoint_store.is_none() {
11484            return;
11485        }
11486
11487        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11488            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11489                continue;
11490            };
11491            self.edit_breakpoint_at_anchor(
11492                anchor,
11493                breakpoint,
11494                BreakpointEditAction::InvertState,
11495                cx,
11496            );
11497        }
11498    }
11499
11500    pub fn toggle_breakpoint(
11501        &mut self,
11502        _: &crate::actions::ToggleBreakpoint,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        if self.breakpoint_store.is_none() {
11507            return;
11508        }
11509
11510        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11511            if let Some(breakpoint) = breakpoint {
11512                self.edit_breakpoint_at_anchor(
11513                    anchor,
11514                    breakpoint,
11515                    BreakpointEditAction::Toggle,
11516                    cx,
11517                );
11518            } else {
11519                self.edit_breakpoint_at_anchor(
11520                    anchor,
11521                    Breakpoint::new_standard(),
11522                    BreakpointEditAction::Toggle,
11523                    cx,
11524                );
11525            }
11526        }
11527    }
11528
11529    pub fn edit_breakpoint_at_anchor(
11530        &mut self,
11531        breakpoint_position: Anchor,
11532        breakpoint: Breakpoint,
11533        edit_action: BreakpointEditAction,
11534        cx: &mut Context<Self>,
11535    ) {
11536        let Some(breakpoint_store) = &self.breakpoint_store else {
11537            return;
11538        };
11539
11540        let Some(buffer) = self
11541            .buffer
11542            .read(cx)
11543            .buffer_for_anchor(breakpoint_position, cx)
11544        else {
11545            return;
11546        };
11547
11548        breakpoint_store.update(cx, |breakpoint_store, cx| {
11549            breakpoint_store.toggle_breakpoint(
11550                buffer,
11551                BreakpointWithPosition {
11552                    position: breakpoint_position.text_anchor,
11553                    bp: breakpoint,
11554                },
11555                edit_action,
11556                cx,
11557            );
11558        });
11559
11560        cx.notify();
11561    }
11562
11563    #[cfg(any(test, feature = "test-support"))]
11564    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11565        self.breakpoint_store.clone()
11566    }
11567
11568    pub fn prepare_restore_change(
11569        &self,
11570        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11571        hunk: &MultiBufferDiffHunk,
11572        cx: &mut App,
11573    ) -> Option<()> {
11574        if hunk.is_created_file() {
11575            return None;
11576        }
11577        let buffer = self.buffer.read(cx);
11578        let diff = buffer.diff_for(hunk.buffer_id)?;
11579        let buffer = buffer.buffer(hunk.buffer_id)?;
11580        let buffer = buffer.read(cx);
11581        let original_text = diff
11582            .read(cx)
11583            .base_text(cx)
11584            .as_rope()
11585            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11586        let buffer_snapshot = buffer.snapshot();
11587        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11588        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11589            probe
11590                .0
11591                .start
11592                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11593                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11594        }) {
11595            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11596            Some(())
11597        } else {
11598            None
11599        }
11600    }
11601
11602    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11603        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11604    }
11605
11606    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11607        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11608    }
11609
11610    pub fn rotate_selections_forward(
11611        &mut self,
11612        _: &RotateSelectionsForward,
11613        window: &mut Window,
11614        cx: &mut Context<Self>,
11615    ) {
11616        self.rotate_selections(window, cx, false)
11617    }
11618
11619    pub fn rotate_selections_backward(
11620        &mut self,
11621        _: &RotateSelectionsBackward,
11622        window: &mut Window,
11623        cx: &mut Context<Self>,
11624    ) {
11625        self.rotate_selections(window, cx, true)
11626    }
11627
11628    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11630        let display_snapshot = self.display_snapshot(cx);
11631        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11632
11633        if selections.len() < 2 {
11634            return;
11635        }
11636
11637        let (edits, new_selections) = {
11638            let buffer = self.buffer.read(cx).read(cx);
11639            let has_selections = selections.iter().any(|s| !s.is_empty());
11640            if has_selections {
11641                let mut selected_texts: Vec<String> = selections
11642                    .iter()
11643                    .map(|selection| {
11644                        buffer
11645                            .text_for_range(selection.start..selection.end)
11646                            .collect()
11647                    })
11648                    .collect();
11649
11650                if reverse {
11651                    selected_texts.rotate_left(1);
11652                } else {
11653                    selected_texts.rotate_right(1);
11654                }
11655
11656                let mut offset_delta: i64 = 0;
11657                let mut new_selections = Vec::new();
11658                let edits: Vec<_> = selections
11659                    .iter()
11660                    .zip(selected_texts.iter())
11661                    .map(|(selection, new_text)| {
11662                        let old_len = (selection.end.0 - selection.start.0) as i64;
11663                        let new_len = new_text.len() as i64;
11664                        let adjusted_start =
11665                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11666                        let adjusted_end =
11667                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11668
11669                        new_selections.push(Selection {
11670                            id: selection.id,
11671                            start: adjusted_start,
11672                            end: adjusted_end,
11673                            reversed: selection.reversed,
11674                            goal: selection.goal,
11675                        });
11676
11677                        offset_delta += new_len - old_len;
11678                        (selection.start..selection.end, new_text.clone())
11679                    })
11680                    .collect();
11681                (edits, new_selections)
11682            } else {
11683                let mut all_rows: Vec<u32> = selections
11684                    .iter()
11685                    .map(|selection| buffer.offset_to_point(selection.start).row)
11686                    .collect();
11687                all_rows.sort_unstable();
11688                all_rows.dedup();
11689
11690                if all_rows.len() < 2 {
11691                    return;
11692                }
11693
11694                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11695                    .iter()
11696                    .map(|&row| {
11697                        let start = Point::new(row, 0);
11698                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11699                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11700                    })
11701                    .collect();
11702
11703                let mut line_texts: Vec<String> = line_ranges
11704                    .iter()
11705                    .map(|range| buffer.text_for_range(range.clone()).collect())
11706                    .collect();
11707
11708                if reverse {
11709                    line_texts.rotate_left(1);
11710                } else {
11711                    line_texts.rotate_right(1);
11712                }
11713
11714                let edits = line_ranges
11715                    .iter()
11716                    .zip(line_texts.iter())
11717                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11718                    .collect();
11719
11720                let num_rows = all_rows.len();
11721                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11722                    .iter()
11723                    .enumerate()
11724                    .map(|(i, &row)| (row, i))
11725                    .collect();
11726
11727                // Compute new line start offsets after rotation (handles CRLF)
11728                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11729                let first_line_start = line_ranges[0].start.0;
11730                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11731                for text in line_texts.iter().take(num_rows - 1) {
11732                    let prev_start = *new_line_starts.last().unwrap();
11733                    new_line_starts.push(prev_start + text.len() + newline_len);
11734                }
11735
11736                let new_selections = selections
11737                    .iter()
11738                    .map(|selection| {
11739                        let point = buffer.offset_to_point(selection.start);
11740                        let old_index = row_to_index[&point.row];
11741                        let new_index = if reverse {
11742                            (old_index + num_rows - 1) % num_rows
11743                        } else {
11744                            (old_index + 1) % num_rows
11745                        };
11746                        let new_offset =
11747                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11748                        Selection {
11749                            id: selection.id,
11750                            start: new_offset,
11751                            end: new_offset,
11752                            reversed: selection.reversed,
11753                            goal: selection.goal,
11754                        }
11755                    })
11756                    .collect();
11757
11758                (edits, new_selections)
11759            }
11760        };
11761
11762        self.transact(window, cx, |this, window, cx| {
11763            this.buffer.update(cx, |buffer, cx| {
11764                buffer.edit(edits, None, cx);
11765            });
11766            this.change_selections(Default::default(), window, cx, |s| {
11767                s.select(new_selections);
11768            });
11769        });
11770    }
11771
11772    fn manipulate_lines<M>(
11773        &mut self,
11774        window: &mut Window,
11775        cx: &mut Context<Self>,
11776        mut manipulate: M,
11777    ) where
11778        M: FnMut(&str) -> LineManipulationResult,
11779    {
11780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11781
11782        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11783        let buffer = self.buffer.read(cx).snapshot(cx);
11784
11785        let mut edits = Vec::new();
11786
11787        let selections = self.selections.all::<Point>(&display_map);
11788        let mut selections = selections.iter().peekable();
11789        let mut contiguous_row_selections = Vec::new();
11790        let mut new_selections = Vec::new();
11791        let mut added_lines = 0;
11792        let mut removed_lines = 0;
11793
11794        while let Some(selection) = selections.next() {
11795            let (start_row, end_row) = consume_contiguous_rows(
11796                &mut contiguous_row_selections,
11797                selection,
11798                &display_map,
11799                &mut selections,
11800            );
11801
11802            let start_point = Point::new(start_row.0, 0);
11803            let end_point = Point::new(
11804                end_row.previous_row().0,
11805                buffer.line_len(end_row.previous_row()),
11806            );
11807            let text = buffer
11808                .text_for_range(start_point..end_point)
11809                .collect::<String>();
11810
11811            let LineManipulationResult {
11812                new_text,
11813                line_count_before,
11814                line_count_after,
11815            } = manipulate(&text);
11816
11817            edits.push((start_point..end_point, new_text));
11818
11819            // Selections must change based on added and removed line count
11820            let start_row =
11821                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11822            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11823            new_selections.push(Selection {
11824                id: selection.id,
11825                start: start_row,
11826                end: end_row,
11827                goal: SelectionGoal::None,
11828                reversed: selection.reversed,
11829            });
11830
11831            if line_count_after > line_count_before {
11832                added_lines += line_count_after - line_count_before;
11833            } else if line_count_before > line_count_after {
11834                removed_lines += line_count_before - line_count_after;
11835            }
11836        }
11837
11838        self.transact(window, cx, |this, window, cx| {
11839            let buffer = this.buffer.update(cx, |buffer, cx| {
11840                buffer.edit(edits, None, cx);
11841                buffer.snapshot(cx)
11842            });
11843
11844            // Recalculate offsets on newly edited buffer
11845            let new_selections = new_selections
11846                .iter()
11847                .map(|s| {
11848                    let start_point = Point::new(s.start.0, 0);
11849                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11850                    Selection {
11851                        id: s.id,
11852                        start: buffer.point_to_offset(start_point),
11853                        end: buffer.point_to_offset(end_point),
11854                        goal: s.goal,
11855                        reversed: s.reversed,
11856                    }
11857                })
11858                .collect();
11859
11860            this.change_selections(Default::default(), window, cx, |s| {
11861                s.select(new_selections);
11862            });
11863
11864            this.request_autoscroll(Autoscroll::fit(), cx);
11865        });
11866    }
11867
11868    fn manipulate_immutable_lines<Fn>(
11869        &mut self,
11870        window: &mut Window,
11871        cx: &mut Context<Self>,
11872        mut callback: Fn,
11873    ) where
11874        Fn: FnMut(&mut Vec<&str>),
11875    {
11876        self.manipulate_lines(window, cx, |text| {
11877            let mut lines: Vec<&str> = text.split('\n').collect();
11878            let line_count_before = lines.len();
11879
11880            callback(&mut lines);
11881
11882            LineManipulationResult {
11883                new_text: lines.join("\n"),
11884                line_count_before,
11885                line_count_after: lines.len(),
11886            }
11887        });
11888    }
11889
11890    fn manipulate_mutable_lines<Fn>(
11891        &mut self,
11892        window: &mut Window,
11893        cx: &mut Context<Self>,
11894        mut callback: Fn,
11895    ) where
11896        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11897    {
11898        self.manipulate_lines(window, cx, |text| {
11899            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11900            let line_count_before = lines.len();
11901
11902            callback(&mut lines);
11903
11904            LineManipulationResult {
11905                new_text: lines.join("\n"),
11906                line_count_before,
11907                line_count_after: lines.len(),
11908            }
11909        });
11910    }
11911
11912    pub fn convert_indentation_to_spaces(
11913        &mut self,
11914        _: &ConvertIndentationToSpaces,
11915        window: &mut Window,
11916        cx: &mut Context<Self>,
11917    ) {
11918        let settings = self.buffer.read(cx).language_settings(cx);
11919        let tab_size = settings.tab_size.get() as usize;
11920
11921        self.manipulate_mutable_lines(window, cx, |lines| {
11922            // Allocates a reasonably sized scratch buffer once for the whole loop
11923            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11924            // Avoids recomputing spaces that could be inserted many times
11925            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11926                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11927                .collect();
11928
11929            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11930                let mut chars = line.as_ref().chars();
11931                let mut col = 0;
11932                let mut changed = false;
11933
11934                for ch in chars.by_ref() {
11935                    match ch {
11936                        ' ' => {
11937                            reindented_line.push(' ');
11938                            col += 1;
11939                        }
11940                        '\t' => {
11941                            // \t are converted to spaces depending on the current column
11942                            let spaces_len = tab_size - (col % tab_size);
11943                            reindented_line.extend(&space_cache[spaces_len - 1]);
11944                            col += spaces_len;
11945                            changed = true;
11946                        }
11947                        _ => {
11948                            // If we dont append before break, the character is consumed
11949                            reindented_line.push(ch);
11950                            break;
11951                        }
11952                    }
11953                }
11954
11955                if !changed {
11956                    reindented_line.clear();
11957                    continue;
11958                }
11959                // Append the rest of the line and replace old reference with new one
11960                reindented_line.extend(chars);
11961                *line = Cow::Owned(reindented_line.clone());
11962                reindented_line.clear();
11963            }
11964        });
11965    }
11966
11967    pub fn convert_indentation_to_tabs(
11968        &mut self,
11969        _: &ConvertIndentationToTabs,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        let settings = self.buffer.read(cx).language_settings(cx);
11974        let tab_size = settings.tab_size.get() as usize;
11975
11976        self.manipulate_mutable_lines(window, cx, |lines| {
11977            // Allocates a reasonably sized buffer once for the whole loop
11978            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11979            // Avoids recomputing spaces that could be inserted many times
11980            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11981                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11982                .collect();
11983
11984            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11985                let mut chars = line.chars();
11986                let mut spaces_count = 0;
11987                let mut first_non_indent_char = None;
11988                let mut changed = false;
11989
11990                for ch in chars.by_ref() {
11991                    match ch {
11992                        ' ' => {
11993                            // Keep track of spaces. Append \t when we reach tab_size
11994                            spaces_count += 1;
11995                            changed = true;
11996                            if spaces_count == tab_size {
11997                                reindented_line.push('\t');
11998                                spaces_count = 0;
11999                            }
12000                        }
12001                        '\t' => {
12002                            reindented_line.push('\t');
12003                            spaces_count = 0;
12004                        }
12005                        _ => {
12006                            // Dont append it yet, we might have remaining spaces
12007                            first_non_indent_char = Some(ch);
12008                            break;
12009                        }
12010                    }
12011                }
12012
12013                if !changed {
12014                    reindented_line.clear();
12015                    continue;
12016                }
12017                // Remaining spaces that didn't make a full tab stop
12018                if spaces_count > 0 {
12019                    reindented_line.extend(&space_cache[spaces_count - 1]);
12020                }
12021                // If we consume an extra character that was not indentation, add it back
12022                if let Some(extra_char) = first_non_indent_char {
12023                    reindented_line.push(extra_char);
12024                }
12025                // Append the rest of the line and replace old reference with new one
12026                reindented_line.extend(chars);
12027                *line = Cow::Owned(reindented_line.clone());
12028                reindented_line.clear();
12029            }
12030        });
12031    }
12032
12033    pub fn convert_to_upper_case(
12034        &mut self,
12035        _: &ConvertToUpperCase,
12036        window: &mut Window,
12037        cx: &mut Context<Self>,
12038    ) {
12039        self.manipulate_text(window, cx, |text| text.to_uppercase())
12040    }
12041
12042    pub fn convert_to_lower_case(
12043        &mut self,
12044        _: &ConvertToLowerCase,
12045        window: &mut Window,
12046        cx: &mut Context<Self>,
12047    ) {
12048        self.manipulate_text(window, cx, |text| text.to_lowercase())
12049    }
12050
12051    pub fn convert_to_title_case(
12052        &mut self,
12053        _: &ConvertToTitleCase,
12054        window: &mut Window,
12055        cx: &mut Context<Self>,
12056    ) {
12057        self.manipulate_text(window, cx, |text| {
12058            text.split('\n')
12059                .map(|line| line.to_case(Case::Title))
12060                .join("\n")
12061        })
12062    }
12063
12064    pub fn convert_to_snake_case(
12065        &mut self,
12066        _: &ConvertToSnakeCase,
12067        window: &mut Window,
12068        cx: &mut Context<Self>,
12069    ) {
12070        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12071    }
12072
12073    pub fn convert_to_kebab_case(
12074        &mut self,
12075        _: &ConvertToKebabCase,
12076        window: &mut Window,
12077        cx: &mut Context<Self>,
12078    ) {
12079        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12080    }
12081
12082    pub fn convert_to_upper_camel_case(
12083        &mut self,
12084        _: &ConvertToUpperCamelCase,
12085        window: &mut Window,
12086        cx: &mut Context<Self>,
12087    ) {
12088        self.manipulate_text(window, cx, |text| {
12089            text.split('\n')
12090                .map(|line| line.to_case(Case::UpperCamel))
12091                .join("\n")
12092        })
12093    }
12094
12095    pub fn convert_to_lower_camel_case(
12096        &mut self,
12097        _: &ConvertToLowerCamelCase,
12098        window: &mut Window,
12099        cx: &mut Context<Self>,
12100    ) {
12101        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12102    }
12103
12104    pub fn convert_to_opposite_case(
12105        &mut self,
12106        _: &ConvertToOppositeCase,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        self.manipulate_text(window, cx, |text| {
12111            text.chars()
12112                .fold(String::with_capacity(text.len()), |mut t, c| {
12113                    if c.is_uppercase() {
12114                        t.extend(c.to_lowercase());
12115                    } else {
12116                        t.extend(c.to_uppercase());
12117                    }
12118                    t
12119                })
12120        })
12121    }
12122
12123    pub fn convert_to_sentence_case(
12124        &mut self,
12125        _: &ConvertToSentenceCase,
12126        window: &mut Window,
12127        cx: &mut Context<Self>,
12128    ) {
12129        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12130    }
12131
12132    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12133        self.manipulate_text(window, cx, |text| {
12134            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12135            if has_upper_case_characters {
12136                text.to_lowercase()
12137            } else {
12138                text.to_uppercase()
12139            }
12140        })
12141    }
12142
12143    pub fn convert_to_rot13(
12144        &mut self,
12145        _: &ConvertToRot13,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        self.manipulate_text(window, cx, |text| {
12150            text.chars()
12151                .map(|c| match c {
12152                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12153                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12154                    _ => c,
12155                })
12156                .collect()
12157        })
12158    }
12159
12160    pub fn convert_to_rot47(
12161        &mut self,
12162        _: &ConvertToRot47,
12163        window: &mut Window,
12164        cx: &mut Context<Self>,
12165    ) {
12166        self.manipulate_text(window, cx, |text| {
12167            text.chars()
12168                .map(|c| {
12169                    let code_point = c as u32;
12170                    if code_point >= 33 && code_point <= 126 {
12171                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12172                    }
12173                    c
12174                })
12175                .collect()
12176        })
12177    }
12178
12179    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12180    where
12181        Fn: FnMut(&str) -> String,
12182    {
12183        let buffer = self.buffer.read(cx).snapshot(cx);
12184
12185        let mut new_selections = Vec::new();
12186        let mut edits = Vec::new();
12187        let mut selection_adjustment = 0isize;
12188
12189        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12190            let selection_is_empty = selection.is_empty();
12191
12192            let (start, end) = if selection_is_empty {
12193                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12194                (word_range.start, word_range.end)
12195            } else {
12196                (
12197                    buffer.point_to_offset(selection.start),
12198                    buffer.point_to_offset(selection.end),
12199                )
12200            };
12201
12202            let text = buffer.text_for_range(start..end).collect::<String>();
12203            let old_length = text.len() as isize;
12204            let text = callback(&text);
12205
12206            new_selections.push(Selection {
12207                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12208                end: MultiBufferOffset(
12209                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12210                ),
12211                goal: SelectionGoal::None,
12212                id: selection.id,
12213                reversed: selection.reversed,
12214            });
12215
12216            selection_adjustment += old_length - text.len() as isize;
12217
12218            edits.push((start..end, text));
12219        }
12220
12221        self.transact(window, cx, |this, window, cx| {
12222            this.buffer.update(cx, |buffer, cx| {
12223                buffer.edit(edits, None, cx);
12224            });
12225
12226            this.change_selections(Default::default(), window, cx, |s| {
12227                s.select(new_selections);
12228            });
12229
12230            this.request_autoscroll(Autoscroll::fit(), cx);
12231        });
12232    }
12233
12234    pub fn move_selection_on_drop(
12235        &mut self,
12236        selection: &Selection<Anchor>,
12237        target: DisplayPoint,
12238        is_cut: bool,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12243        let buffer = display_map.buffer_snapshot();
12244        let mut edits = Vec::new();
12245        let insert_point = display_map
12246            .clip_point(target, Bias::Left)
12247            .to_point(&display_map);
12248        let text = buffer
12249            .text_for_range(selection.start..selection.end)
12250            .collect::<String>();
12251        if is_cut {
12252            edits.push(((selection.start..selection.end), String::new()));
12253        }
12254        let insert_anchor = buffer.anchor_before(insert_point);
12255        edits.push(((insert_anchor..insert_anchor), text));
12256        let last_edit_start = insert_anchor.bias_left(buffer);
12257        let last_edit_end = insert_anchor.bias_right(buffer);
12258        self.transact(window, cx, |this, window, cx| {
12259            this.buffer.update(cx, |buffer, cx| {
12260                buffer.edit(edits, None, cx);
12261            });
12262            this.change_selections(Default::default(), window, cx, |s| {
12263                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12264            });
12265        });
12266    }
12267
12268    pub fn clear_selection_drag_state(&mut self) {
12269        self.selection_drag_state = SelectionDragState::None;
12270    }
12271
12272    pub fn duplicate(
12273        &mut self,
12274        upwards: bool,
12275        whole_lines: bool,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12280
12281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12282        let buffer = display_map.buffer_snapshot();
12283        let selections = self.selections.all::<Point>(&display_map);
12284
12285        let mut edits = Vec::new();
12286        let mut selections_iter = selections.iter().peekable();
12287        while let Some(selection) = selections_iter.next() {
12288            let mut rows = selection.spanned_rows(false, &display_map);
12289            // duplicate line-wise
12290            if whole_lines || selection.start == selection.end {
12291                // Avoid duplicating the same lines twice.
12292                while let Some(next_selection) = selections_iter.peek() {
12293                    let next_rows = next_selection.spanned_rows(false, &display_map);
12294                    if next_rows.start < rows.end {
12295                        rows.end = next_rows.end;
12296                        selections_iter.next().unwrap();
12297                    } else {
12298                        break;
12299                    }
12300                }
12301
12302                // Copy the text from the selected row region and splice it either at the start
12303                // or end of the region.
12304                let start = Point::new(rows.start.0, 0);
12305                let end = Point::new(
12306                    rows.end.previous_row().0,
12307                    buffer.line_len(rows.end.previous_row()),
12308                );
12309
12310                let mut text = buffer.text_for_range(start..end).collect::<String>();
12311
12312                let insert_location = if upwards {
12313                    // When duplicating upward, we need to insert before the current line.
12314                    // If we're on the last line and it doesn't end with a newline,
12315                    // we need to add a newline before the duplicated content.
12316                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12317                        && buffer.max_point().column > 0
12318                        && !text.ends_with('\n');
12319
12320                    if needs_leading_newline {
12321                        text.insert(0, '\n');
12322                        end
12323                    } else {
12324                        text.push('\n');
12325                        Point::new(rows.start.0, 0)
12326                    }
12327                } else {
12328                    text.push('\n');
12329                    start
12330                };
12331                edits.push((insert_location..insert_location, text));
12332            } else {
12333                // duplicate character-wise
12334                let start = selection.start;
12335                let end = selection.end;
12336                let text = buffer.text_for_range(start..end).collect::<String>();
12337                edits.push((selection.end..selection.end, text));
12338            }
12339        }
12340
12341        self.transact(window, cx, |this, window, cx| {
12342            this.buffer.update(cx, |buffer, cx| {
12343                buffer.edit(edits, None, cx);
12344            });
12345
12346            // When duplicating upward with whole lines, move the cursor to the duplicated line
12347            if upwards && whole_lines {
12348                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12349
12350                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12351                    let mut new_ranges = Vec::new();
12352                    let selections = s.all::<Point>(&display_map);
12353                    let mut selections_iter = selections.iter().peekable();
12354
12355                    while let Some(first_selection) = selections_iter.next() {
12356                        // Group contiguous selections together to find the total row span
12357                        let mut group_selections = vec![first_selection];
12358                        let mut rows = first_selection.spanned_rows(false, &display_map);
12359
12360                        while let Some(next_selection) = selections_iter.peek() {
12361                            let next_rows = next_selection.spanned_rows(false, &display_map);
12362                            if next_rows.start < rows.end {
12363                                rows.end = next_rows.end;
12364                                group_selections.push(selections_iter.next().unwrap());
12365                            } else {
12366                                break;
12367                            }
12368                        }
12369
12370                        let row_count = rows.end.0 - rows.start.0;
12371
12372                        // Move all selections in this group up by the total number of duplicated rows
12373                        for selection in group_selections {
12374                            let new_start = Point::new(
12375                                selection.start.row.saturating_sub(row_count),
12376                                selection.start.column,
12377                            );
12378
12379                            let new_end = Point::new(
12380                                selection.end.row.saturating_sub(row_count),
12381                                selection.end.column,
12382                            );
12383
12384                            new_ranges.push(new_start..new_end);
12385                        }
12386                    }
12387
12388                    s.select_ranges(new_ranges);
12389                });
12390            }
12391
12392            this.request_autoscroll(Autoscroll::fit(), cx);
12393        });
12394    }
12395
12396    pub fn duplicate_line_up(
12397        &mut self,
12398        _: &DuplicateLineUp,
12399        window: &mut Window,
12400        cx: &mut Context<Self>,
12401    ) {
12402        self.duplicate(true, true, window, cx);
12403    }
12404
12405    pub fn duplicate_line_down(
12406        &mut self,
12407        _: &DuplicateLineDown,
12408        window: &mut Window,
12409        cx: &mut Context<Self>,
12410    ) {
12411        self.duplicate(false, true, window, cx);
12412    }
12413
12414    pub fn duplicate_selection(
12415        &mut self,
12416        _: &DuplicateSelection,
12417        window: &mut Window,
12418        cx: &mut Context<Self>,
12419    ) {
12420        self.duplicate(false, false, window, cx);
12421    }
12422
12423    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12425        if self.mode.is_single_line() {
12426            cx.propagate();
12427            return;
12428        }
12429
12430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12431        let buffer = self.buffer.read(cx).snapshot(cx);
12432
12433        let mut edits = Vec::new();
12434        let mut unfold_ranges = Vec::new();
12435        let mut refold_creases = Vec::new();
12436
12437        let selections = self.selections.all::<Point>(&display_map);
12438        let mut selections = selections.iter().peekable();
12439        let mut contiguous_row_selections = Vec::new();
12440        let mut new_selections = Vec::new();
12441
12442        while let Some(selection) = selections.next() {
12443            // Find all the selections that span a contiguous row range
12444            let (start_row, end_row) = consume_contiguous_rows(
12445                &mut contiguous_row_selections,
12446                selection,
12447                &display_map,
12448                &mut selections,
12449            );
12450
12451            // Move the text spanned by the row range to be before the line preceding the row range
12452            if start_row.0 > 0 {
12453                let range_to_move = Point::new(
12454                    start_row.previous_row().0,
12455                    buffer.line_len(start_row.previous_row()),
12456                )
12457                    ..Point::new(
12458                        end_row.previous_row().0,
12459                        buffer.line_len(end_row.previous_row()),
12460                    );
12461                let insertion_point = display_map
12462                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12463                    .0;
12464
12465                // Don't move lines across excerpts
12466                if buffer
12467                    .excerpt_containing(insertion_point..range_to_move.end)
12468                    .is_some()
12469                {
12470                    let text = buffer
12471                        .text_for_range(range_to_move.clone())
12472                        .flat_map(|s| s.chars())
12473                        .skip(1)
12474                        .chain(['\n'])
12475                        .collect::<String>();
12476
12477                    edits.push((
12478                        buffer.anchor_after(range_to_move.start)
12479                            ..buffer.anchor_before(range_to_move.end),
12480                        String::new(),
12481                    ));
12482                    let insertion_anchor = buffer.anchor_after(insertion_point);
12483                    edits.push((insertion_anchor..insertion_anchor, text));
12484
12485                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12486
12487                    // Move selections up
12488                    new_selections.extend(contiguous_row_selections.drain(..).map(
12489                        |mut selection| {
12490                            selection.start.row -= row_delta;
12491                            selection.end.row -= row_delta;
12492                            selection
12493                        },
12494                    ));
12495
12496                    // Move folds up
12497                    unfold_ranges.push(range_to_move.clone());
12498                    for fold in display_map.folds_in_range(
12499                        buffer.anchor_before(range_to_move.start)
12500                            ..buffer.anchor_after(range_to_move.end),
12501                    ) {
12502                        let mut start = fold.range.start.to_point(&buffer);
12503                        let mut end = fold.range.end.to_point(&buffer);
12504                        start.row -= row_delta;
12505                        end.row -= row_delta;
12506                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12507                    }
12508                }
12509            }
12510
12511            // If we didn't move line(s), preserve the existing selections
12512            new_selections.append(&mut contiguous_row_selections);
12513        }
12514
12515        self.transact(window, cx, |this, window, cx| {
12516            this.unfold_ranges(&unfold_ranges, true, true, cx);
12517            this.buffer.update(cx, |buffer, cx| {
12518                for (range, text) in edits {
12519                    buffer.edit([(range, text)], None, cx);
12520                }
12521            });
12522            this.fold_creases(refold_creases, true, window, cx);
12523            this.change_selections(Default::default(), window, cx, |s| {
12524                s.select(new_selections);
12525            })
12526        });
12527    }
12528
12529    pub fn move_line_down(
12530        &mut self,
12531        _: &MoveLineDown,
12532        window: &mut Window,
12533        cx: &mut Context<Self>,
12534    ) {
12535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12536        if self.mode.is_single_line() {
12537            cx.propagate();
12538            return;
12539        }
12540
12541        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12542        let buffer = self.buffer.read(cx).snapshot(cx);
12543
12544        let mut edits = Vec::new();
12545        let mut unfold_ranges = Vec::new();
12546        let mut refold_creases = Vec::new();
12547
12548        let selections = self.selections.all::<Point>(&display_map);
12549        let mut selections = selections.iter().peekable();
12550        let mut contiguous_row_selections = Vec::new();
12551        let mut new_selections = Vec::new();
12552
12553        while let Some(selection) = selections.next() {
12554            // Find all the selections that span a contiguous row range
12555            let (start_row, end_row) = consume_contiguous_rows(
12556                &mut contiguous_row_selections,
12557                selection,
12558                &display_map,
12559                &mut selections,
12560            );
12561
12562            // Move the text spanned by the row range to be after the last line of the row range
12563            if end_row.0 <= buffer.max_point().row {
12564                let range_to_move =
12565                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12566                let insertion_point = display_map
12567                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12568                    .0;
12569
12570                // Don't move lines across excerpt boundaries
12571                if buffer
12572                    .excerpt_containing(range_to_move.start..insertion_point)
12573                    .is_some()
12574                {
12575                    let mut text = String::from("\n");
12576                    text.extend(buffer.text_for_range(range_to_move.clone()));
12577                    text.pop(); // Drop trailing newline
12578                    edits.push((
12579                        buffer.anchor_after(range_to_move.start)
12580                            ..buffer.anchor_before(range_to_move.end),
12581                        String::new(),
12582                    ));
12583                    let insertion_anchor = buffer.anchor_after(insertion_point);
12584                    edits.push((insertion_anchor..insertion_anchor, text));
12585
12586                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12587
12588                    // Move selections down
12589                    new_selections.extend(contiguous_row_selections.drain(..).map(
12590                        |mut selection| {
12591                            selection.start.row += row_delta;
12592                            selection.end.row += row_delta;
12593                            selection
12594                        },
12595                    ));
12596
12597                    // Move folds down
12598                    unfold_ranges.push(range_to_move.clone());
12599                    for fold in display_map.folds_in_range(
12600                        buffer.anchor_before(range_to_move.start)
12601                            ..buffer.anchor_after(range_to_move.end),
12602                    ) {
12603                        let mut start = fold.range.start.to_point(&buffer);
12604                        let mut end = fold.range.end.to_point(&buffer);
12605                        start.row += row_delta;
12606                        end.row += row_delta;
12607                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12608                    }
12609                }
12610            }
12611
12612            // If we didn't move line(s), preserve the existing selections
12613            new_selections.append(&mut contiguous_row_selections);
12614        }
12615
12616        self.transact(window, cx, |this, window, cx| {
12617            this.unfold_ranges(&unfold_ranges, true, true, cx);
12618            this.buffer.update(cx, |buffer, cx| {
12619                for (range, text) in edits {
12620                    buffer.edit([(range, text)], None, cx);
12621                }
12622            });
12623            this.fold_creases(refold_creases, true, window, cx);
12624            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12625        });
12626    }
12627
12628    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12630        let text_layout_details = &self.text_layout_details(window);
12631        self.transact(window, cx, |this, window, cx| {
12632            let edits = this.change_selections(Default::default(), window, cx, |s| {
12633                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12634                s.move_with(|display_map, selection| {
12635                    if !selection.is_empty() {
12636                        return;
12637                    }
12638
12639                    let mut head = selection.head();
12640                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12641                    if head.column() == display_map.line_len(head.row()) {
12642                        transpose_offset = display_map
12643                            .buffer_snapshot()
12644                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12645                    }
12646
12647                    if transpose_offset == MultiBufferOffset(0) {
12648                        return;
12649                    }
12650
12651                    *head.column_mut() += 1;
12652                    head = display_map.clip_point(head, Bias::Right);
12653                    let goal = SelectionGoal::HorizontalPosition(
12654                        display_map
12655                            .x_for_display_point(head, text_layout_details)
12656                            .into(),
12657                    );
12658                    selection.collapse_to(head, goal);
12659
12660                    let transpose_start = display_map
12661                        .buffer_snapshot()
12662                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12663                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12664                        let transpose_end = display_map
12665                            .buffer_snapshot()
12666                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12667                        if let Some(ch) = display_map
12668                            .buffer_snapshot()
12669                            .chars_at(transpose_start)
12670                            .next()
12671                        {
12672                            edits.push((transpose_start..transpose_offset, String::new()));
12673                            edits.push((transpose_end..transpose_end, ch.to_string()));
12674                        }
12675                    }
12676                });
12677                edits
12678            });
12679            this.buffer
12680                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12681            let selections = this
12682                .selections
12683                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12684            this.change_selections(Default::default(), window, cx, |s| {
12685                s.select(selections);
12686            });
12687        });
12688    }
12689
12690    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12692        if self.mode.is_single_line() {
12693            cx.propagate();
12694            return;
12695        }
12696
12697        self.rewrap_impl(RewrapOptions::default(), cx)
12698    }
12699
12700    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12701        let buffer = self.buffer.read(cx).snapshot(cx);
12702        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12703
12704        #[derive(Clone, Debug, PartialEq)]
12705        enum CommentFormat {
12706            /// single line comment, with prefix for line
12707            Line(String),
12708            /// single line within a block comment, with prefix for line
12709            BlockLine(String),
12710            /// a single line of a block comment that includes the initial delimiter
12711            BlockCommentWithStart(BlockCommentConfig),
12712            /// a single line of a block comment that includes the ending delimiter
12713            BlockCommentWithEnd(BlockCommentConfig),
12714        }
12715
12716        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12717        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12718            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12719                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12720                .peekable();
12721
12722            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12723                row
12724            } else {
12725                return Vec::new();
12726            };
12727
12728            let language_settings = buffer.language_settings_at(selection.head(), cx);
12729            let language_scope = buffer.language_scope_at(selection.head());
12730
12731            let indent_and_prefix_for_row =
12732                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12733                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12734                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12735                        &language_scope
12736                    {
12737                        let indent_end = Point::new(row, indent.len);
12738                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12739                        let line_text_after_indent = buffer
12740                            .text_for_range(indent_end..line_end)
12741                            .collect::<String>();
12742
12743                        let is_within_comment_override = buffer
12744                            .language_scope_at(indent_end)
12745                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12746                        let comment_delimiters = if is_within_comment_override {
12747                            // we are within a comment syntax node, but we don't
12748                            // yet know what kind of comment: block, doc or line
12749                            match (
12750                                language_scope.documentation_comment(),
12751                                language_scope.block_comment(),
12752                            ) {
12753                                (Some(config), _) | (_, Some(config))
12754                                    if buffer.contains_str_at(indent_end, &config.start) =>
12755                                {
12756                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12757                                }
12758                                (Some(config), _) | (_, Some(config))
12759                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12760                                {
12761                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12762                                }
12763                                (Some(config), _) | (_, Some(config))
12764                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12765                                {
12766                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12767                                }
12768                                (_, _) => language_scope
12769                                    .line_comment_prefixes()
12770                                    .iter()
12771                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12772                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12773                            }
12774                        } else {
12775                            // we not in an overridden comment node, but we may
12776                            // be within a non-overridden line comment node
12777                            language_scope
12778                                .line_comment_prefixes()
12779                                .iter()
12780                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12781                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12782                        };
12783
12784                        let rewrap_prefix = language_scope
12785                            .rewrap_prefixes()
12786                            .iter()
12787                            .find_map(|prefix_regex| {
12788                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12789                                    if mat.start() == 0 {
12790                                        Some(mat.as_str().to_string())
12791                                    } else {
12792                                        None
12793                                    }
12794                                })
12795                            })
12796                            .flatten();
12797                        (comment_delimiters, rewrap_prefix)
12798                    } else {
12799                        (None, None)
12800                    };
12801                    (indent, comment_prefix, rewrap_prefix)
12802                };
12803
12804            let mut ranges = Vec::new();
12805            let from_empty_selection = selection.is_empty();
12806
12807            let mut current_range_start = first_row;
12808            let mut prev_row = first_row;
12809            let (
12810                mut current_range_indent,
12811                mut current_range_comment_delimiters,
12812                mut current_range_rewrap_prefix,
12813            ) = indent_and_prefix_for_row(first_row);
12814
12815            for row in non_blank_rows_iter.skip(1) {
12816                let has_paragraph_break = row > prev_row + 1;
12817
12818                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12819                    indent_and_prefix_for_row(row);
12820
12821                let has_indent_change = row_indent != current_range_indent;
12822                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12823
12824                let has_boundary_change = has_comment_change
12825                    || row_rewrap_prefix.is_some()
12826                    || (has_indent_change && current_range_comment_delimiters.is_some());
12827
12828                if has_paragraph_break || has_boundary_change {
12829                    ranges.push((
12830                        language_settings.clone(),
12831                        Point::new(current_range_start, 0)
12832                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12833                        current_range_indent,
12834                        current_range_comment_delimiters.clone(),
12835                        current_range_rewrap_prefix.clone(),
12836                        from_empty_selection,
12837                    ));
12838                    current_range_start = row;
12839                    current_range_indent = row_indent;
12840                    current_range_comment_delimiters = row_comment_delimiters;
12841                    current_range_rewrap_prefix = row_rewrap_prefix;
12842                }
12843                prev_row = row;
12844            }
12845
12846            ranges.push((
12847                language_settings.clone(),
12848                Point::new(current_range_start, 0)
12849                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12850                current_range_indent,
12851                current_range_comment_delimiters,
12852                current_range_rewrap_prefix,
12853                from_empty_selection,
12854            ));
12855
12856            ranges
12857        });
12858
12859        let mut edits = Vec::new();
12860        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12861
12862        for (
12863            language_settings,
12864            wrap_range,
12865            mut indent_size,
12866            comment_prefix,
12867            rewrap_prefix,
12868            from_empty_selection,
12869        ) in wrap_ranges
12870        {
12871            let mut start_row = wrap_range.start.row;
12872            let mut end_row = wrap_range.end.row;
12873
12874            // Skip selections that overlap with a range that has already been rewrapped.
12875            let selection_range = start_row..end_row;
12876            if rewrapped_row_ranges
12877                .iter()
12878                .any(|range| range.overlaps(&selection_range))
12879            {
12880                continue;
12881            }
12882
12883            let tab_size = language_settings.tab_size;
12884
12885            let (line_prefix, inside_comment) = match &comment_prefix {
12886                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12887                    (Some(prefix.as_str()), true)
12888                }
12889                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12890                    (Some(prefix.as_ref()), true)
12891                }
12892                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12893                    start: _,
12894                    end: _,
12895                    prefix,
12896                    tab_size,
12897                })) => {
12898                    indent_size.len += tab_size;
12899                    (Some(prefix.as_ref()), true)
12900                }
12901                None => (None, false),
12902            };
12903            let indent_prefix = indent_size.chars().collect::<String>();
12904            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12905
12906            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12907                RewrapBehavior::InComments => inside_comment,
12908                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12909                RewrapBehavior::Anywhere => true,
12910            };
12911
12912            let should_rewrap = options.override_language_settings
12913                || allow_rewrap_based_on_language
12914                || self.hard_wrap.is_some();
12915            if !should_rewrap {
12916                continue;
12917            }
12918
12919            if from_empty_selection {
12920                'expand_upwards: while start_row > 0 {
12921                    let prev_row = start_row - 1;
12922                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12923                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12924                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12925                    {
12926                        start_row = prev_row;
12927                    } else {
12928                        break 'expand_upwards;
12929                    }
12930                }
12931
12932                'expand_downwards: while end_row < buffer.max_point().row {
12933                    let next_row = end_row + 1;
12934                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12935                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12936                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12937                    {
12938                        end_row = next_row;
12939                    } else {
12940                        break 'expand_downwards;
12941                    }
12942                }
12943            }
12944
12945            let start = Point::new(start_row, 0);
12946            let start_offset = ToOffset::to_offset(&start, &buffer);
12947            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12948            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12949            let mut first_line_delimiter = None;
12950            let mut last_line_delimiter = None;
12951            let Some(lines_without_prefixes) = selection_text
12952                .lines()
12953                .enumerate()
12954                .map(|(ix, line)| {
12955                    let line_trimmed = line.trim_start();
12956                    if rewrap_prefix.is_some() && ix > 0 {
12957                        Ok(line_trimmed)
12958                    } else if let Some(
12959                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12960                            start,
12961                            prefix,
12962                            end,
12963                            tab_size,
12964                        })
12965                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12966                            start,
12967                            prefix,
12968                            end,
12969                            tab_size,
12970                        }),
12971                    ) = &comment_prefix
12972                    {
12973                        let line_trimmed = line_trimmed
12974                            .strip_prefix(start.as_ref())
12975                            .map(|s| {
12976                                let mut indent_size = indent_size;
12977                                indent_size.len -= tab_size;
12978                                let indent_prefix: String = indent_size.chars().collect();
12979                                first_line_delimiter = Some((indent_prefix, start));
12980                                s.trim_start()
12981                            })
12982                            .unwrap_or(line_trimmed);
12983                        let line_trimmed = line_trimmed
12984                            .strip_suffix(end.as_ref())
12985                            .map(|s| {
12986                                last_line_delimiter = Some(end);
12987                                s.trim_end()
12988                            })
12989                            .unwrap_or(line_trimmed);
12990                        let line_trimmed = line_trimmed
12991                            .strip_prefix(prefix.as_ref())
12992                            .unwrap_or(line_trimmed);
12993                        Ok(line_trimmed)
12994                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12995                        line_trimmed.strip_prefix(prefix).with_context(|| {
12996                            format!("line did not start with prefix {prefix:?}: {line:?}")
12997                        })
12998                    } else {
12999                        line_trimmed
13000                            .strip_prefix(&line_prefix.trim_start())
13001                            .with_context(|| {
13002                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13003                            })
13004                    }
13005                })
13006                .collect::<Result<Vec<_>, _>>()
13007                .log_err()
13008            else {
13009                continue;
13010            };
13011
13012            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13013                buffer
13014                    .language_settings_at(Point::new(start_row, 0), cx)
13015                    .preferred_line_length as usize
13016            });
13017
13018            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13019                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13020            } else {
13021                line_prefix.clone()
13022            };
13023
13024            let wrapped_text = {
13025                let mut wrapped_text = wrap_with_prefix(
13026                    line_prefix,
13027                    subsequent_lines_prefix,
13028                    lines_without_prefixes.join("\n"),
13029                    wrap_column,
13030                    tab_size,
13031                    options.preserve_existing_whitespace,
13032                );
13033
13034                if let Some((indent, delimiter)) = first_line_delimiter {
13035                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13036                }
13037                if let Some(last_line) = last_line_delimiter {
13038                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13039                }
13040
13041                wrapped_text
13042            };
13043
13044            // TODO: should always use char-based diff while still supporting cursor behavior that
13045            // matches vim.
13046            let mut diff_options = DiffOptions::default();
13047            if options.override_language_settings {
13048                diff_options.max_word_diff_len = 0;
13049                diff_options.max_word_diff_line_count = 0;
13050            } else {
13051                diff_options.max_word_diff_len = usize::MAX;
13052                diff_options.max_word_diff_line_count = usize::MAX;
13053            }
13054
13055            for (old_range, new_text) in
13056                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13057            {
13058                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13059                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13060                edits.push((edit_start..edit_end, new_text));
13061            }
13062
13063            rewrapped_row_ranges.push(start_row..=end_row);
13064        }
13065
13066        self.buffer
13067            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13068    }
13069
13070    pub fn cut_common(
13071        &mut self,
13072        cut_no_selection_line: bool,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) -> ClipboardItem {
13076        let mut text = String::new();
13077        let buffer = self.buffer.read(cx).snapshot(cx);
13078        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13079        let mut clipboard_selections = Vec::with_capacity(selections.len());
13080        {
13081            let max_point = buffer.max_point();
13082            let mut is_first = true;
13083            let mut prev_selection_was_entire_line = false;
13084            for selection in &mut selections {
13085                let is_entire_line =
13086                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13087                if is_entire_line {
13088                    selection.start = Point::new(selection.start.row, 0);
13089                    if !selection.is_empty() && selection.end.column == 0 {
13090                        selection.end = cmp::min(max_point, selection.end);
13091                    } else {
13092                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13093                    }
13094                    selection.goal = SelectionGoal::None;
13095                }
13096                if is_first {
13097                    is_first = false;
13098                } else if !prev_selection_was_entire_line {
13099                    text += "\n";
13100                }
13101                prev_selection_was_entire_line = is_entire_line;
13102                let mut len = 0;
13103                for chunk in buffer.text_for_range(selection.start..selection.end) {
13104                    text.push_str(chunk);
13105                    len += chunk.len();
13106                }
13107
13108                clipboard_selections.push(ClipboardSelection::for_buffer(
13109                    len,
13110                    is_entire_line,
13111                    selection.range(),
13112                    &buffer,
13113                    self.project.as_ref(),
13114                    cx,
13115                ));
13116            }
13117        }
13118
13119        self.transact(window, cx, |this, window, cx| {
13120            this.change_selections(Default::default(), window, cx, |s| {
13121                s.select(selections);
13122            });
13123            this.insert("", window, cx);
13124        });
13125        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13126    }
13127
13128    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13130        let item = self.cut_common(true, window, cx);
13131        cx.write_to_clipboard(item);
13132    }
13133
13134    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13136        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13137            s.move_with(|snapshot, sel| {
13138                if sel.is_empty() {
13139                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13140                }
13141                if sel.is_empty() {
13142                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13143                }
13144            });
13145        });
13146        let item = self.cut_common(false, window, cx);
13147        cx.set_global(KillRing(item))
13148    }
13149
13150    pub fn kill_ring_yank(
13151        &mut self,
13152        _: &KillRingYank,
13153        window: &mut Window,
13154        cx: &mut Context<Self>,
13155    ) {
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13157        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13158            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13159                (kill_ring.text().to_string(), kill_ring.metadata_json())
13160            } else {
13161                return;
13162            }
13163        } else {
13164            return;
13165        };
13166        self.do_paste(&text, metadata, false, window, cx);
13167    }
13168
13169    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13170        self.do_copy(true, cx);
13171    }
13172
13173    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13174        self.do_copy(false, cx);
13175    }
13176
13177    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13178        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13179        let buffer = self.buffer.read(cx).read(cx);
13180        let mut text = String::new();
13181
13182        let mut clipboard_selections = Vec::with_capacity(selections.len());
13183        {
13184            let max_point = buffer.max_point();
13185            let mut is_first = true;
13186            let mut prev_selection_was_entire_line = false;
13187            for selection in &selections {
13188                let mut start = selection.start;
13189                let mut end = selection.end;
13190                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13191                let mut add_trailing_newline = false;
13192                if is_entire_line {
13193                    start = Point::new(start.row, 0);
13194                    let next_line_start = Point::new(end.row + 1, 0);
13195                    if next_line_start <= max_point {
13196                        end = next_line_start;
13197                    } else {
13198                        // We're on the last line without a trailing newline.
13199                        // Copy to the end of the line and add a newline afterwards.
13200                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13201                        add_trailing_newline = true;
13202                    }
13203                }
13204
13205                let mut trimmed_selections = Vec::new();
13206                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13207                    let row = MultiBufferRow(start.row);
13208                    let first_indent = buffer.indent_size_for_line(row);
13209                    if first_indent.len == 0 || start.column > first_indent.len {
13210                        trimmed_selections.push(start..end);
13211                    } else {
13212                        trimmed_selections.push(
13213                            Point::new(row.0, first_indent.len)
13214                                ..Point::new(row.0, buffer.line_len(row)),
13215                        );
13216                        for row in start.row + 1..=end.row {
13217                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13218                            if row == end.row {
13219                                line_len = end.column;
13220                            }
13221                            if line_len == 0 {
13222                                trimmed_selections
13223                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13224                                continue;
13225                            }
13226                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13227                            if row_indent_size.len >= first_indent.len {
13228                                trimmed_selections.push(
13229                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13230                                );
13231                            } else {
13232                                trimmed_selections.clear();
13233                                trimmed_selections.push(start..end);
13234                                break;
13235                            }
13236                        }
13237                    }
13238                } else {
13239                    trimmed_selections.push(start..end);
13240                }
13241
13242                for trimmed_range in trimmed_selections {
13243                    if is_first {
13244                        is_first = false;
13245                    } else if !prev_selection_was_entire_line {
13246                        text += "\n";
13247                    }
13248                    prev_selection_was_entire_line = is_entire_line;
13249                    let mut len = 0;
13250                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13251                        text.push_str(chunk);
13252                        len += chunk.len();
13253                    }
13254                    if add_trailing_newline {
13255                        text.push('\n');
13256                        len += 1;
13257                    }
13258                    clipboard_selections.push(ClipboardSelection::for_buffer(
13259                        len,
13260                        is_entire_line,
13261                        trimmed_range,
13262                        &buffer,
13263                        self.project.as_ref(),
13264                        cx,
13265                    ));
13266                }
13267            }
13268        }
13269
13270        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13271            text,
13272            clipboard_selections,
13273        ));
13274    }
13275
13276    pub fn do_paste(
13277        &mut self,
13278        text: &String,
13279        clipboard_selections: Option<Vec<ClipboardSelection>>,
13280        handle_entire_lines: bool,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if self.read_only(cx) {
13285            return;
13286        }
13287
13288        let clipboard_text = Cow::Borrowed(text.as_str());
13289
13290        self.transact(window, cx, |this, window, cx| {
13291            let had_active_edit_prediction = this.has_active_edit_prediction();
13292            let display_map = this.display_snapshot(cx);
13293            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13294            let cursor_offset = this
13295                .selections
13296                .last::<MultiBufferOffset>(&display_map)
13297                .head();
13298
13299            if let Some(mut clipboard_selections) = clipboard_selections {
13300                let all_selections_were_entire_line =
13301                    clipboard_selections.iter().all(|s| s.is_entire_line);
13302                let first_selection_indent_column =
13303                    clipboard_selections.first().map(|s| s.first_line_indent);
13304                if clipboard_selections.len() != old_selections.len() {
13305                    clipboard_selections.drain(..);
13306                }
13307                let mut auto_indent_on_paste = true;
13308
13309                this.buffer.update(cx, |buffer, cx| {
13310                    let snapshot = buffer.read(cx);
13311                    auto_indent_on_paste = snapshot
13312                        .language_settings_at(cursor_offset, cx)
13313                        .auto_indent_on_paste;
13314
13315                    let mut start_offset = 0;
13316                    let mut edits = Vec::new();
13317                    let mut original_indent_columns = Vec::new();
13318                    for (ix, selection) in old_selections.iter().enumerate() {
13319                        let to_insert;
13320                        let entire_line;
13321                        let original_indent_column;
13322                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13323                            let end_offset = start_offset + clipboard_selection.len;
13324                            to_insert = &clipboard_text[start_offset..end_offset];
13325                            entire_line = clipboard_selection.is_entire_line;
13326                            start_offset = if entire_line {
13327                                end_offset
13328                            } else {
13329                                end_offset + 1
13330                            };
13331                            original_indent_column = Some(clipboard_selection.first_line_indent);
13332                        } else {
13333                            to_insert = &*clipboard_text;
13334                            entire_line = all_selections_were_entire_line;
13335                            original_indent_column = first_selection_indent_column
13336                        }
13337
13338                        let (range, to_insert) =
13339                            if selection.is_empty() && handle_entire_lines && entire_line {
13340                                // If the corresponding selection was empty when this slice of the
13341                                // clipboard text was written, then the entire line containing the
13342                                // selection was copied. If this selection is also currently empty,
13343                                // then paste the line before the current line of the buffer.
13344                                let column = selection.start.to_point(&snapshot).column as usize;
13345                                let line_start = selection.start - column;
13346                                (line_start..line_start, Cow::Borrowed(to_insert))
13347                            } else {
13348                                let language = snapshot.language_at(selection.head());
13349                                let range = selection.range();
13350                                if let Some(language) = language
13351                                    && language.name() == "Markdown".into()
13352                                {
13353                                    edit_for_markdown_paste(
13354                                        &snapshot,
13355                                        range,
13356                                        to_insert,
13357                                        url::Url::parse(to_insert).ok(),
13358                                    )
13359                                } else {
13360                                    (range, Cow::Borrowed(to_insert))
13361                                }
13362                            };
13363
13364                        edits.push((range, to_insert));
13365                        original_indent_columns.push(original_indent_column);
13366                    }
13367                    drop(snapshot);
13368
13369                    buffer.edit(
13370                        edits,
13371                        if auto_indent_on_paste {
13372                            Some(AutoindentMode::Block {
13373                                original_indent_columns,
13374                            })
13375                        } else {
13376                            None
13377                        },
13378                        cx,
13379                    );
13380                });
13381
13382                let selections = this
13383                    .selections
13384                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13385                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13386            } else {
13387                let url = url::Url::parse(&clipboard_text).ok();
13388
13389                let auto_indent_mode = if !clipboard_text.is_empty() {
13390                    Some(AutoindentMode::Block {
13391                        original_indent_columns: Vec::new(),
13392                    })
13393                } else {
13394                    None
13395                };
13396
13397                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13398                    let snapshot = buffer.snapshot(cx);
13399
13400                    let anchors = old_selections
13401                        .iter()
13402                        .map(|s| {
13403                            let anchor = snapshot.anchor_after(s.head());
13404                            s.map(|_| anchor)
13405                        })
13406                        .collect::<Vec<_>>();
13407
13408                    let mut edits = Vec::new();
13409
13410                    for selection in old_selections.iter() {
13411                        let language = snapshot.language_at(selection.head());
13412                        let range = selection.range();
13413
13414                        let (edit_range, edit_text) = if let Some(language) = language
13415                            && language.name() == "Markdown".into()
13416                        {
13417                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13418                        } else {
13419                            (range, clipboard_text.clone())
13420                        };
13421
13422                        edits.push((edit_range, edit_text));
13423                    }
13424
13425                    drop(snapshot);
13426                    buffer.edit(edits, auto_indent_mode, cx);
13427
13428                    anchors
13429                });
13430
13431                this.change_selections(Default::default(), window, cx, |s| {
13432                    s.select_anchors(selection_anchors);
13433                });
13434            }
13435
13436            //   🤔                 |    ..     | show_in_menu |
13437            // | ..                  |   true        true
13438            // | had_edit_prediction |   false       true
13439
13440            let trigger_in_words =
13441                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13442
13443            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13444        });
13445    }
13446
13447    pub fn diff_clipboard_with_selection(
13448        &mut self,
13449        _: &DiffClipboardWithSelection,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        let selections = self
13454            .selections
13455            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13456
13457        if selections.is_empty() {
13458            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13459            return;
13460        };
13461
13462        let clipboard_text = match cx.read_from_clipboard() {
13463            Some(item) => match item.entries().first() {
13464                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13465                _ => None,
13466            },
13467            None => None,
13468        };
13469
13470        let Some(clipboard_text) = clipboard_text else {
13471            log::warn!("Clipboard doesn't contain text.");
13472            return;
13473        };
13474
13475        window.dispatch_action(
13476            Box::new(DiffClipboardWithSelectionData {
13477                clipboard_text,
13478                editor: cx.entity(),
13479            }),
13480            cx,
13481        );
13482    }
13483
13484    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13486        if let Some(item) = cx.read_from_clipboard() {
13487            let entries = item.entries();
13488
13489            match entries.first() {
13490                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13491                // of all the pasted entries.
13492                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13493                    .do_paste(
13494                        clipboard_string.text(),
13495                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13496                        true,
13497                        window,
13498                        cx,
13499                    ),
13500                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13501            }
13502        }
13503    }
13504
13505    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13506        if self.read_only(cx) {
13507            return;
13508        }
13509
13510        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13511
13512        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13513            if let Some((selections, _)) =
13514                self.selection_history.transaction(transaction_id).cloned()
13515            {
13516                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13517                    s.select_anchors(selections.to_vec());
13518                });
13519            } else {
13520                log::error!(
13521                    "No entry in selection_history found for undo. \
13522                     This may correspond to a bug where undo does not update the selection. \
13523                     If this is occurring, please add details to \
13524                     https://github.com/zed-industries/zed/issues/22692"
13525                );
13526            }
13527            self.request_autoscroll(Autoscroll::fit(), cx);
13528            self.unmark_text(window, cx);
13529            self.refresh_edit_prediction(true, false, window, cx);
13530            cx.emit(EditorEvent::Edited { transaction_id });
13531            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13532        }
13533    }
13534
13535    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13536        if self.read_only(cx) {
13537            return;
13538        }
13539
13540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13541
13542        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13543            if let Some((_, Some(selections))) =
13544                self.selection_history.transaction(transaction_id).cloned()
13545            {
13546                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13547                    s.select_anchors(selections.to_vec());
13548                });
13549            } else {
13550                log::error!(
13551                    "No entry in selection_history found for redo. \
13552                     This may correspond to a bug where undo does not update the selection. \
13553                     If this is occurring, please add details to \
13554                     https://github.com/zed-industries/zed/issues/22692"
13555                );
13556            }
13557            self.request_autoscroll(Autoscroll::fit(), cx);
13558            self.unmark_text(window, cx);
13559            self.refresh_edit_prediction(true, false, window, cx);
13560            cx.emit(EditorEvent::Edited { transaction_id });
13561        }
13562    }
13563
13564    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13565        self.buffer
13566            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13567    }
13568
13569    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13570        self.buffer
13571            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13572    }
13573
13574    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13576        self.change_selections(Default::default(), window, cx, |s| {
13577            s.move_with(|map, selection| {
13578                let cursor = if selection.is_empty() {
13579                    movement::left(map, selection.start)
13580                } else {
13581                    selection.start
13582                };
13583                selection.collapse_to(cursor, SelectionGoal::None);
13584            });
13585        })
13586    }
13587
13588    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13592        })
13593    }
13594
13595    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13597        self.change_selections(Default::default(), window, cx, |s| {
13598            s.move_with(|map, selection| {
13599                let cursor = if selection.is_empty() {
13600                    movement::right(map, selection.end)
13601                } else {
13602                    selection.end
13603                };
13604                selection.collapse_to(cursor, SelectionGoal::None)
13605            });
13606        })
13607    }
13608
13609    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13613        });
13614    }
13615
13616    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13617        if self.take_rename(true, window, cx).is_some() {
13618            return;
13619        }
13620
13621        if self.mode.is_single_line() {
13622            cx.propagate();
13623            return;
13624        }
13625
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627
13628        let text_layout_details = &self.text_layout_details(window);
13629        let selection_count = self.selections.count();
13630        let first_selection = self.selections.first_anchor();
13631
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_with(|map, selection| {
13634                if !selection.is_empty() {
13635                    selection.goal = SelectionGoal::None;
13636                }
13637                let (cursor, goal) = movement::up(
13638                    map,
13639                    selection.start,
13640                    selection.goal,
13641                    false,
13642                    text_layout_details,
13643                );
13644                selection.collapse_to(cursor, goal);
13645            });
13646        });
13647
13648        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13649        {
13650            cx.propagate();
13651        }
13652    }
13653
13654    pub fn move_up_by_lines(
13655        &mut self,
13656        action: &MoveUpByLines,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        if self.take_rename(true, window, cx).is_some() {
13661            return;
13662        }
13663
13664        if self.mode.is_single_line() {
13665            cx.propagate();
13666            return;
13667        }
13668
13669        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13670
13671        let text_layout_details = &self.text_layout_details(window);
13672
13673        self.change_selections(Default::default(), window, cx, |s| {
13674            s.move_with(|map, selection| {
13675                if !selection.is_empty() {
13676                    selection.goal = SelectionGoal::None;
13677                }
13678                let (cursor, goal) = movement::up_by_rows(
13679                    map,
13680                    selection.start,
13681                    action.lines,
13682                    selection.goal,
13683                    false,
13684                    text_layout_details,
13685                );
13686                selection.collapse_to(cursor, goal);
13687            });
13688        })
13689    }
13690
13691    pub fn move_down_by_lines(
13692        &mut self,
13693        action: &MoveDownByLines,
13694        window: &mut Window,
13695        cx: &mut Context<Self>,
13696    ) {
13697        if self.take_rename(true, window, cx).is_some() {
13698            return;
13699        }
13700
13701        if self.mode.is_single_line() {
13702            cx.propagate();
13703            return;
13704        }
13705
13706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13707
13708        let text_layout_details = &self.text_layout_details(window);
13709
13710        self.change_selections(Default::default(), window, cx, |s| {
13711            s.move_with(|map, selection| {
13712                if !selection.is_empty() {
13713                    selection.goal = SelectionGoal::None;
13714                }
13715                let (cursor, goal) = movement::down_by_rows(
13716                    map,
13717                    selection.start,
13718                    action.lines,
13719                    selection.goal,
13720                    false,
13721                    text_layout_details,
13722                );
13723                selection.collapse_to(cursor, goal);
13724            });
13725        })
13726    }
13727
13728    pub fn select_down_by_lines(
13729        &mut self,
13730        action: &SelectDownByLines,
13731        window: &mut Window,
13732        cx: &mut Context<Self>,
13733    ) {
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        let text_layout_details = &self.text_layout_details(window);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_heads_with(|map, head, goal| {
13738                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13739            })
13740        })
13741    }
13742
13743    pub fn select_up_by_lines(
13744        &mut self,
13745        action: &SelectUpByLines,
13746        window: &mut Window,
13747        cx: &mut Context<Self>,
13748    ) {
13749        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13750        let text_layout_details = &self.text_layout_details(window);
13751        self.change_selections(Default::default(), window, cx, |s| {
13752            s.move_heads_with(|map, head, goal| {
13753                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13754            })
13755        })
13756    }
13757
13758    pub fn select_page_up(
13759        &mut self,
13760        _: &SelectPageUp,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        let Some(row_count) = self.visible_row_count() else {
13765            return;
13766        };
13767
13768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13769
13770        let text_layout_details = &self.text_layout_details(window);
13771
13772        self.change_selections(Default::default(), window, cx, |s| {
13773            s.move_heads_with(|map, head, goal| {
13774                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13775            })
13776        })
13777    }
13778
13779    pub fn move_page_up(
13780        &mut self,
13781        action: &MovePageUp,
13782        window: &mut Window,
13783        cx: &mut Context<Self>,
13784    ) {
13785        if self.take_rename(true, window, cx).is_some() {
13786            return;
13787        }
13788
13789        if self
13790            .context_menu
13791            .borrow_mut()
13792            .as_mut()
13793            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13794            .unwrap_or(false)
13795        {
13796            return;
13797        }
13798
13799        if matches!(self.mode, EditorMode::SingleLine) {
13800            cx.propagate();
13801            return;
13802        }
13803
13804        let Some(row_count) = self.visible_row_count() else {
13805            return;
13806        };
13807
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809
13810        let effects = if action.center_cursor {
13811            SelectionEffects::scroll(Autoscroll::center())
13812        } else {
13813            SelectionEffects::default()
13814        };
13815
13816        let text_layout_details = &self.text_layout_details(window);
13817
13818        self.change_selections(effects, window, cx, |s| {
13819            s.move_with(|map, selection| {
13820                if !selection.is_empty() {
13821                    selection.goal = SelectionGoal::None;
13822                }
13823                let (cursor, goal) = movement::up_by_rows(
13824                    map,
13825                    selection.end,
13826                    row_count,
13827                    selection.goal,
13828                    false,
13829                    text_layout_details,
13830                );
13831                selection.collapse_to(cursor, goal);
13832            });
13833        });
13834    }
13835
13836    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13838        let text_layout_details = &self.text_layout_details(window);
13839        self.change_selections(Default::default(), window, cx, |s| {
13840            s.move_heads_with(|map, head, goal| {
13841                movement::up(map, head, goal, false, text_layout_details)
13842            })
13843        })
13844    }
13845
13846    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13847        self.take_rename(true, window, cx);
13848
13849        if self.mode.is_single_line() {
13850            cx.propagate();
13851            return;
13852        }
13853
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855
13856        let text_layout_details = &self.text_layout_details(window);
13857        let selection_count = self.selections.count();
13858        let first_selection = self.selections.first_anchor();
13859
13860        self.change_selections(Default::default(), window, cx, |s| {
13861            s.move_with(|map, selection| {
13862                if !selection.is_empty() {
13863                    selection.goal = SelectionGoal::None;
13864                }
13865                let (cursor, goal) = movement::down(
13866                    map,
13867                    selection.end,
13868                    selection.goal,
13869                    false,
13870                    text_layout_details,
13871                );
13872                selection.collapse_to(cursor, goal);
13873            });
13874        });
13875
13876        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13877        {
13878            cx.propagate();
13879        }
13880    }
13881
13882    pub fn select_page_down(
13883        &mut self,
13884        _: &SelectPageDown,
13885        window: &mut Window,
13886        cx: &mut Context<Self>,
13887    ) {
13888        let Some(row_count) = self.visible_row_count() else {
13889            return;
13890        };
13891
13892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13893
13894        let text_layout_details = &self.text_layout_details(window);
13895
13896        self.change_selections(Default::default(), window, cx, |s| {
13897            s.move_heads_with(|map, head, goal| {
13898                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13899            })
13900        })
13901    }
13902
13903    pub fn move_page_down(
13904        &mut self,
13905        action: &MovePageDown,
13906        window: &mut Window,
13907        cx: &mut Context<Self>,
13908    ) {
13909        if self.take_rename(true, window, cx).is_some() {
13910            return;
13911        }
13912
13913        if self
13914            .context_menu
13915            .borrow_mut()
13916            .as_mut()
13917            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13918            .unwrap_or(false)
13919        {
13920            return;
13921        }
13922
13923        if matches!(self.mode, EditorMode::SingleLine) {
13924            cx.propagate();
13925            return;
13926        }
13927
13928        let Some(row_count) = self.visible_row_count() else {
13929            return;
13930        };
13931
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13933
13934        let effects = if action.center_cursor {
13935            SelectionEffects::scroll(Autoscroll::center())
13936        } else {
13937            SelectionEffects::default()
13938        };
13939
13940        let text_layout_details = &self.text_layout_details(window);
13941        self.change_selections(effects, window, cx, |s| {
13942            s.move_with(|map, selection| {
13943                if !selection.is_empty() {
13944                    selection.goal = SelectionGoal::None;
13945                }
13946                let (cursor, goal) = movement::down_by_rows(
13947                    map,
13948                    selection.end,
13949                    row_count,
13950                    selection.goal,
13951                    false,
13952                    text_layout_details,
13953                );
13954                selection.collapse_to(cursor, goal);
13955            });
13956        });
13957    }
13958
13959    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13961        let text_layout_details = &self.text_layout_details(window);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.move_heads_with(|map, head, goal| {
13964                movement::down(map, head, goal, false, text_layout_details)
13965            })
13966        });
13967    }
13968
13969    pub fn context_menu_first(
13970        &mut self,
13971        _: &ContextMenuFirst,
13972        window: &mut Window,
13973        cx: &mut Context<Self>,
13974    ) {
13975        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13976            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13977        }
13978    }
13979
13980    pub fn context_menu_prev(
13981        &mut self,
13982        _: &ContextMenuPrevious,
13983        window: &mut Window,
13984        cx: &mut Context<Self>,
13985    ) {
13986        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13987            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13988        }
13989    }
13990
13991    pub fn context_menu_next(
13992        &mut self,
13993        _: &ContextMenuNext,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13998            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13999        }
14000    }
14001
14002    pub fn context_menu_last(
14003        &mut self,
14004        _: &ContextMenuLast,
14005        window: &mut Window,
14006        cx: &mut Context<Self>,
14007    ) {
14008        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14009            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14010        }
14011    }
14012
14013    pub fn signature_help_prev(
14014        &mut self,
14015        _: &SignatureHelpPrevious,
14016        _: &mut Window,
14017        cx: &mut Context<Self>,
14018    ) {
14019        if let Some(popover) = self.signature_help_state.popover_mut() {
14020            if popover.current_signature == 0 {
14021                popover.current_signature = popover.signatures.len() - 1;
14022            } else {
14023                popover.current_signature -= 1;
14024            }
14025            cx.notify();
14026        }
14027    }
14028
14029    pub fn signature_help_next(
14030        &mut self,
14031        _: &SignatureHelpNext,
14032        _: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        if let Some(popover) = self.signature_help_state.popover_mut() {
14036            if popover.current_signature + 1 == popover.signatures.len() {
14037                popover.current_signature = 0;
14038            } else {
14039                popover.current_signature += 1;
14040            }
14041            cx.notify();
14042        }
14043    }
14044
14045    pub fn move_to_previous_word_start(
14046        &mut self,
14047        _: &MoveToPreviousWordStart,
14048        window: &mut Window,
14049        cx: &mut Context<Self>,
14050    ) {
14051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14052        self.change_selections(Default::default(), window, cx, |s| {
14053            s.move_cursors_with(|map, head, _| {
14054                (
14055                    movement::previous_word_start(map, head),
14056                    SelectionGoal::None,
14057                )
14058            });
14059        })
14060    }
14061
14062    pub fn move_to_previous_subword_start(
14063        &mut self,
14064        _: &MoveToPreviousSubwordStart,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069        self.change_selections(Default::default(), window, cx, |s| {
14070            s.move_cursors_with(|map, head, _| {
14071                (
14072                    movement::previous_subword_start(map, head),
14073                    SelectionGoal::None,
14074                )
14075            });
14076        })
14077    }
14078
14079    pub fn select_to_previous_word_start(
14080        &mut self,
14081        _: &SelectToPreviousWordStart,
14082        window: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) {
14085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14086        self.change_selections(Default::default(), window, cx, |s| {
14087            s.move_heads_with(|map, head, _| {
14088                (
14089                    movement::previous_word_start(map, head),
14090                    SelectionGoal::None,
14091                )
14092            });
14093        })
14094    }
14095
14096    pub fn select_to_previous_subword_start(
14097        &mut self,
14098        _: &SelectToPreviousSubwordStart,
14099        window: &mut Window,
14100        cx: &mut Context<Self>,
14101    ) {
14102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14103        self.change_selections(Default::default(), window, cx, |s| {
14104            s.move_heads_with(|map, head, _| {
14105                (
14106                    movement::previous_subword_start(map, head),
14107                    SelectionGoal::None,
14108                )
14109            });
14110        })
14111    }
14112
14113    pub fn delete_to_previous_word_start(
14114        &mut self,
14115        action: &DeleteToPreviousWordStart,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) {
14119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14120        self.transact(window, cx, |this, window, cx| {
14121            this.select_autoclose_pair(window, cx);
14122            this.change_selections(Default::default(), window, cx, |s| {
14123                s.move_with(|map, selection| {
14124                    if selection.is_empty() {
14125                        let mut cursor = if action.ignore_newlines {
14126                            movement::previous_word_start(map, selection.head())
14127                        } else {
14128                            movement::previous_word_start_or_newline(map, selection.head())
14129                        };
14130                        cursor = movement::adjust_greedy_deletion(
14131                            map,
14132                            selection.head(),
14133                            cursor,
14134                            action.ignore_brackets,
14135                        );
14136                        selection.set_head(cursor, SelectionGoal::None);
14137                    }
14138                });
14139            });
14140            this.insert("", window, cx);
14141        });
14142    }
14143
14144    pub fn delete_to_previous_subword_start(
14145        &mut self,
14146        _: &DeleteToPreviousSubwordStart,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) {
14150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14151        self.transact(window, cx, |this, window, cx| {
14152            this.select_autoclose_pair(window, cx);
14153            this.change_selections(Default::default(), window, cx, |s| {
14154                s.move_with(|map, selection| {
14155                    if selection.is_empty() {
14156                        let mut cursor = movement::previous_subword_start(map, selection.head());
14157                        cursor =
14158                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14159                        selection.set_head(cursor, SelectionGoal::None);
14160                    }
14161                });
14162            });
14163            this.insert("", window, cx);
14164        });
14165    }
14166
14167    pub fn move_to_next_word_end(
14168        &mut self,
14169        _: &MoveToNextWordEnd,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14174        self.change_selections(Default::default(), window, cx, |s| {
14175            s.move_cursors_with(|map, head, _| {
14176                (movement::next_word_end(map, head), SelectionGoal::None)
14177            });
14178        })
14179    }
14180
14181    pub fn move_to_next_subword_end(
14182        &mut self,
14183        _: &MoveToNextSubwordEnd,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188        self.change_selections(Default::default(), window, cx, |s| {
14189            s.move_cursors_with(|map, head, _| {
14190                (movement::next_subword_end(map, head), SelectionGoal::None)
14191            });
14192        })
14193    }
14194
14195    pub fn select_to_next_word_end(
14196        &mut self,
14197        _: &SelectToNextWordEnd,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14202        self.change_selections(Default::default(), window, cx, |s| {
14203            s.move_heads_with(|map, head, _| {
14204                (movement::next_word_end(map, head), SelectionGoal::None)
14205            });
14206        })
14207    }
14208
14209    pub fn select_to_next_subword_end(
14210        &mut self,
14211        _: &SelectToNextSubwordEnd,
14212        window: &mut Window,
14213        cx: &mut Context<Self>,
14214    ) {
14215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14216        self.change_selections(Default::default(), window, cx, |s| {
14217            s.move_heads_with(|map, head, _| {
14218                (movement::next_subword_end(map, head), SelectionGoal::None)
14219            });
14220        })
14221    }
14222
14223    pub fn delete_to_next_word_end(
14224        &mut self,
14225        action: &DeleteToNextWordEnd,
14226        window: &mut Window,
14227        cx: &mut Context<Self>,
14228    ) {
14229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14230        self.transact(window, cx, |this, window, cx| {
14231            this.change_selections(Default::default(), window, cx, |s| {
14232                s.move_with(|map, selection| {
14233                    if selection.is_empty() {
14234                        let mut cursor = if action.ignore_newlines {
14235                            movement::next_word_end(map, selection.head())
14236                        } else {
14237                            movement::next_word_end_or_newline(map, selection.head())
14238                        };
14239                        cursor = movement::adjust_greedy_deletion(
14240                            map,
14241                            selection.head(),
14242                            cursor,
14243                            action.ignore_brackets,
14244                        );
14245                        selection.set_head(cursor, SelectionGoal::None);
14246                    }
14247                });
14248            });
14249            this.insert("", window, cx);
14250        });
14251    }
14252
14253    pub fn delete_to_next_subword_end(
14254        &mut self,
14255        _: &DeleteToNextSubwordEnd,
14256        window: &mut Window,
14257        cx: &mut Context<Self>,
14258    ) {
14259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14260        self.transact(window, cx, |this, window, cx| {
14261            this.change_selections(Default::default(), window, cx, |s| {
14262                s.move_with(|map, selection| {
14263                    if selection.is_empty() {
14264                        let mut cursor = movement::next_subword_end(map, selection.head());
14265                        cursor =
14266                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14267                        selection.set_head(cursor, SelectionGoal::None);
14268                    }
14269                });
14270            });
14271            this.insert("", window, cx);
14272        });
14273    }
14274
14275    pub fn move_to_beginning_of_line(
14276        &mut self,
14277        action: &MoveToBeginningOfLine,
14278        window: &mut Window,
14279        cx: &mut Context<Self>,
14280    ) {
14281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14282        self.change_selections(Default::default(), window, cx, |s| {
14283            s.move_cursors_with(|map, head, _| {
14284                (
14285                    movement::indented_line_beginning(
14286                        map,
14287                        head,
14288                        action.stop_at_soft_wraps,
14289                        action.stop_at_indent,
14290                    ),
14291                    SelectionGoal::None,
14292                )
14293            });
14294        })
14295    }
14296
14297    pub fn select_to_beginning_of_line(
14298        &mut self,
14299        action: &SelectToBeginningOfLine,
14300        window: &mut Window,
14301        cx: &mut Context<Self>,
14302    ) {
14303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14304        self.change_selections(Default::default(), window, cx, |s| {
14305            s.move_heads_with(|map, head, _| {
14306                (
14307                    movement::indented_line_beginning(
14308                        map,
14309                        head,
14310                        action.stop_at_soft_wraps,
14311                        action.stop_at_indent,
14312                    ),
14313                    SelectionGoal::None,
14314                )
14315            });
14316        });
14317    }
14318
14319    pub fn delete_to_beginning_of_line(
14320        &mut self,
14321        action: &DeleteToBeginningOfLine,
14322        window: &mut Window,
14323        cx: &mut Context<Self>,
14324    ) {
14325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14326        self.transact(window, cx, |this, window, cx| {
14327            this.change_selections(Default::default(), window, cx, |s| {
14328                s.move_with(|_, selection| {
14329                    selection.reversed = true;
14330                });
14331            });
14332
14333            this.select_to_beginning_of_line(
14334                &SelectToBeginningOfLine {
14335                    stop_at_soft_wraps: false,
14336                    stop_at_indent: action.stop_at_indent,
14337                },
14338                window,
14339                cx,
14340            );
14341            this.backspace(&Backspace, window, cx);
14342        });
14343    }
14344
14345    pub fn move_to_end_of_line(
14346        &mut self,
14347        action: &MoveToEndOfLine,
14348        window: &mut Window,
14349        cx: &mut Context<Self>,
14350    ) {
14351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14352        self.change_selections(Default::default(), window, cx, |s| {
14353            s.move_cursors_with(|map, head, _| {
14354                (
14355                    movement::line_end(map, head, action.stop_at_soft_wraps),
14356                    SelectionGoal::None,
14357                )
14358            });
14359        })
14360    }
14361
14362    pub fn select_to_end_of_line(
14363        &mut self,
14364        action: &SelectToEndOfLine,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) {
14368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14369        self.change_selections(Default::default(), window, cx, |s| {
14370            s.move_heads_with(|map, head, _| {
14371                (
14372                    movement::line_end(map, head, action.stop_at_soft_wraps),
14373                    SelectionGoal::None,
14374                )
14375            });
14376        })
14377    }
14378
14379    pub fn delete_to_end_of_line(
14380        &mut self,
14381        _: &DeleteToEndOfLine,
14382        window: &mut Window,
14383        cx: &mut Context<Self>,
14384    ) {
14385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14386        self.transact(window, cx, |this, window, cx| {
14387            this.select_to_end_of_line(
14388                &SelectToEndOfLine {
14389                    stop_at_soft_wraps: false,
14390                },
14391                window,
14392                cx,
14393            );
14394            this.delete(&Delete, window, cx);
14395        });
14396    }
14397
14398    pub fn cut_to_end_of_line(
14399        &mut self,
14400        action: &CutToEndOfLine,
14401        window: &mut Window,
14402        cx: &mut Context<Self>,
14403    ) {
14404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14405        self.transact(window, cx, |this, window, cx| {
14406            this.select_to_end_of_line(
14407                &SelectToEndOfLine {
14408                    stop_at_soft_wraps: false,
14409                },
14410                window,
14411                cx,
14412            );
14413            if !action.stop_at_newlines {
14414                this.change_selections(Default::default(), window, cx, |s| {
14415                    s.move_with(|_, sel| {
14416                        if sel.is_empty() {
14417                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14418                        }
14419                    });
14420                });
14421            }
14422            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14423            let item = this.cut_common(false, window, cx);
14424            cx.write_to_clipboard(item);
14425        });
14426    }
14427
14428    pub fn move_to_start_of_paragraph(
14429        &mut self,
14430        _: &MoveToStartOfParagraph,
14431        window: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) {
14434        if matches!(self.mode, EditorMode::SingleLine) {
14435            cx.propagate();
14436            return;
14437        }
14438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14439        self.change_selections(Default::default(), window, cx, |s| {
14440            s.move_with(|map, selection| {
14441                selection.collapse_to(
14442                    movement::start_of_paragraph(map, selection.head(), 1),
14443                    SelectionGoal::None,
14444                )
14445            });
14446        })
14447    }
14448
14449    pub fn move_to_end_of_paragraph(
14450        &mut self,
14451        _: &MoveToEndOfParagraph,
14452        window: &mut Window,
14453        cx: &mut Context<Self>,
14454    ) {
14455        if matches!(self.mode, EditorMode::SingleLine) {
14456            cx.propagate();
14457            return;
14458        }
14459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14460        self.change_selections(Default::default(), window, cx, |s| {
14461            s.move_with(|map, selection| {
14462                selection.collapse_to(
14463                    movement::end_of_paragraph(map, selection.head(), 1),
14464                    SelectionGoal::None,
14465                )
14466            });
14467        })
14468    }
14469
14470    pub fn select_to_start_of_paragraph(
14471        &mut self,
14472        _: &SelectToStartOfParagraph,
14473        window: &mut Window,
14474        cx: &mut Context<Self>,
14475    ) {
14476        if matches!(self.mode, EditorMode::SingleLine) {
14477            cx.propagate();
14478            return;
14479        }
14480        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14481        self.change_selections(Default::default(), window, cx, |s| {
14482            s.move_heads_with(|map, head, _| {
14483                (
14484                    movement::start_of_paragraph(map, head, 1),
14485                    SelectionGoal::None,
14486                )
14487            });
14488        })
14489    }
14490
14491    pub fn select_to_end_of_paragraph(
14492        &mut self,
14493        _: &SelectToEndOfParagraph,
14494        window: &mut Window,
14495        cx: &mut Context<Self>,
14496    ) {
14497        if matches!(self.mode, EditorMode::SingleLine) {
14498            cx.propagate();
14499            return;
14500        }
14501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14502        self.change_selections(Default::default(), window, cx, |s| {
14503            s.move_heads_with(|map, head, _| {
14504                (
14505                    movement::end_of_paragraph(map, head, 1),
14506                    SelectionGoal::None,
14507                )
14508            });
14509        })
14510    }
14511
14512    pub fn move_to_start_of_excerpt(
14513        &mut self,
14514        _: &MoveToStartOfExcerpt,
14515        window: &mut Window,
14516        cx: &mut Context<Self>,
14517    ) {
14518        if matches!(self.mode, EditorMode::SingleLine) {
14519            cx.propagate();
14520            return;
14521        }
14522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14523        self.change_selections(Default::default(), window, cx, |s| {
14524            s.move_with(|map, selection| {
14525                selection.collapse_to(
14526                    movement::start_of_excerpt(
14527                        map,
14528                        selection.head(),
14529                        workspace::searchable::Direction::Prev,
14530                    ),
14531                    SelectionGoal::None,
14532                )
14533            });
14534        })
14535    }
14536
14537    pub fn move_to_start_of_next_excerpt(
14538        &mut self,
14539        _: &MoveToStartOfNextExcerpt,
14540        window: &mut Window,
14541        cx: &mut Context<Self>,
14542    ) {
14543        if matches!(self.mode, EditorMode::SingleLine) {
14544            cx.propagate();
14545            return;
14546        }
14547
14548        self.change_selections(Default::default(), window, cx, |s| {
14549            s.move_with(|map, selection| {
14550                selection.collapse_to(
14551                    movement::start_of_excerpt(
14552                        map,
14553                        selection.head(),
14554                        workspace::searchable::Direction::Next,
14555                    ),
14556                    SelectionGoal::None,
14557                )
14558            });
14559        })
14560    }
14561
14562    pub fn move_to_end_of_excerpt(
14563        &mut self,
14564        _: &MoveToEndOfExcerpt,
14565        window: &mut Window,
14566        cx: &mut Context<Self>,
14567    ) {
14568        if matches!(self.mode, EditorMode::SingleLine) {
14569            cx.propagate();
14570            return;
14571        }
14572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14573        self.change_selections(Default::default(), window, cx, |s| {
14574            s.move_with(|map, selection| {
14575                selection.collapse_to(
14576                    movement::end_of_excerpt(
14577                        map,
14578                        selection.head(),
14579                        workspace::searchable::Direction::Next,
14580                    ),
14581                    SelectionGoal::None,
14582                )
14583            });
14584        })
14585    }
14586
14587    pub fn move_to_end_of_previous_excerpt(
14588        &mut self,
14589        _: &MoveToEndOfPreviousExcerpt,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if matches!(self.mode, EditorMode::SingleLine) {
14594            cx.propagate();
14595            return;
14596        }
14597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14598        self.change_selections(Default::default(), window, cx, |s| {
14599            s.move_with(|map, selection| {
14600                selection.collapse_to(
14601                    movement::end_of_excerpt(
14602                        map,
14603                        selection.head(),
14604                        workspace::searchable::Direction::Prev,
14605                    ),
14606                    SelectionGoal::None,
14607                )
14608            });
14609        })
14610    }
14611
14612    pub fn select_to_start_of_excerpt(
14613        &mut self,
14614        _: &SelectToStartOfExcerpt,
14615        window: &mut Window,
14616        cx: &mut Context<Self>,
14617    ) {
14618        if matches!(self.mode, EditorMode::SingleLine) {
14619            cx.propagate();
14620            return;
14621        }
14622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14623        self.change_selections(Default::default(), window, cx, |s| {
14624            s.move_heads_with(|map, head, _| {
14625                (
14626                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14627                    SelectionGoal::None,
14628                )
14629            });
14630        })
14631    }
14632
14633    pub fn select_to_start_of_next_excerpt(
14634        &mut self,
14635        _: &SelectToStartOfNextExcerpt,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) {
14639        if matches!(self.mode, EditorMode::SingleLine) {
14640            cx.propagate();
14641            return;
14642        }
14643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14644        self.change_selections(Default::default(), window, cx, |s| {
14645            s.move_heads_with(|map, head, _| {
14646                (
14647                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14648                    SelectionGoal::None,
14649                )
14650            });
14651        })
14652    }
14653
14654    pub fn select_to_end_of_excerpt(
14655        &mut self,
14656        _: &SelectToEndOfExcerpt,
14657        window: &mut Window,
14658        cx: &mut Context<Self>,
14659    ) {
14660        if matches!(self.mode, EditorMode::SingleLine) {
14661            cx.propagate();
14662            return;
14663        }
14664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14665        self.change_selections(Default::default(), window, cx, |s| {
14666            s.move_heads_with(|map, head, _| {
14667                (
14668                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14669                    SelectionGoal::None,
14670                )
14671            });
14672        })
14673    }
14674
14675    pub fn select_to_end_of_previous_excerpt(
14676        &mut self,
14677        _: &SelectToEndOfPreviousExcerpt,
14678        window: &mut Window,
14679        cx: &mut Context<Self>,
14680    ) {
14681        if matches!(self.mode, EditorMode::SingleLine) {
14682            cx.propagate();
14683            return;
14684        }
14685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14686        self.change_selections(Default::default(), window, cx, |s| {
14687            s.move_heads_with(|map, head, _| {
14688                (
14689                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14690                    SelectionGoal::None,
14691                )
14692            });
14693        })
14694    }
14695
14696    pub fn move_to_beginning(
14697        &mut self,
14698        _: &MoveToBeginning,
14699        window: &mut Window,
14700        cx: &mut Context<Self>,
14701    ) {
14702        if matches!(self.mode, EditorMode::SingleLine) {
14703            cx.propagate();
14704            return;
14705        }
14706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14707        self.change_selections(Default::default(), window, cx, |s| {
14708            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14709        });
14710    }
14711
14712    pub fn select_to_beginning(
14713        &mut self,
14714        _: &SelectToBeginning,
14715        window: &mut Window,
14716        cx: &mut Context<Self>,
14717    ) {
14718        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14719        selection.set_head(Point::zero(), SelectionGoal::None);
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721        self.change_selections(Default::default(), window, cx, |s| {
14722            s.select(vec![selection]);
14723        });
14724    }
14725
14726    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14727        if matches!(self.mode, EditorMode::SingleLine) {
14728            cx.propagate();
14729            return;
14730        }
14731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14732        let cursor = self.buffer.read(cx).read(cx).len();
14733        self.change_selections(Default::default(), window, cx, |s| {
14734            s.select_ranges(vec![cursor..cursor])
14735        });
14736    }
14737
14738    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14739        self.nav_history = nav_history;
14740    }
14741
14742    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14743        self.nav_history.as_ref()
14744    }
14745
14746    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14747        self.push_to_nav_history(
14748            self.selections.newest_anchor().head(),
14749            None,
14750            false,
14751            true,
14752            cx,
14753        );
14754    }
14755
14756    fn push_to_nav_history(
14757        &mut self,
14758        cursor_anchor: Anchor,
14759        new_position: Option<Point>,
14760        is_deactivate: bool,
14761        always: bool,
14762        cx: &mut Context<Self>,
14763    ) {
14764        if let Some(nav_history) = self.nav_history.as_mut() {
14765            let buffer = self.buffer.read(cx).read(cx);
14766            let cursor_position = cursor_anchor.to_point(&buffer);
14767            let scroll_state = self.scroll_manager.anchor();
14768            let scroll_top_row = scroll_state.top_row(&buffer);
14769            drop(buffer);
14770
14771            if let Some(new_position) = new_position {
14772                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14773                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14774                    return;
14775                }
14776            }
14777
14778            nav_history.push(
14779                Some(NavigationData {
14780                    cursor_anchor,
14781                    cursor_position,
14782                    scroll_anchor: scroll_state,
14783                    scroll_top_row,
14784                }),
14785                cx,
14786            );
14787            cx.emit(EditorEvent::PushedToNavHistory {
14788                anchor: cursor_anchor,
14789                is_deactivate,
14790            })
14791        }
14792    }
14793
14794    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14796        let buffer = self.buffer.read(cx).snapshot(cx);
14797        let mut selection = self
14798            .selections
14799            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14800        selection.set_head(buffer.len(), SelectionGoal::None);
14801        self.change_selections(Default::default(), window, cx, |s| {
14802            s.select(vec![selection]);
14803        });
14804    }
14805
14806    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14808        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14809            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14810        });
14811    }
14812
14813    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14814        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14815        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14816        let mut selections = self.selections.all::<Point>(&display_map);
14817        let max_point = display_map.buffer_snapshot().max_point();
14818        for selection in &mut selections {
14819            let rows = selection.spanned_rows(true, &display_map);
14820            selection.start = Point::new(rows.start.0, 0);
14821            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14822            selection.reversed = false;
14823        }
14824        self.change_selections(Default::default(), window, cx, |s| {
14825            s.select(selections);
14826        });
14827    }
14828
14829    pub fn split_selection_into_lines(
14830        &mut self,
14831        action: &SplitSelectionIntoLines,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) {
14835        let selections = self
14836            .selections
14837            .all::<Point>(&self.display_snapshot(cx))
14838            .into_iter()
14839            .map(|selection| selection.start..selection.end)
14840            .collect::<Vec<_>>();
14841        self.unfold_ranges(&selections, true, true, cx);
14842
14843        let mut new_selection_ranges = Vec::new();
14844        {
14845            let buffer = self.buffer.read(cx).read(cx);
14846            for selection in selections {
14847                for row in selection.start.row..selection.end.row {
14848                    let line_start = Point::new(row, 0);
14849                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14850
14851                    if action.keep_selections {
14852                        // Keep the selection range for each line
14853                        let selection_start = if row == selection.start.row {
14854                            selection.start
14855                        } else {
14856                            line_start
14857                        };
14858                        new_selection_ranges.push(selection_start..line_end);
14859                    } else {
14860                        // Collapse to cursor at end of line
14861                        new_selection_ranges.push(line_end..line_end);
14862                    }
14863                }
14864
14865                let is_multiline_selection = selection.start.row != selection.end.row;
14866                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14867                // so this action feels more ergonomic when paired with other selection operations
14868                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14869                if !should_skip_last {
14870                    if action.keep_selections {
14871                        if is_multiline_selection {
14872                            let line_start = Point::new(selection.end.row, 0);
14873                            new_selection_ranges.push(line_start..selection.end);
14874                        } else {
14875                            new_selection_ranges.push(selection.start..selection.end);
14876                        }
14877                    } else {
14878                        new_selection_ranges.push(selection.end..selection.end);
14879                    }
14880                }
14881            }
14882        }
14883        self.change_selections(Default::default(), window, cx, |s| {
14884            s.select_ranges(new_selection_ranges);
14885        });
14886    }
14887
14888    pub fn add_selection_above(
14889        &mut self,
14890        action: &AddSelectionAbove,
14891        window: &mut Window,
14892        cx: &mut Context<Self>,
14893    ) {
14894        self.add_selection(true, action.skip_soft_wrap, window, cx);
14895    }
14896
14897    pub fn add_selection_below(
14898        &mut self,
14899        action: &AddSelectionBelow,
14900        window: &mut Window,
14901        cx: &mut Context<Self>,
14902    ) {
14903        self.add_selection(false, action.skip_soft_wrap, window, cx);
14904    }
14905
14906    fn add_selection(
14907        &mut self,
14908        above: bool,
14909        skip_soft_wrap: bool,
14910        window: &mut Window,
14911        cx: &mut Context<Self>,
14912    ) {
14913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14914
14915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14916        let all_selections = self.selections.all::<Point>(&display_map);
14917        let text_layout_details = self.text_layout_details(window);
14918
14919        let (mut columnar_selections, new_selections_to_columnarize) = {
14920            if let Some(state) = self.add_selections_state.as_ref() {
14921                let columnar_selection_ids: HashSet<_> = state
14922                    .groups
14923                    .iter()
14924                    .flat_map(|group| group.stack.iter())
14925                    .copied()
14926                    .collect();
14927
14928                all_selections
14929                    .into_iter()
14930                    .partition(|s| columnar_selection_ids.contains(&s.id))
14931            } else {
14932                (Vec::new(), all_selections)
14933            }
14934        };
14935
14936        let mut state = self
14937            .add_selections_state
14938            .take()
14939            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14940
14941        for selection in new_selections_to_columnarize {
14942            let range = selection.display_range(&display_map).sorted();
14943            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14944            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14945            let positions = start_x.min(end_x)..start_x.max(end_x);
14946            let mut stack = Vec::new();
14947            for row in range.start.row().0..=range.end.row().0 {
14948                if let Some(selection) = self.selections.build_columnar_selection(
14949                    &display_map,
14950                    DisplayRow(row),
14951                    &positions,
14952                    selection.reversed,
14953                    &text_layout_details,
14954                ) {
14955                    stack.push(selection.id);
14956                    columnar_selections.push(selection);
14957                }
14958            }
14959            if !stack.is_empty() {
14960                if above {
14961                    stack.reverse();
14962                }
14963                state.groups.push(AddSelectionsGroup { above, stack });
14964            }
14965        }
14966
14967        let mut final_selections = Vec::new();
14968        let end_row = if above {
14969            DisplayRow(0)
14970        } else {
14971            display_map.max_point().row()
14972        };
14973
14974        let mut last_added_item_per_group = HashMap::default();
14975        for group in state.groups.iter_mut() {
14976            if let Some(last_id) = group.stack.last() {
14977                last_added_item_per_group.insert(*last_id, group);
14978            }
14979        }
14980
14981        for selection in columnar_selections {
14982            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14983                if above == group.above {
14984                    let range = selection.display_range(&display_map).sorted();
14985                    debug_assert_eq!(range.start.row(), range.end.row());
14986                    let mut row = range.start.row();
14987                    let positions =
14988                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14989                            Pixels::from(start)..Pixels::from(end)
14990                        } else {
14991                            let start_x =
14992                                display_map.x_for_display_point(range.start, &text_layout_details);
14993                            let end_x =
14994                                display_map.x_for_display_point(range.end, &text_layout_details);
14995                            start_x.min(end_x)..start_x.max(end_x)
14996                        };
14997
14998                    let mut maybe_new_selection = None;
14999                    let direction = if above { -1 } else { 1 };
15000
15001                    while row != end_row {
15002                        let new_buffer_row = if skip_soft_wrap {
15003                            let new_row = display_map
15004                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15005                            row = new_row.row();
15006                            Some(new_row.to_point(&display_map).row)
15007                        } else {
15008                            if above {
15009                                row.0 -= 1;
15010                            } else {
15011                                row.0 += 1;
15012                            }
15013                            None
15014                        };
15015
15016                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15017                            let start_col = selection.start.column;
15018                            let end_col = selection.end.column;
15019                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15020
15021                            self.selections
15022                                .build_columnar_selection_from_buffer_columns(
15023                                    &display_map,
15024                                    buffer_row,
15025                                    &buffer_columns,
15026                                    selection.reversed,
15027                                    &text_layout_details,
15028                                )
15029                        } else {
15030                            self.selections.build_columnar_selection(
15031                                &display_map,
15032                                row,
15033                                &positions,
15034                                selection.reversed,
15035                                &text_layout_details,
15036                            )
15037                        };
15038
15039                        if let Some(new_selection) = new_selection {
15040                            maybe_new_selection = Some(new_selection);
15041                            break;
15042                        }
15043                    }
15044
15045                    if let Some(new_selection) = maybe_new_selection {
15046                        group.stack.push(new_selection.id);
15047                        if above {
15048                            final_selections.push(new_selection);
15049                            final_selections.push(selection);
15050                        } else {
15051                            final_selections.push(selection);
15052                            final_selections.push(new_selection);
15053                        }
15054                    } else {
15055                        final_selections.push(selection);
15056                    }
15057                } else {
15058                    group.stack.pop();
15059                }
15060            } else {
15061                final_selections.push(selection);
15062            }
15063        }
15064
15065        self.change_selections(Default::default(), window, cx, |s| {
15066            s.select(final_selections);
15067        });
15068
15069        let final_selection_ids: HashSet<_> = self
15070            .selections
15071            .all::<Point>(&display_map)
15072            .iter()
15073            .map(|s| s.id)
15074            .collect();
15075        state.groups.retain_mut(|group| {
15076            // selections might get merged above so we remove invalid items from stacks
15077            group.stack.retain(|id| final_selection_ids.contains(id));
15078
15079            // single selection in stack can be treated as initial state
15080            group.stack.len() > 1
15081        });
15082
15083        if !state.groups.is_empty() {
15084            self.add_selections_state = Some(state);
15085        }
15086    }
15087
15088    pub fn insert_snippet_at_selections(
15089        &mut self,
15090        action: &InsertSnippet,
15091        window: &mut Window,
15092        cx: &mut Context<Self>,
15093    ) {
15094        self.try_insert_snippet_at_selections(action, window, cx)
15095            .log_err();
15096    }
15097
15098    fn try_insert_snippet_at_selections(
15099        &mut self,
15100        action: &InsertSnippet,
15101        window: &mut Window,
15102        cx: &mut Context<Self>,
15103    ) -> Result<()> {
15104        let insertion_ranges = self
15105            .selections
15106            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15107            .into_iter()
15108            .map(|selection| selection.range())
15109            .collect_vec();
15110
15111        let snippet = if let Some(snippet_body) = &action.snippet {
15112            if action.language.is_none() && action.name.is_none() {
15113                Snippet::parse(snippet_body)?
15114            } else {
15115                bail!("`snippet` is mutually exclusive with `language` and `name`")
15116            }
15117        } else if let Some(name) = &action.name {
15118            let project = self.project().context("no project")?;
15119            let snippet_store = project.read(cx).snippets().read(cx);
15120            let snippet = snippet_store
15121                .snippets_for(action.language.clone(), cx)
15122                .into_iter()
15123                .find(|snippet| snippet.name == *name)
15124                .context("snippet not found")?;
15125            Snippet::parse(&snippet.body)?
15126        } else {
15127            // todo(andrew): open modal to select snippet
15128            bail!("`name` or `snippet` is required")
15129        };
15130
15131        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15132    }
15133
15134    fn select_match_ranges(
15135        &mut self,
15136        range: Range<MultiBufferOffset>,
15137        reversed: bool,
15138        replace_newest: bool,
15139        auto_scroll: Option<Autoscroll>,
15140        window: &mut Window,
15141        cx: &mut Context<Editor>,
15142    ) {
15143        self.unfold_ranges(
15144            std::slice::from_ref(&range),
15145            false,
15146            auto_scroll.is_some(),
15147            cx,
15148        );
15149        let effects = if let Some(scroll) = auto_scroll {
15150            SelectionEffects::scroll(scroll)
15151        } else {
15152            SelectionEffects::no_scroll()
15153        };
15154        self.change_selections(effects, window, cx, |s| {
15155            if replace_newest {
15156                s.delete(s.newest_anchor().id);
15157            }
15158            if reversed {
15159                s.insert_range(range.end..range.start);
15160            } else {
15161                s.insert_range(range);
15162            }
15163        });
15164    }
15165
15166    pub fn select_next_match_internal(
15167        &mut self,
15168        display_map: &DisplaySnapshot,
15169        replace_newest: bool,
15170        autoscroll: Option<Autoscroll>,
15171        window: &mut Window,
15172        cx: &mut Context<Self>,
15173    ) -> Result<()> {
15174        let buffer = display_map.buffer_snapshot();
15175        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15176        if let Some(mut select_next_state) = self.select_next_state.take() {
15177            let query = &select_next_state.query;
15178            if !select_next_state.done {
15179                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15180                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15181                let mut next_selected_range = None;
15182
15183                let bytes_after_last_selection =
15184                    buffer.bytes_in_range(last_selection.end..buffer.len());
15185                let bytes_before_first_selection =
15186                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15187                let query_matches = query
15188                    .stream_find_iter(bytes_after_last_selection)
15189                    .map(|result| (last_selection.end, result))
15190                    .chain(
15191                        query
15192                            .stream_find_iter(bytes_before_first_selection)
15193                            .map(|result| (MultiBufferOffset(0), result)),
15194                    );
15195
15196                for (start_offset, query_match) in query_matches {
15197                    let query_match = query_match.unwrap(); // can only fail due to I/O
15198                    let offset_range =
15199                        start_offset + query_match.start()..start_offset + query_match.end();
15200
15201                    if !select_next_state.wordwise
15202                        || (!buffer.is_inside_word(offset_range.start, None)
15203                            && !buffer.is_inside_word(offset_range.end, None))
15204                    {
15205                        let idx = selections
15206                            .partition_point(|selection| selection.end <= offset_range.start);
15207                        let overlaps = selections
15208                            .get(idx)
15209                            .map_or(false, |selection| selection.start < offset_range.end);
15210
15211                        if !overlaps {
15212                            next_selected_range = Some(offset_range);
15213                            break;
15214                        }
15215                    }
15216                }
15217
15218                if let Some(next_selected_range) = next_selected_range {
15219                    self.select_match_ranges(
15220                        next_selected_range,
15221                        last_selection.reversed,
15222                        replace_newest,
15223                        autoscroll,
15224                        window,
15225                        cx,
15226                    );
15227                } else {
15228                    select_next_state.done = true;
15229                }
15230            }
15231
15232            self.select_next_state = Some(select_next_state);
15233        } else {
15234            let mut only_carets = true;
15235            let mut same_text_selected = true;
15236            let mut selected_text = None;
15237
15238            let mut selections_iter = selections.iter().peekable();
15239            while let Some(selection) = selections_iter.next() {
15240                if selection.start != selection.end {
15241                    only_carets = false;
15242                }
15243
15244                if same_text_selected {
15245                    if selected_text.is_none() {
15246                        selected_text =
15247                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15248                    }
15249
15250                    if let Some(next_selection) = selections_iter.peek() {
15251                        if next_selection.len() == selection.len() {
15252                            let next_selected_text = buffer
15253                                .text_for_range(next_selection.range())
15254                                .collect::<String>();
15255                            if Some(next_selected_text) != selected_text {
15256                                same_text_selected = false;
15257                                selected_text = None;
15258                            }
15259                        } else {
15260                            same_text_selected = false;
15261                            selected_text = None;
15262                        }
15263                    }
15264                }
15265            }
15266
15267            if only_carets {
15268                for selection in &mut selections {
15269                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15270                    selection.start = word_range.start;
15271                    selection.end = word_range.end;
15272                    selection.goal = SelectionGoal::None;
15273                    selection.reversed = false;
15274                    self.select_match_ranges(
15275                        selection.start..selection.end,
15276                        selection.reversed,
15277                        replace_newest,
15278                        autoscroll,
15279                        window,
15280                        cx,
15281                    );
15282                }
15283
15284                if selections.len() == 1 {
15285                    let selection = selections
15286                        .last()
15287                        .expect("ensured that there's only one selection");
15288                    let query = buffer
15289                        .text_for_range(selection.start..selection.end)
15290                        .collect::<String>();
15291                    let is_empty = query.is_empty();
15292                    let select_state = SelectNextState {
15293                        query: self.build_query(&[query], cx)?,
15294                        wordwise: true,
15295                        done: is_empty,
15296                    };
15297                    self.select_next_state = Some(select_state);
15298                } else {
15299                    self.select_next_state = None;
15300                }
15301            } else if let Some(selected_text) = selected_text {
15302                self.select_next_state = Some(SelectNextState {
15303                    query: self.build_query(&[selected_text], cx)?,
15304                    wordwise: false,
15305                    done: false,
15306                });
15307                self.select_next_match_internal(
15308                    display_map,
15309                    replace_newest,
15310                    autoscroll,
15311                    window,
15312                    cx,
15313                )?;
15314            }
15315        }
15316        Ok(())
15317    }
15318
15319    pub fn select_all_matches(
15320        &mut self,
15321        _action: &SelectAllMatches,
15322        window: &mut Window,
15323        cx: &mut Context<Self>,
15324    ) -> Result<()> {
15325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15326
15327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15328
15329        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15330        let Some(select_next_state) = self.select_next_state.as_mut() else {
15331            return Ok(());
15332        };
15333        if select_next_state.done {
15334            return Ok(());
15335        }
15336
15337        let mut new_selections = Vec::new();
15338
15339        let reversed = self
15340            .selections
15341            .oldest::<MultiBufferOffset>(&display_map)
15342            .reversed;
15343        let buffer = display_map.buffer_snapshot();
15344        let query_matches = select_next_state
15345            .query
15346            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15347
15348        for query_match in query_matches.into_iter() {
15349            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15350            let offset_range = if reversed {
15351                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15352            } else {
15353                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15354            };
15355
15356            if !select_next_state.wordwise
15357                || (!buffer.is_inside_word(offset_range.start, None)
15358                    && !buffer.is_inside_word(offset_range.end, None))
15359            {
15360                new_selections.push(offset_range.start..offset_range.end);
15361            }
15362        }
15363
15364        select_next_state.done = true;
15365
15366        if new_selections.is_empty() {
15367            log::error!("bug: new_selections is empty in select_all_matches");
15368            return Ok(());
15369        }
15370
15371        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15372        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15373            selections.select_ranges(new_selections)
15374        });
15375
15376        Ok(())
15377    }
15378
15379    pub fn select_next(
15380        &mut self,
15381        action: &SelectNext,
15382        window: &mut Window,
15383        cx: &mut Context<Self>,
15384    ) -> Result<()> {
15385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15387        self.select_next_match_internal(
15388            &display_map,
15389            action.replace_newest,
15390            Some(Autoscroll::newest()),
15391            window,
15392            cx,
15393        )?;
15394        Ok(())
15395    }
15396
15397    pub fn select_previous(
15398        &mut self,
15399        action: &SelectPrevious,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) -> Result<()> {
15403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15404        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15405        let buffer = display_map.buffer_snapshot();
15406        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15407        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15408            let query = &select_prev_state.query;
15409            if !select_prev_state.done {
15410                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15411                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15412                let mut next_selected_range = None;
15413                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15414                let bytes_before_last_selection =
15415                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15416                let bytes_after_first_selection =
15417                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15418                let query_matches = query
15419                    .stream_find_iter(bytes_before_last_selection)
15420                    .map(|result| (last_selection.start, result))
15421                    .chain(
15422                        query
15423                            .stream_find_iter(bytes_after_first_selection)
15424                            .map(|result| (buffer.len(), result)),
15425                    );
15426                for (end_offset, query_match) in query_matches {
15427                    let query_match = query_match.unwrap(); // can only fail due to I/O
15428                    let offset_range =
15429                        end_offset - query_match.end()..end_offset - query_match.start();
15430
15431                    if !select_prev_state.wordwise
15432                        || (!buffer.is_inside_word(offset_range.start, None)
15433                            && !buffer.is_inside_word(offset_range.end, None))
15434                    {
15435                        next_selected_range = Some(offset_range);
15436                        break;
15437                    }
15438                }
15439
15440                if let Some(next_selected_range) = next_selected_range {
15441                    self.select_match_ranges(
15442                        next_selected_range,
15443                        last_selection.reversed,
15444                        action.replace_newest,
15445                        Some(Autoscroll::newest()),
15446                        window,
15447                        cx,
15448                    );
15449                } else {
15450                    select_prev_state.done = true;
15451                }
15452            }
15453
15454            self.select_prev_state = Some(select_prev_state);
15455        } else {
15456            let mut only_carets = true;
15457            let mut same_text_selected = true;
15458            let mut selected_text = None;
15459
15460            let mut selections_iter = selections.iter().peekable();
15461            while let Some(selection) = selections_iter.next() {
15462                if selection.start != selection.end {
15463                    only_carets = false;
15464                }
15465
15466                if same_text_selected {
15467                    if selected_text.is_none() {
15468                        selected_text =
15469                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15470                    }
15471
15472                    if let Some(next_selection) = selections_iter.peek() {
15473                        if next_selection.len() == selection.len() {
15474                            let next_selected_text = buffer
15475                                .text_for_range(next_selection.range())
15476                                .collect::<String>();
15477                            if Some(next_selected_text) != selected_text {
15478                                same_text_selected = false;
15479                                selected_text = None;
15480                            }
15481                        } else {
15482                            same_text_selected = false;
15483                            selected_text = None;
15484                        }
15485                    }
15486                }
15487            }
15488
15489            if only_carets {
15490                for selection in &mut selections {
15491                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15492                    selection.start = word_range.start;
15493                    selection.end = word_range.end;
15494                    selection.goal = SelectionGoal::None;
15495                    selection.reversed = false;
15496                    self.select_match_ranges(
15497                        selection.start..selection.end,
15498                        selection.reversed,
15499                        action.replace_newest,
15500                        Some(Autoscroll::newest()),
15501                        window,
15502                        cx,
15503                    );
15504                }
15505                if selections.len() == 1 {
15506                    let selection = selections
15507                        .last()
15508                        .expect("ensured that there's only one selection");
15509                    let query = buffer
15510                        .text_for_range(selection.start..selection.end)
15511                        .collect::<String>();
15512                    let is_empty = query.is_empty();
15513                    let select_state = SelectNextState {
15514                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15515                        wordwise: true,
15516                        done: is_empty,
15517                    };
15518                    self.select_prev_state = Some(select_state);
15519                } else {
15520                    self.select_prev_state = None;
15521                }
15522            } else if let Some(selected_text) = selected_text {
15523                self.select_prev_state = Some(SelectNextState {
15524                    query: self
15525                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15526                    wordwise: false,
15527                    done: false,
15528                });
15529                self.select_previous(action, window, cx)?;
15530            }
15531        }
15532        Ok(())
15533    }
15534
15535    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15536    /// setting the case sensitivity based on the global
15537    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15538    /// editor's settings.
15539    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15540    where
15541        I: IntoIterator<Item = P>,
15542        P: AsRef<[u8]>,
15543    {
15544        let case_sensitive = self
15545            .select_next_is_case_sensitive
15546            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15547
15548        let mut builder = AhoCorasickBuilder::new();
15549        builder.ascii_case_insensitive(!case_sensitive);
15550        builder.build(patterns)
15551    }
15552
15553    pub fn find_next_match(
15554        &mut self,
15555        _: &FindNextMatch,
15556        window: &mut Window,
15557        cx: &mut Context<Self>,
15558    ) -> Result<()> {
15559        let selections = self.selections.disjoint_anchors_arc();
15560        match selections.first() {
15561            Some(first) if selections.len() >= 2 => {
15562                self.change_selections(Default::default(), window, cx, |s| {
15563                    s.select_ranges([first.range()]);
15564                });
15565            }
15566            _ => self.select_next(
15567                &SelectNext {
15568                    replace_newest: true,
15569                },
15570                window,
15571                cx,
15572            )?,
15573        }
15574        Ok(())
15575    }
15576
15577    pub fn find_previous_match(
15578        &mut self,
15579        _: &FindPreviousMatch,
15580        window: &mut Window,
15581        cx: &mut Context<Self>,
15582    ) -> Result<()> {
15583        let selections = self.selections.disjoint_anchors_arc();
15584        match selections.last() {
15585            Some(last) if selections.len() >= 2 => {
15586                self.change_selections(Default::default(), window, cx, |s| {
15587                    s.select_ranges([last.range()]);
15588                });
15589            }
15590            _ => self.select_previous(
15591                &SelectPrevious {
15592                    replace_newest: true,
15593                },
15594                window,
15595                cx,
15596            )?,
15597        }
15598        Ok(())
15599    }
15600
15601    pub fn toggle_comments(
15602        &mut self,
15603        action: &ToggleComments,
15604        window: &mut Window,
15605        cx: &mut Context<Self>,
15606    ) {
15607        if self.read_only(cx) {
15608            return;
15609        }
15610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15611        let text_layout_details = &self.text_layout_details(window);
15612        self.transact(window, cx, |this, window, cx| {
15613            let mut selections = this
15614                .selections
15615                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15616            let mut edits = Vec::new();
15617            let mut selection_edit_ranges = Vec::new();
15618            let mut last_toggled_row = None;
15619            let snapshot = this.buffer.read(cx).read(cx);
15620            let empty_str: Arc<str> = Arc::default();
15621            let mut suffixes_inserted = Vec::new();
15622            let ignore_indent = action.ignore_indent;
15623
15624            fn comment_prefix_range(
15625                snapshot: &MultiBufferSnapshot,
15626                row: MultiBufferRow,
15627                comment_prefix: &str,
15628                comment_prefix_whitespace: &str,
15629                ignore_indent: bool,
15630            ) -> Range<Point> {
15631                let indent_size = if ignore_indent {
15632                    0
15633                } else {
15634                    snapshot.indent_size_for_line(row).len
15635                };
15636
15637                let start = Point::new(row.0, indent_size);
15638
15639                let mut line_bytes = snapshot
15640                    .bytes_in_range(start..snapshot.max_point())
15641                    .flatten()
15642                    .copied();
15643
15644                // If this line currently begins with the line comment prefix, then record
15645                // the range containing the prefix.
15646                if line_bytes
15647                    .by_ref()
15648                    .take(comment_prefix.len())
15649                    .eq(comment_prefix.bytes())
15650                {
15651                    // Include any whitespace that matches the comment prefix.
15652                    let matching_whitespace_len = line_bytes
15653                        .zip(comment_prefix_whitespace.bytes())
15654                        .take_while(|(a, b)| a == b)
15655                        .count() as u32;
15656                    let end = Point::new(
15657                        start.row,
15658                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15659                    );
15660                    start..end
15661                } else {
15662                    start..start
15663                }
15664            }
15665
15666            fn comment_suffix_range(
15667                snapshot: &MultiBufferSnapshot,
15668                row: MultiBufferRow,
15669                comment_suffix: &str,
15670                comment_suffix_has_leading_space: bool,
15671            ) -> Range<Point> {
15672                let end = Point::new(row.0, snapshot.line_len(row));
15673                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15674
15675                let mut line_end_bytes = snapshot
15676                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15677                    .flatten()
15678                    .copied();
15679
15680                let leading_space_len = if suffix_start_column > 0
15681                    && line_end_bytes.next() == Some(b' ')
15682                    && comment_suffix_has_leading_space
15683                {
15684                    1
15685                } else {
15686                    0
15687                };
15688
15689                // If this line currently begins with the line comment prefix, then record
15690                // the range containing the prefix.
15691                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15692                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15693                    start..end
15694                } else {
15695                    end..end
15696                }
15697            }
15698
15699            // TODO: Handle selections that cross excerpts
15700            for selection in &mut selections {
15701                let start_column = snapshot
15702                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15703                    .len;
15704                let language = if let Some(language) =
15705                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15706                {
15707                    language
15708                } else {
15709                    continue;
15710                };
15711
15712                selection_edit_ranges.clear();
15713
15714                // If multiple selections contain a given row, avoid processing that
15715                // row more than once.
15716                let mut start_row = MultiBufferRow(selection.start.row);
15717                if last_toggled_row == Some(start_row) {
15718                    start_row = start_row.next_row();
15719                }
15720                let end_row =
15721                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15722                        MultiBufferRow(selection.end.row - 1)
15723                    } else {
15724                        MultiBufferRow(selection.end.row)
15725                    };
15726                last_toggled_row = Some(end_row);
15727
15728                if start_row > end_row {
15729                    continue;
15730                }
15731
15732                // If the language has line comments, toggle those.
15733                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15734
15735                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15736                if ignore_indent {
15737                    full_comment_prefixes = full_comment_prefixes
15738                        .into_iter()
15739                        .map(|s| Arc::from(s.trim_end()))
15740                        .collect();
15741                }
15742
15743                if !full_comment_prefixes.is_empty() {
15744                    let first_prefix = full_comment_prefixes
15745                        .first()
15746                        .expect("prefixes is non-empty");
15747                    let prefix_trimmed_lengths = full_comment_prefixes
15748                        .iter()
15749                        .map(|p| p.trim_end_matches(' ').len())
15750                        .collect::<SmallVec<[usize; 4]>>();
15751
15752                    let mut all_selection_lines_are_comments = true;
15753
15754                    for row in start_row.0..=end_row.0 {
15755                        let row = MultiBufferRow(row);
15756                        if start_row < end_row && snapshot.is_line_blank(row) {
15757                            continue;
15758                        }
15759
15760                        let prefix_range = full_comment_prefixes
15761                            .iter()
15762                            .zip(prefix_trimmed_lengths.iter().copied())
15763                            .map(|(prefix, trimmed_prefix_len)| {
15764                                comment_prefix_range(
15765                                    snapshot.deref(),
15766                                    row,
15767                                    &prefix[..trimmed_prefix_len],
15768                                    &prefix[trimmed_prefix_len..],
15769                                    ignore_indent,
15770                                )
15771                            })
15772                            .max_by_key(|range| range.end.column - range.start.column)
15773                            .expect("prefixes is non-empty");
15774
15775                        if prefix_range.is_empty() {
15776                            all_selection_lines_are_comments = false;
15777                        }
15778
15779                        selection_edit_ranges.push(prefix_range);
15780                    }
15781
15782                    if all_selection_lines_are_comments {
15783                        edits.extend(
15784                            selection_edit_ranges
15785                                .iter()
15786                                .cloned()
15787                                .map(|range| (range, empty_str.clone())),
15788                        );
15789                    } else {
15790                        let min_column = selection_edit_ranges
15791                            .iter()
15792                            .map(|range| range.start.column)
15793                            .min()
15794                            .unwrap_or(0);
15795                        edits.extend(selection_edit_ranges.iter().map(|range| {
15796                            let position = Point::new(range.start.row, min_column);
15797                            (position..position, first_prefix.clone())
15798                        }));
15799                    }
15800                } else if let Some(BlockCommentConfig {
15801                    start: full_comment_prefix,
15802                    end: comment_suffix,
15803                    ..
15804                }) = language.block_comment()
15805                {
15806                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15807                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15808                    let prefix_range = comment_prefix_range(
15809                        snapshot.deref(),
15810                        start_row,
15811                        comment_prefix,
15812                        comment_prefix_whitespace,
15813                        ignore_indent,
15814                    );
15815                    let suffix_range = comment_suffix_range(
15816                        snapshot.deref(),
15817                        end_row,
15818                        comment_suffix.trim_start_matches(' '),
15819                        comment_suffix.starts_with(' '),
15820                    );
15821
15822                    if prefix_range.is_empty() || suffix_range.is_empty() {
15823                        edits.push((
15824                            prefix_range.start..prefix_range.start,
15825                            full_comment_prefix.clone(),
15826                        ));
15827                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15828                        suffixes_inserted.push((end_row, comment_suffix.len()));
15829                    } else {
15830                        edits.push((prefix_range, empty_str.clone()));
15831                        edits.push((suffix_range, empty_str.clone()));
15832                    }
15833                } else {
15834                    continue;
15835                }
15836            }
15837
15838            drop(snapshot);
15839            this.buffer.update(cx, |buffer, cx| {
15840                buffer.edit(edits, None, cx);
15841            });
15842
15843            // Adjust selections so that they end before any comment suffixes that
15844            // were inserted.
15845            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15846            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15847            let snapshot = this.buffer.read(cx).read(cx);
15848            for selection in &mut selections {
15849                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15850                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15851                        Ordering::Less => {
15852                            suffixes_inserted.next();
15853                            continue;
15854                        }
15855                        Ordering::Greater => break,
15856                        Ordering::Equal => {
15857                            if selection.end.column == snapshot.line_len(row) {
15858                                if selection.is_empty() {
15859                                    selection.start.column -= suffix_len as u32;
15860                                }
15861                                selection.end.column -= suffix_len as u32;
15862                            }
15863                            break;
15864                        }
15865                    }
15866                }
15867            }
15868
15869            drop(snapshot);
15870            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15871
15872            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15873            let selections_on_single_row = selections.windows(2).all(|selections| {
15874                selections[0].start.row == selections[1].start.row
15875                    && selections[0].end.row == selections[1].end.row
15876                    && selections[0].start.row == selections[0].end.row
15877            });
15878            let selections_selecting = selections
15879                .iter()
15880                .any(|selection| selection.start != selection.end);
15881            let advance_downwards = action.advance_downwards
15882                && selections_on_single_row
15883                && !selections_selecting
15884                && !matches!(this.mode, EditorMode::SingleLine);
15885
15886            if advance_downwards {
15887                let snapshot = this.buffer.read(cx).snapshot(cx);
15888
15889                this.change_selections(Default::default(), window, cx, |s| {
15890                    s.move_cursors_with(|display_snapshot, display_point, _| {
15891                        let mut point = display_point.to_point(display_snapshot);
15892                        point.row += 1;
15893                        point = snapshot.clip_point(point, Bias::Left);
15894                        let display_point = point.to_display_point(display_snapshot);
15895                        let goal = SelectionGoal::HorizontalPosition(
15896                            display_snapshot
15897                                .x_for_display_point(display_point, text_layout_details)
15898                                .into(),
15899                        );
15900                        (display_point, goal)
15901                    })
15902                });
15903            }
15904        });
15905    }
15906
15907    pub fn select_enclosing_symbol(
15908        &mut self,
15909        _: &SelectEnclosingSymbol,
15910        window: &mut Window,
15911        cx: &mut Context<Self>,
15912    ) {
15913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15914
15915        let buffer = self.buffer.read(cx).snapshot(cx);
15916        let old_selections = self
15917            .selections
15918            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15919            .into_boxed_slice();
15920
15921        fn update_selection(
15922            selection: &Selection<MultiBufferOffset>,
15923            buffer_snap: &MultiBufferSnapshot,
15924        ) -> Option<Selection<MultiBufferOffset>> {
15925            let cursor = selection.head();
15926            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15927            for symbol in symbols.iter().rev() {
15928                let start = symbol.range.start.to_offset(buffer_snap);
15929                let end = symbol.range.end.to_offset(buffer_snap);
15930                let new_range = start..end;
15931                if start < selection.start || end > selection.end {
15932                    return Some(Selection {
15933                        id: selection.id,
15934                        start: new_range.start,
15935                        end: new_range.end,
15936                        goal: SelectionGoal::None,
15937                        reversed: selection.reversed,
15938                    });
15939                }
15940            }
15941            None
15942        }
15943
15944        let mut selected_larger_symbol = false;
15945        let new_selections = old_selections
15946            .iter()
15947            .map(|selection| match update_selection(selection, &buffer) {
15948                Some(new_selection) => {
15949                    if new_selection.range() != selection.range() {
15950                        selected_larger_symbol = true;
15951                    }
15952                    new_selection
15953                }
15954                None => selection.clone(),
15955            })
15956            .collect::<Vec<_>>();
15957
15958        if selected_larger_symbol {
15959            self.change_selections(Default::default(), window, cx, |s| {
15960                s.select(new_selections);
15961            });
15962        }
15963    }
15964
15965    pub fn select_larger_syntax_node(
15966        &mut self,
15967        _: &SelectLargerSyntaxNode,
15968        window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        let Some(visible_row_count) = self.visible_row_count() else {
15972            return;
15973        };
15974        let old_selections: Box<[_]> = self
15975            .selections
15976            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15977            .into();
15978        if old_selections.is_empty() {
15979            return;
15980        }
15981
15982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15983
15984        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15985        let buffer = self.buffer.read(cx).snapshot(cx);
15986
15987        let mut selected_larger_node = false;
15988        let mut new_selections = old_selections
15989            .iter()
15990            .map(|selection| {
15991                let old_range = selection.start..selection.end;
15992
15993                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15994                    // manually select word at selection
15995                    if ["string_content", "inline"].contains(&node.kind()) {
15996                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15997                        // ignore if word is already selected
15998                        if !word_range.is_empty() && old_range != word_range {
15999                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16000                            // only select word if start and end point belongs to same word
16001                            if word_range == last_word_range {
16002                                selected_larger_node = true;
16003                                return Selection {
16004                                    id: selection.id,
16005                                    start: word_range.start,
16006                                    end: word_range.end,
16007                                    goal: SelectionGoal::None,
16008                                    reversed: selection.reversed,
16009                                };
16010                            }
16011                        }
16012                    }
16013                }
16014
16015                let mut new_range = old_range.clone();
16016                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16017                    new_range = range;
16018                    if !node.is_named() {
16019                        continue;
16020                    }
16021                    if !display_map.intersects_fold(new_range.start)
16022                        && !display_map.intersects_fold(new_range.end)
16023                    {
16024                        break;
16025                    }
16026                }
16027
16028                selected_larger_node |= new_range != old_range;
16029                Selection {
16030                    id: selection.id,
16031                    start: new_range.start,
16032                    end: new_range.end,
16033                    goal: SelectionGoal::None,
16034                    reversed: selection.reversed,
16035                }
16036            })
16037            .collect::<Vec<_>>();
16038
16039        if !selected_larger_node {
16040            return; // don't put this call in the history
16041        }
16042
16043        // scroll based on transformation done to the last selection created by the user
16044        let (last_old, last_new) = old_selections
16045            .last()
16046            .zip(new_selections.last().cloned())
16047            .expect("old_selections isn't empty");
16048
16049        // revert selection
16050        let is_selection_reversed = {
16051            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16052            new_selections.last_mut().expect("checked above").reversed =
16053                should_newest_selection_be_reversed;
16054            should_newest_selection_be_reversed
16055        };
16056
16057        if selected_larger_node {
16058            self.select_syntax_node_history.disable_clearing = true;
16059            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16060                s.select(new_selections.clone());
16061            });
16062            self.select_syntax_node_history.disable_clearing = false;
16063        }
16064
16065        let start_row = last_new.start.to_display_point(&display_map).row().0;
16066        let end_row = last_new.end.to_display_point(&display_map).row().0;
16067        let selection_height = end_row - start_row + 1;
16068        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16069
16070        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16071        let scroll_behavior = if fits_on_the_screen {
16072            self.request_autoscroll(Autoscroll::fit(), cx);
16073            SelectSyntaxNodeScrollBehavior::FitSelection
16074        } else if is_selection_reversed {
16075            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16076            SelectSyntaxNodeScrollBehavior::CursorTop
16077        } else {
16078            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16079            SelectSyntaxNodeScrollBehavior::CursorBottom
16080        };
16081
16082        self.select_syntax_node_history.push((
16083            old_selections,
16084            scroll_behavior,
16085            is_selection_reversed,
16086        ));
16087    }
16088
16089    pub fn select_smaller_syntax_node(
16090        &mut self,
16091        _: &SelectSmallerSyntaxNode,
16092        window: &mut Window,
16093        cx: &mut Context<Self>,
16094    ) {
16095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16096
16097        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16098            self.select_syntax_node_history.pop()
16099        {
16100            if let Some(selection) = selections.last_mut() {
16101                selection.reversed = is_selection_reversed;
16102            }
16103
16104            self.select_syntax_node_history.disable_clearing = true;
16105            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16106                s.select(selections.to_vec());
16107            });
16108            self.select_syntax_node_history.disable_clearing = false;
16109
16110            match scroll_behavior {
16111                SelectSyntaxNodeScrollBehavior::CursorTop => {
16112                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16113                }
16114                SelectSyntaxNodeScrollBehavior::FitSelection => {
16115                    self.request_autoscroll(Autoscroll::fit(), cx);
16116                }
16117                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16118                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16119                }
16120            }
16121        }
16122    }
16123
16124    pub fn unwrap_syntax_node(
16125        &mut self,
16126        _: &UnwrapSyntaxNode,
16127        window: &mut Window,
16128        cx: &mut Context<Self>,
16129    ) {
16130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16131
16132        let buffer = self.buffer.read(cx).snapshot(cx);
16133        let selections = self
16134            .selections
16135            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16136            .into_iter()
16137            // subtracting the offset requires sorting
16138            .sorted_by_key(|i| i.start);
16139
16140        let full_edits = selections
16141            .into_iter()
16142            .filter_map(|selection| {
16143                let child = if selection.is_empty()
16144                    && let Some((_, ancestor_range)) =
16145                        buffer.syntax_ancestor(selection.start..selection.end)
16146                {
16147                    ancestor_range
16148                } else {
16149                    selection.range()
16150                };
16151
16152                let mut parent = child.clone();
16153                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16154                    parent = ancestor_range;
16155                    if parent.start < child.start || parent.end > child.end {
16156                        break;
16157                    }
16158                }
16159
16160                if parent == child {
16161                    return None;
16162                }
16163                let text = buffer.text_for_range(child).collect::<String>();
16164                Some((selection.id, parent, text))
16165            })
16166            .collect::<Vec<_>>();
16167        if full_edits.is_empty() {
16168            return;
16169        }
16170
16171        self.transact(window, cx, |this, window, cx| {
16172            this.buffer.update(cx, |buffer, cx| {
16173                buffer.edit(
16174                    full_edits
16175                        .iter()
16176                        .map(|(_, p, t)| (p.clone(), t.clone()))
16177                        .collect::<Vec<_>>(),
16178                    None,
16179                    cx,
16180                );
16181            });
16182            this.change_selections(Default::default(), window, cx, |s| {
16183                let mut offset = 0;
16184                let mut selections = vec![];
16185                for (id, parent, text) in full_edits {
16186                    let start = parent.start - offset;
16187                    offset += (parent.end - parent.start) - text.len();
16188                    selections.push(Selection {
16189                        id,
16190                        start,
16191                        end: start + text.len(),
16192                        reversed: false,
16193                        goal: Default::default(),
16194                    });
16195                }
16196                s.select(selections);
16197            });
16198        });
16199    }
16200
16201    pub fn select_next_syntax_node(
16202        &mut self,
16203        _: &SelectNextSyntaxNode,
16204        window: &mut Window,
16205        cx: &mut Context<Self>,
16206    ) {
16207        let old_selections: Box<[_]> = self
16208            .selections
16209            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16210            .into();
16211        if old_selections.is_empty() {
16212            return;
16213        }
16214
16215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16216
16217        let buffer = self.buffer.read(cx).snapshot(cx);
16218        let mut selected_sibling = false;
16219
16220        let new_selections = old_selections
16221            .iter()
16222            .map(|selection| {
16223                let old_range = selection.start..selection.end;
16224
16225                let old_range =
16226                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16227                let excerpt = buffer.excerpt_containing(old_range.clone());
16228
16229                if let Some(mut excerpt) = excerpt
16230                    && let Some(node) = excerpt
16231                        .buffer()
16232                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16233                {
16234                    let new_range = excerpt.map_range_from_buffer(
16235                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16236                    );
16237                    selected_sibling = true;
16238                    Selection {
16239                        id: selection.id,
16240                        start: new_range.start,
16241                        end: new_range.end,
16242                        goal: SelectionGoal::None,
16243                        reversed: selection.reversed,
16244                    }
16245                } else {
16246                    selection.clone()
16247                }
16248            })
16249            .collect::<Vec<_>>();
16250
16251        if selected_sibling {
16252            self.change_selections(
16253                SelectionEffects::scroll(Autoscroll::fit()),
16254                window,
16255                cx,
16256                |s| {
16257                    s.select(new_selections);
16258                },
16259            );
16260        }
16261    }
16262
16263    pub fn select_prev_syntax_node(
16264        &mut self,
16265        _: &SelectPreviousSyntaxNode,
16266        window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) {
16269        let old_selections: Box<[_]> = self
16270            .selections
16271            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16272            .into();
16273        if old_selections.is_empty() {
16274            return;
16275        }
16276
16277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16278
16279        let buffer = self.buffer.read(cx).snapshot(cx);
16280        let mut selected_sibling = false;
16281
16282        let new_selections = old_selections
16283            .iter()
16284            .map(|selection| {
16285                let old_range = selection.start..selection.end;
16286                let old_range =
16287                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16288                let excerpt = buffer.excerpt_containing(old_range.clone());
16289
16290                if let Some(mut excerpt) = excerpt
16291                    && let Some(node) = excerpt
16292                        .buffer()
16293                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16294                {
16295                    let new_range = excerpt.map_range_from_buffer(
16296                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16297                    );
16298                    selected_sibling = true;
16299                    Selection {
16300                        id: selection.id,
16301                        start: new_range.start,
16302                        end: new_range.end,
16303                        goal: SelectionGoal::None,
16304                        reversed: selection.reversed,
16305                    }
16306                } else {
16307                    selection.clone()
16308                }
16309            })
16310            .collect::<Vec<_>>();
16311
16312        if selected_sibling {
16313            self.change_selections(
16314                SelectionEffects::scroll(Autoscroll::fit()),
16315                window,
16316                cx,
16317                |s| {
16318                    s.select(new_selections);
16319                },
16320            );
16321        }
16322    }
16323
16324    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16325        if !EditorSettings::get_global(cx).gutter.runnables {
16326            self.clear_tasks();
16327            return Task::ready(());
16328        }
16329        let project = self.project().map(Entity::downgrade);
16330        let task_sources = self.lsp_task_sources(cx);
16331        let multi_buffer = self.buffer.downgrade();
16332        cx.spawn_in(window, async move |editor, cx| {
16333            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16334            let Some(project) = project.and_then(|p| p.upgrade()) else {
16335                return;
16336            };
16337            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16338                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16339            }) else {
16340                return;
16341            };
16342
16343            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16344            if hide_runnables {
16345                return;
16346            }
16347            let new_rows =
16348                cx.background_spawn({
16349                    let snapshot = display_snapshot.clone();
16350                    async move {
16351                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16352                    }
16353                })
16354                    .await;
16355            let Ok(lsp_tasks) =
16356                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16357            else {
16358                return;
16359            };
16360            let lsp_tasks = lsp_tasks.await;
16361
16362            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16363                lsp_tasks
16364                    .into_iter()
16365                    .flat_map(|(kind, tasks)| {
16366                        tasks.into_iter().filter_map(move |(location, task)| {
16367                            Some((kind.clone(), location?, task))
16368                        })
16369                    })
16370                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16371                        let buffer = location.target.buffer;
16372                        let buffer_snapshot = buffer.read(cx).snapshot();
16373                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16374                            |(excerpt_id, snapshot, _)| {
16375                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16376                                    display_snapshot
16377                                        .buffer_snapshot()
16378                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16379                                } else {
16380                                    None
16381                                }
16382                            },
16383                        );
16384                        if let Some(offset) = offset {
16385                            let task_buffer_range =
16386                                location.target.range.to_point(&buffer_snapshot);
16387                            let context_buffer_range =
16388                                task_buffer_range.to_offset(&buffer_snapshot);
16389                            let context_range = BufferOffset(context_buffer_range.start)
16390                                ..BufferOffset(context_buffer_range.end);
16391
16392                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16393                                .or_insert_with(|| RunnableTasks {
16394                                    templates: Vec::new(),
16395                                    offset,
16396                                    column: task_buffer_range.start.column,
16397                                    extra_variables: HashMap::default(),
16398                                    context_range,
16399                                })
16400                                .templates
16401                                .push((kind, task.original_task().clone()));
16402                        }
16403
16404                        acc
16405                    })
16406            }) else {
16407                return;
16408            };
16409
16410            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16411                buffer.language_settings(cx).tasks.prefer_lsp
16412            }) else {
16413                return;
16414            };
16415
16416            let rows = Self::runnable_rows(
16417                project,
16418                display_snapshot,
16419                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16420                new_rows,
16421                cx.clone(),
16422            )
16423            .await;
16424            editor
16425                .update(cx, |editor, _| {
16426                    editor.clear_tasks();
16427                    for (key, mut value) in rows {
16428                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16429                            value.templates.extend(lsp_tasks.templates);
16430                        }
16431
16432                        editor.insert_tasks(key, value);
16433                    }
16434                    for (key, value) in lsp_tasks_by_rows {
16435                        editor.insert_tasks(key, value);
16436                    }
16437                })
16438                .ok();
16439        })
16440    }
16441    fn fetch_runnable_ranges(
16442        snapshot: &DisplaySnapshot,
16443        range: Range<Anchor>,
16444    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16445        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16446    }
16447
16448    fn runnable_rows(
16449        project: Entity<Project>,
16450        snapshot: DisplaySnapshot,
16451        prefer_lsp: bool,
16452        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16453        cx: AsyncWindowContext,
16454    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16455        cx.spawn(async move |cx| {
16456            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16457            for (run_range, mut runnable) in runnable_ranges {
16458                let Some(tasks) = cx
16459                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16460                    .ok()
16461                else {
16462                    continue;
16463                };
16464                let mut tasks = tasks.await;
16465
16466                if prefer_lsp {
16467                    tasks.retain(|(task_kind, _)| {
16468                        !matches!(task_kind, TaskSourceKind::Language { .. })
16469                    });
16470                }
16471                if tasks.is_empty() {
16472                    continue;
16473                }
16474
16475                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16476                let Some(row) = snapshot
16477                    .buffer_snapshot()
16478                    .buffer_line_for_row(MultiBufferRow(point.row))
16479                    .map(|(_, range)| range.start.row)
16480                else {
16481                    continue;
16482                };
16483
16484                let context_range =
16485                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16486                runnable_rows.push((
16487                    (runnable.buffer_id, row),
16488                    RunnableTasks {
16489                        templates: tasks,
16490                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16491                        context_range,
16492                        column: point.column,
16493                        extra_variables: runnable.extra_captures,
16494                    },
16495                ));
16496            }
16497            runnable_rows
16498        })
16499    }
16500
16501    fn templates_with_tags(
16502        project: &Entity<Project>,
16503        runnable: &mut Runnable,
16504        cx: &mut App,
16505    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16506        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16507            let (worktree_id, file) = project
16508                .buffer_for_id(runnable.buffer, cx)
16509                .and_then(|buffer| buffer.read(cx).file())
16510                .map(|file| (file.worktree_id(cx), file.clone()))
16511                .unzip();
16512
16513            (
16514                project.task_store().read(cx).task_inventory().cloned(),
16515                worktree_id,
16516                file,
16517            )
16518        });
16519
16520        let tags = mem::take(&mut runnable.tags);
16521        let language = runnable.language.clone();
16522        cx.spawn(async move |cx| {
16523            let mut templates_with_tags = Vec::new();
16524            if let Some(inventory) = inventory {
16525                for RunnableTag(tag) in tags {
16526                    let new_tasks = inventory.update(cx, |inventory, cx| {
16527                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16528                    });
16529                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16530                        move |(_, template)| {
16531                            template.tags.iter().any(|source_tag| source_tag == &tag)
16532                        },
16533                    ));
16534                }
16535            }
16536            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16537
16538            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16539                // Strongest source wins; if we have worktree tag binding, prefer that to
16540                // global and language bindings;
16541                // if we have a global binding, prefer that to language binding.
16542                let first_mismatch = templates_with_tags
16543                    .iter()
16544                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16545                if let Some(index) = first_mismatch {
16546                    templates_with_tags.truncate(index);
16547                }
16548            }
16549
16550            templates_with_tags
16551        })
16552    }
16553
16554    pub fn move_to_enclosing_bracket(
16555        &mut self,
16556        _: &MoveToEnclosingBracket,
16557        window: &mut Window,
16558        cx: &mut Context<Self>,
16559    ) {
16560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16561        self.change_selections(Default::default(), window, cx, |s| {
16562            s.move_offsets_with(|snapshot, selection| {
16563                let Some(enclosing_bracket_ranges) =
16564                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16565                else {
16566                    return;
16567                };
16568
16569                let mut best_length = usize::MAX;
16570                let mut best_inside = false;
16571                let mut best_in_bracket_range = false;
16572                let mut best_destination = None;
16573                for (open, close) in enclosing_bracket_ranges {
16574                    let close = close.to_inclusive();
16575                    let length = *close.end() - open.start;
16576                    let inside = selection.start >= open.end && selection.end <= *close.start();
16577                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16578                        || close.contains(&selection.head());
16579
16580                    // If best is next to a bracket and current isn't, skip
16581                    if !in_bracket_range && best_in_bracket_range {
16582                        continue;
16583                    }
16584
16585                    // Prefer smaller lengths unless best is inside and current isn't
16586                    if length > best_length && (best_inside || !inside) {
16587                        continue;
16588                    }
16589
16590                    best_length = length;
16591                    best_inside = inside;
16592                    best_in_bracket_range = in_bracket_range;
16593                    best_destination = Some(
16594                        if close.contains(&selection.start) && close.contains(&selection.end) {
16595                            if inside { open.end } else { open.start }
16596                        } else if inside {
16597                            *close.start()
16598                        } else {
16599                            *close.end()
16600                        },
16601                    );
16602                }
16603
16604                if let Some(destination) = best_destination {
16605                    selection.collapse_to(destination, SelectionGoal::None);
16606                }
16607            })
16608        });
16609    }
16610
16611    pub fn undo_selection(
16612        &mut self,
16613        _: &UndoSelection,
16614        window: &mut Window,
16615        cx: &mut Context<Self>,
16616    ) {
16617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16618        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16619            self.selection_history.mode = SelectionHistoryMode::Undoing;
16620            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16621                this.end_selection(window, cx);
16622                this.change_selections(
16623                    SelectionEffects::scroll(Autoscroll::newest()),
16624                    window,
16625                    cx,
16626                    |s| s.select_anchors(entry.selections.to_vec()),
16627                );
16628            });
16629            self.selection_history.mode = SelectionHistoryMode::Normal;
16630
16631            self.select_next_state = entry.select_next_state;
16632            self.select_prev_state = entry.select_prev_state;
16633            self.add_selections_state = entry.add_selections_state;
16634        }
16635    }
16636
16637    pub fn redo_selection(
16638        &mut self,
16639        _: &RedoSelection,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) {
16643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16644        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16645            self.selection_history.mode = SelectionHistoryMode::Redoing;
16646            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16647                this.end_selection(window, cx);
16648                this.change_selections(
16649                    SelectionEffects::scroll(Autoscroll::newest()),
16650                    window,
16651                    cx,
16652                    |s| s.select_anchors(entry.selections.to_vec()),
16653                );
16654            });
16655            self.selection_history.mode = SelectionHistoryMode::Normal;
16656
16657            self.select_next_state = entry.select_next_state;
16658            self.select_prev_state = entry.select_prev_state;
16659            self.add_selections_state = entry.add_selections_state;
16660        }
16661    }
16662
16663    pub fn expand_excerpts(
16664        &mut self,
16665        action: &ExpandExcerpts,
16666        _: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) {
16669        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16670    }
16671
16672    pub fn expand_excerpts_down(
16673        &mut self,
16674        action: &ExpandExcerptsDown,
16675        _: &mut Window,
16676        cx: &mut Context<Self>,
16677    ) {
16678        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16679    }
16680
16681    pub fn expand_excerpts_up(
16682        &mut self,
16683        action: &ExpandExcerptsUp,
16684        _: &mut Window,
16685        cx: &mut Context<Self>,
16686    ) {
16687        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16688    }
16689
16690    pub fn expand_excerpts_for_direction(
16691        &mut self,
16692        lines: u32,
16693        direction: ExpandExcerptDirection,
16694        cx: &mut Context<Self>,
16695    ) {
16696        let selections = self.selections.disjoint_anchors_arc();
16697
16698        let lines = if lines == 0 {
16699            EditorSettings::get_global(cx).expand_excerpt_lines
16700        } else {
16701            lines
16702        };
16703
16704        let snapshot = self.buffer.read(cx).snapshot(cx);
16705        let mut excerpt_ids = selections
16706            .iter()
16707            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16708            .collect::<Vec<_>>();
16709        excerpt_ids.sort();
16710        excerpt_ids.dedup();
16711
16712        if self.delegate_expand_excerpts {
16713            cx.emit(EditorEvent::ExpandExcerptsRequested {
16714                excerpt_ids,
16715                lines,
16716                direction,
16717            });
16718            return;
16719        }
16720
16721        self.buffer.update(cx, |buffer, cx| {
16722            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16723        })
16724    }
16725
16726    pub fn expand_excerpt(
16727        &mut self,
16728        excerpt: ExcerptId,
16729        direction: ExpandExcerptDirection,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16734
16735        if self.delegate_expand_excerpts {
16736            cx.emit(EditorEvent::ExpandExcerptsRequested {
16737                excerpt_ids: vec![excerpt],
16738                lines: lines_to_expand,
16739                direction,
16740            });
16741            return;
16742        }
16743
16744        let current_scroll_position = self.scroll_position(cx);
16745        let mut scroll = None;
16746
16747        if direction == ExpandExcerptDirection::Down {
16748            let multi_buffer = self.buffer.read(cx);
16749            let snapshot = multi_buffer.snapshot(cx);
16750            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16751                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16752                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16753            {
16754                let buffer_snapshot = buffer.read(cx).snapshot();
16755                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16756                let last_row = buffer_snapshot.max_point().row;
16757                let lines_below = last_row.saturating_sub(excerpt_end_row);
16758                if lines_below >= lines_to_expand {
16759                    scroll = Some(
16760                        current_scroll_position
16761                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16762                    );
16763                }
16764            }
16765        }
16766        if direction == ExpandExcerptDirection::Up
16767            && self
16768                .buffer
16769                .read(cx)
16770                .snapshot(cx)
16771                .excerpt_before(excerpt)
16772                .is_none()
16773        {
16774            scroll = Some(current_scroll_position);
16775        }
16776
16777        self.buffer.update(cx, |buffer, cx| {
16778            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16779        });
16780
16781        if let Some(new_scroll_position) = scroll {
16782            self.set_scroll_position(new_scroll_position, window, cx);
16783        }
16784    }
16785
16786    pub fn go_to_singleton_buffer_point(
16787        &mut self,
16788        point: Point,
16789        window: &mut Window,
16790        cx: &mut Context<Self>,
16791    ) {
16792        self.go_to_singleton_buffer_range(point..point, window, cx);
16793    }
16794
16795    pub fn go_to_singleton_buffer_range(
16796        &mut self,
16797        range: Range<Point>,
16798        window: &mut Window,
16799        cx: &mut Context<Self>,
16800    ) {
16801        let multibuffer = self.buffer().read(cx);
16802        let Some(buffer) = multibuffer.as_singleton() else {
16803            return;
16804        };
16805        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16806            return;
16807        };
16808        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16809            return;
16810        };
16811        self.change_selections(
16812            SelectionEffects::default().nav_history(true),
16813            window,
16814            cx,
16815            |s| s.select_anchor_ranges([start..end]),
16816        );
16817    }
16818
16819    pub fn go_to_diagnostic(
16820        &mut self,
16821        action: &GoToDiagnostic,
16822        window: &mut Window,
16823        cx: &mut Context<Self>,
16824    ) {
16825        if !self.diagnostics_enabled() {
16826            return;
16827        }
16828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16829        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16830    }
16831
16832    pub fn go_to_prev_diagnostic(
16833        &mut self,
16834        action: &GoToPreviousDiagnostic,
16835        window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        if !self.diagnostics_enabled() {
16839            return;
16840        }
16841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16842        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16843    }
16844
16845    pub fn go_to_diagnostic_impl(
16846        &mut self,
16847        direction: Direction,
16848        severity: GoToDiagnosticSeverityFilter,
16849        window: &mut Window,
16850        cx: &mut Context<Self>,
16851    ) {
16852        let buffer = self.buffer.read(cx).snapshot(cx);
16853        let selection = self
16854            .selections
16855            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16856
16857        let mut active_group_id = None;
16858        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16859            && active_group.active_range.start.to_offset(&buffer) == selection.start
16860        {
16861            active_group_id = Some(active_group.group_id);
16862        }
16863
16864        fn filtered<'a>(
16865            severity: GoToDiagnosticSeverityFilter,
16866            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16867        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16868            diagnostics
16869                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16870                .filter(|entry| entry.range.start != entry.range.end)
16871                .filter(|entry| !entry.diagnostic.is_unnecessary)
16872        }
16873
16874        let before = filtered(
16875            severity,
16876            buffer
16877                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16878                .filter(|entry| entry.range.start <= selection.start),
16879        );
16880        let after = filtered(
16881            severity,
16882            buffer
16883                .diagnostics_in_range(selection.start..buffer.len())
16884                .filter(|entry| entry.range.start >= selection.start),
16885        );
16886
16887        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16888        if direction == Direction::Prev {
16889            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16890            {
16891                for diagnostic in prev_diagnostics.into_iter().rev() {
16892                    if diagnostic.range.start != selection.start
16893                        || active_group_id
16894                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16895                    {
16896                        found = Some(diagnostic);
16897                        break 'outer;
16898                    }
16899                }
16900            }
16901        } else {
16902            for diagnostic in after.chain(before) {
16903                if diagnostic.range.start != selection.start
16904                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16905                {
16906                    found = Some(diagnostic);
16907                    break;
16908                }
16909            }
16910        }
16911        let Some(next_diagnostic) = found else {
16912            return;
16913        };
16914
16915        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16916        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16917            return;
16918        };
16919        let snapshot = self.snapshot(window, cx);
16920        if snapshot.intersects_fold(next_diagnostic.range.start) {
16921            self.unfold_ranges(
16922                std::slice::from_ref(&next_diagnostic.range),
16923                true,
16924                false,
16925                cx,
16926            );
16927        }
16928        self.change_selections(Default::default(), window, cx, |s| {
16929            s.select_ranges(vec![
16930                next_diagnostic.range.start..next_diagnostic.range.start,
16931            ])
16932        });
16933        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16934        self.refresh_edit_prediction(false, true, window, cx);
16935    }
16936
16937    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16939        let snapshot = self.snapshot(window, cx);
16940        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16941        self.go_to_hunk_before_or_after_position(
16942            &snapshot,
16943            selection.head(),
16944            Direction::Next,
16945            window,
16946            cx,
16947        );
16948    }
16949
16950    pub fn go_to_hunk_before_or_after_position(
16951        &mut self,
16952        snapshot: &EditorSnapshot,
16953        position: Point,
16954        direction: Direction,
16955        window: &mut Window,
16956        cx: &mut Context<Editor>,
16957    ) {
16958        let row = if direction == Direction::Next {
16959            self.hunk_after_position(snapshot, position)
16960                .map(|hunk| hunk.row_range.start)
16961        } else {
16962            self.hunk_before_position(snapshot, position)
16963        };
16964
16965        if let Some(row) = row {
16966            let destination = Point::new(row.0, 0);
16967            let autoscroll = Autoscroll::center();
16968
16969            self.unfold_ranges(&[destination..destination], false, false, cx);
16970            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16971                s.select_ranges([destination..destination]);
16972            });
16973        }
16974    }
16975
16976    fn hunk_after_position(
16977        &mut self,
16978        snapshot: &EditorSnapshot,
16979        position: Point,
16980    ) -> Option<MultiBufferDiffHunk> {
16981        snapshot
16982            .buffer_snapshot()
16983            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16984            .find(|hunk| hunk.row_range.start.0 > position.row)
16985            .or_else(|| {
16986                snapshot
16987                    .buffer_snapshot()
16988                    .diff_hunks_in_range(Point::zero()..position)
16989                    .find(|hunk| hunk.row_range.end.0 < position.row)
16990            })
16991    }
16992
16993    fn go_to_prev_hunk(
16994        &mut self,
16995        _: &GoToPreviousHunk,
16996        window: &mut Window,
16997        cx: &mut Context<Self>,
16998    ) {
16999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17000        let snapshot = self.snapshot(window, cx);
17001        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17002        self.go_to_hunk_before_or_after_position(
17003            &snapshot,
17004            selection.head(),
17005            Direction::Prev,
17006            window,
17007            cx,
17008        );
17009    }
17010
17011    fn hunk_before_position(
17012        &mut self,
17013        snapshot: &EditorSnapshot,
17014        position: Point,
17015    ) -> Option<MultiBufferRow> {
17016        snapshot
17017            .buffer_snapshot()
17018            .diff_hunk_before(position)
17019            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17020    }
17021
17022    fn go_to_next_change(
17023        &mut self,
17024        _: &GoToNextChange,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if let Some(selections) = self
17029            .change_list
17030            .next_change(1, Direction::Next)
17031            .map(|s| s.to_vec())
17032        {
17033            self.change_selections(Default::default(), window, cx, |s| {
17034                let map = s.display_snapshot();
17035                s.select_display_ranges(selections.iter().map(|a| {
17036                    let point = a.to_display_point(&map);
17037                    point..point
17038                }))
17039            })
17040        }
17041    }
17042
17043    fn go_to_previous_change(
17044        &mut self,
17045        _: &GoToPreviousChange,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        if let Some(selections) = self
17050            .change_list
17051            .next_change(1, Direction::Prev)
17052            .map(|s| s.to_vec())
17053        {
17054            self.change_selections(Default::default(), window, cx, |s| {
17055                let map = s.display_snapshot();
17056                s.select_display_ranges(selections.iter().map(|a| {
17057                    let point = a.to_display_point(&map);
17058                    point..point
17059                }))
17060            })
17061        }
17062    }
17063
17064    pub fn go_to_next_document_highlight(
17065        &mut self,
17066        _: &GoToNextDocumentHighlight,
17067        window: &mut Window,
17068        cx: &mut Context<Self>,
17069    ) {
17070        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17071    }
17072
17073    pub fn go_to_prev_document_highlight(
17074        &mut self,
17075        _: &GoToPreviousDocumentHighlight,
17076        window: &mut Window,
17077        cx: &mut Context<Self>,
17078    ) {
17079        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17080    }
17081
17082    pub fn go_to_document_highlight_before_or_after_position(
17083        &mut self,
17084        direction: Direction,
17085        window: &mut Window,
17086        cx: &mut Context<Editor>,
17087    ) {
17088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17089        let snapshot = self.snapshot(window, cx);
17090        let buffer = &snapshot.buffer_snapshot();
17091        let position = self
17092            .selections
17093            .newest::<Point>(&snapshot.display_snapshot)
17094            .head();
17095        let anchor_position = buffer.anchor_after(position);
17096
17097        // Get all document highlights (both read and write)
17098        let mut all_highlights = Vec::new();
17099
17100        if let Some((_, read_highlights)) = self
17101            .background_highlights
17102            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17103        {
17104            all_highlights.extend(read_highlights.iter());
17105        }
17106
17107        if let Some((_, write_highlights)) = self
17108            .background_highlights
17109            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17110        {
17111            all_highlights.extend(write_highlights.iter());
17112        }
17113
17114        if all_highlights.is_empty() {
17115            return;
17116        }
17117
17118        // Sort highlights by position
17119        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17120
17121        let target_highlight = match direction {
17122            Direction::Next => {
17123                // Find the first highlight after the current position
17124                all_highlights
17125                    .iter()
17126                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17127            }
17128            Direction::Prev => {
17129                // Find the last highlight before the current position
17130                all_highlights
17131                    .iter()
17132                    .rev()
17133                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17134            }
17135        };
17136
17137        if let Some(highlight) = target_highlight {
17138            let destination = highlight.start.to_point(buffer);
17139            let autoscroll = Autoscroll::center();
17140
17141            self.unfold_ranges(&[destination..destination], false, false, cx);
17142            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17143                s.select_ranges([destination..destination]);
17144            });
17145        }
17146    }
17147
17148    fn go_to_line<T: 'static>(
17149        &mut self,
17150        position: Anchor,
17151        highlight_color: Option<Hsla>,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) {
17155        let snapshot = self.snapshot(window, cx).display_snapshot;
17156        let position = position.to_point(&snapshot.buffer_snapshot());
17157        let start = snapshot
17158            .buffer_snapshot()
17159            .clip_point(Point::new(position.row, 0), Bias::Left);
17160        let end = start + Point::new(1, 0);
17161        let start = snapshot.buffer_snapshot().anchor_before(start);
17162        let end = snapshot.buffer_snapshot().anchor_before(end);
17163
17164        self.highlight_rows::<T>(
17165            start..end,
17166            highlight_color
17167                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17168            Default::default(),
17169            cx,
17170        );
17171
17172        if self.buffer.read(cx).is_singleton() {
17173            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17174        }
17175    }
17176
17177    pub fn go_to_definition(
17178        &mut self,
17179        _: &GoToDefinition,
17180        window: &mut Window,
17181        cx: &mut Context<Self>,
17182    ) -> Task<Result<Navigated>> {
17183        let definition =
17184            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17185        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17186        cx.spawn_in(window, async move |editor, cx| {
17187            if definition.await? == Navigated::Yes {
17188                return Ok(Navigated::Yes);
17189            }
17190            match fallback_strategy {
17191                GoToDefinitionFallback::None => Ok(Navigated::No),
17192                GoToDefinitionFallback::FindAllReferences => {
17193                    match editor.update_in(cx, |editor, window, cx| {
17194                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17195                    })? {
17196                        Some(references) => references.await,
17197                        None => Ok(Navigated::No),
17198                    }
17199                }
17200            }
17201        })
17202    }
17203
17204    pub fn go_to_declaration(
17205        &mut self,
17206        _: &GoToDeclaration,
17207        window: &mut Window,
17208        cx: &mut Context<Self>,
17209    ) -> Task<Result<Navigated>> {
17210        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17211    }
17212
17213    pub fn go_to_declaration_split(
17214        &mut self,
17215        _: &GoToDeclaration,
17216        window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) -> Task<Result<Navigated>> {
17219        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17220    }
17221
17222    pub fn go_to_implementation(
17223        &mut self,
17224        _: &GoToImplementation,
17225        window: &mut Window,
17226        cx: &mut Context<Self>,
17227    ) -> Task<Result<Navigated>> {
17228        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17229    }
17230
17231    pub fn go_to_implementation_split(
17232        &mut self,
17233        _: &GoToImplementationSplit,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) -> Task<Result<Navigated>> {
17237        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17238    }
17239
17240    pub fn go_to_type_definition(
17241        &mut self,
17242        _: &GoToTypeDefinition,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) -> Task<Result<Navigated>> {
17246        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17247    }
17248
17249    pub fn go_to_definition_split(
17250        &mut self,
17251        _: &GoToDefinitionSplit,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) -> Task<Result<Navigated>> {
17255        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17256    }
17257
17258    pub fn go_to_type_definition_split(
17259        &mut self,
17260        _: &GoToTypeDefinitionSplit,
17261        window: &mut Window,
17262        cx: &mut Context<Self>,
17263    ) -> Task<Result<Navigated>> {
17264        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17265    }
17266
17267    fn go_to_definition_of_kind(
17268        &mut self,
17269        kind: GotoDefinitionKind,
17270        split: bool,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) -> Task<Result<Navigated>> {
17274        let Some(provider) = self.semantics_provider.clone() else {
17275            return Task::ready(Ok(Navigated::No));
17276        };
17277        let head = self
17278            .selections
17279            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17280            .head();
17281        let buffer = self.buffer.read(cx);
17282        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17283            return Task::ready(Ok(Navigated::No));
17284        };
17285        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17286            return Task::ready(Ok(Navigated::No));
17287        };
17288
17289        cx.spawn_in(window, async move |editor, cx| {
17290            let Some(definitions) = definitions.await? else {
17291                return Ok(Navigated::No);
17292            };
17293            let navigated = editor
17294                .update_in(cx, |editor, window, cx| {
17295                    editor.navigate_to_hover_links(
17296                        Some(kind),
17297                        definitions
17298                            .into_iter()
17299                            .filter(|location| {
17300                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17301                            })
17302                            .map(HoverLink::Text)
17303                            .collect::<Vec<_>>(),
17304                        split,
17305                        window,
17306                        cx,
17307                    )
17308                })?
17309                .await?;
17310            anyhow::Ok(navigated)
17311        })
17312    }
17313
17314    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17315        let selection = self.selections.newest_anchor();
17316        let head = selection.head();
17317        let tail = selection.tail();
17318
17319        let Some((buffer, start_position)) =
17320            self.buffer.read(cx).text_anchor_for_position(head, cx)
17321        else {
17322            return;
17323        };
17324
17325        let end_position = if head != tail {
17326            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17327                return;
17328            };
17329            Some(pos)
17330        } else {
17331            None
17332        };
17333
17334        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17335            let url = if let Some(end_pos) = end_position {
17336                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17337            } else {
17338                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17339            };
17340
17341            if let Some(url) = url {
17342                cx.update(|window, cx| {
17343                    if parse_zed_link(&url, cx).is_some() {
17344                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17345                    } else {
17346                        cx.open_url(&url);
17347                    }
17348                })?;
17349            }
17350
17351            anyhow::Ok(())
17352        });
17353
17354        url_finder.detach();
17355    }
17356
17357    pub fn open_selected_filename(
17358        &mut self,
17359        _: &OpenSelectedFilename,
17360        window: &mut Window,
17361        cx: &mut Context<Self>,
17362    ) {
17363        let Some(workspace) = self.workspace() else {
17364            return;
17365        };
17366
17367        let position = self.selections.newest_anchor().head();
17368
17369        let Some((buffer, buffer_position)) =
17370            self.buffer.read(cx).text_anchor_for_position(position, cx)
17371        else {
17372            return;
17373        };
17374
17375        let project = self.project.clone();
17376
17377        cx.spawn_in(window, async move |_, cx| {
17378            let result = find_file(&buffer, project, buffer_position, cx).await;
17379
17380            if let Some((_, path)) = result {
17381                workspace
17382                    .update_in(cx, |workspace, window, cx| {
17383                        workspace.open_resolved_path(path, window, cx)
17384                    })?
17385                    .await?;
17386            }
17387            anyhow::Ok(())
17388        })
17389        .detach();
17390    }
17391
17392    pub(crate) fn navigate_to_hover_links(
17393        &mut self,
17394        kind: Option<GotoDefinitionKind>,
17395        definitions: Vec<HoverLink>,
17396        split: bool,
17397        window: &mut Window,
17398        cx: &mut Context<Editor>,
17399    ) -> Task<Result<Navigated>> {
17400        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17401        let mut first_url_or_file = None;
17402        let definitions: Vec<_> = definitions
17403            .into_iter()
17404            .filter_map(|def| match def {
17405                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17406                HoverLink::InlayHint(lsp_location, server_id) => {
17407                    let computation =
17408                        self.compute_target_location(lsp_location, server_id, window, cx);
17409                    Some(cx.background_spawn(computation))
17410                }
17411                HoverLink::Url(url) => {
17412                    first_url_or_file = Some(Either::Left(url));
17413                    None
17414                }
17415                HoverLink::File(path) => {
17416                    first_url_or_file = Some(Either::Right(path));
17417                    None
17418                }
17419            })
17420            .collect();
17421
17422        let workspace = self.workspace();
17423
17424        cx.spawn_in(window, async move |editor, cx| {
17425            let locations: Vec<Location> = future::join_all(definitions)
17426                .await
17427                .into_iter()
17428                .filter_map(|location| location.transpose())
17429                .collect::<Result<_>>()
17430                .context("location tasks")?;
17431            let mut locations = cx.update(|_, cx| {
17432                locations
17433                    .into_iter()
17434                    .map(|location| {
17435                        let buffer = location.buffer.read(cx);
17436                        (location.buffer, location.range.to_point(buffer))
17437                    })
17438                    .into_group_map()
17439            })?;
17440            let mut num_locations = 0;
17441            for ranges in locations.values_mut() {
17442                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17443                ranges.dedup();
17444                num_locations += ranges.len();
17445            }
17446
17447            if num_locations > 1 {
17448                let tab_kind = match kind {
17449                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17450                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17451                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17452                    Some(GotoDefinitionKind::Type) => "Types",
17453                };
17454                let title = editor
17455                    .update_in(cx, |_, _, cx| {
17456                        let target = locations
17457                            .iter()
17458                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17459                            .map(|(buffer, location)| {
17460                                buffer
17461                                    .read(cx)
17462                                    .text_for_range(location.clone())
17463                                    .collect::<String>()
17464                            })
17465                            .filter(|text| !text.contains('\n'))
17466                            .unique()
17467                            .take(3)
17468                            .join(", ");
17469                        if target.is_empty() {
17470                            tab_kind.to_owned()
17471                        } else {
17472                            format!("{tab_kind} for {target}")
17473                        }
17474                    })
17475                    .context("buffer title")?;
17476
17477                let Some(workspace) = workspace else {
17478                    return Ok(Navigated::No);
17479                };
17480
17481                let opened = workspace
17482                    .update_in(cx, |workspace, window, cx| {
17483                        let allow_preview = PreviewTabsSettings::get_global(cx)
17484                            .enable_preview_multibuffer_from_code_navigation;
17485                        Self::open_locations_in_multibuffer(
17486                            workspace,
17487                            locations,
17488                            title,
17489                            split,
17490                            allow_preview,
17491                            MultibufferSelectionMode::First,
17492                            window,
17493                            cx,
17494                        )
17495                    })
17496                    .is_ok();
17497
17498                anyhow::Ok(Navigated::from_bool(opened))
17499            } else if num_locations == 0 {
17500                // If there is one url or file, open it directly
17501                match first_url_or_file {
17502                    Some(Either::Left(url)) => {
17503                        cx.update(|window, cx| {
17504                            if parse_zed_link(&url, cx).is_some() {
17505                                window
17506                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17507                            } else {
17508                                cx.open_url(&url);
17509                            }
17510                        })?;
17511                        Ok(Navigated::Yes)
17512                    }
17513                    Some(Either::Right(path)) => {
17514                        // TODO(andrew): respect preview tab settings
17515                        //               `enable_keep_preview_on_code_navigation` and
17516                        //               `enable_preview_file_from_code_navigation`
17517                        let Some(workspace) = workspace else {
17518                            return Ok(Navigated::No);
17519                        };
17520                        workspace
17521                            .update_in(cx, |workspace, window, cx| {
17522                                workspace.open_resolved_path(path, window, cx)
17523                            })?
17524                            .await?;
17525                        Ok(Navigated::Yes)
17526                    }
17527                    None => Ok(Navigated::No),
17528                }
17529            } else {
17530                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17531                let target_range = target_ranges.first().unwrap().clone();
17532
17533                editor.update_in(cx, |editor, window, cx| {
17534                    let range = target_range.to_point(target_buffer.read(cx));
17535                    let range = editor.range_for_match(&range);
17536                    let range = collapse_multiline_range(range);
17537
17538                    if !split
17539                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17540                    {
17541                        editor.go_to_singleton_buffer_range(range, window, cx);
17542                    } else {
17543                        let Some(workspace) = workspace else {
17544                            return Navigated::No;
17545                        };
17546                        let pane = workspace.read(cx).active_pane().clone();
17547                        window.defer(cx, move |window, cx| {
17548                            let target_editor: Entity<Self> =
17549                                workspace.update(cx, |workspace, cx| {
17550                                    let pane = if split {
17551                                        workspace.adjacent_pane(window, cx)
17552                                    } else {
17553                                        workspace.active_pane().clone()
17554                                    };
17555
17556                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17557                                    let keep_old_preview = preview_tabs_settings
17558                                        .enable_keep_preview_on_code_navigation;
17559                                    let allow_new_preview = preview_tabs_settings
17560                                        .enable_preview_file_from_code_navigation;
17561
17562                                    workspace.open_project_item(
17563                                        pane,
17564                                        target_buffer.clone(),
17565                                        true,
17566                                        true,
17567                                        keep_old_preview,
17568                                        allow_new_preview,
17569                                        window,
17570                                        cx,
17571                                    )
17572                                });
17573                            target_editor.update(cx, |target_editor, cx| {
17574                                // When selecting a definition in a different buffer, disable the nav history
17575                                // to avoid creating a history entry at the previous cursor location.
17576                                pane.update(cx, |pane, _| pane.disable_history());
17577                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17578                                pane.update(cx, |pane, _| pane.enable_history());
17579                            });
17580                        });
17581                    }
17582                    Navigated::Yes
17583                })
17584            }
17585        })
17586    }
17587
17588    fn compute_target_location(
17589        &self,
17590        lsp_location: lsp::Location,
17591        server_id: LanguageServerId,
17592        window: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) -> Task<anyhow::Result<Option<Location>>> {
17595        let Some(project) = self.project.clone() else {
17596            return Task::ready(Ok(None));
17597        };
17598
17599        cx.spawn_in(window, async move |editor, cx| {
17600            let location_task = editor.update(cx, |_, cx| {
17601                project.update(cx, |project, cx| {
17602                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17603                })
17604            })?;
17605            let location = Some({
17606                let target_buffer_handle = location_task.await.context("open local buffer")?;
17607                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17608                    let target_start = target_buffer
17609                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17610                    let target_end = target_buffer
17611                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17612                    target_buffer.anchor_after(target_start)
17613                        ..target_buffer.anchor_before(target_end)
17614                });
17615                Location {
17616                    buffer: target_buffer_handle,
17617                    range,
17618                }
17619            });
17620            Ok(location)
17621        })
17622    }
17623
17624    fn go_to_next_reference(
17625        &mut self,
17626        _: &GoToNextReference,
17627        window: &mut Window,
17628        cx: &mut Context<Self>,
17629    ) {
17630        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17631        if let Some(task) = task {
17632            task.detach();
17633        };
17634    }
17635
17636    fn go_to_prev_reference(
17637        &mut self,
17638        _: &GoToPreviousReference,
17639        window: &mut Window,
17640        cx: &mut Context<Self>,
17641    ) {
17642        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17643        if let Some(task) = task {
17644            task.detach();
17645        };
17646    }
17647
17648    pub fn go_to_reference_before_or_after_position(
17649        &mut self,
17650        direction: Direction,
17651        count: usize,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Option<Task<Result<()>>> {
17655        let selection = self.selections.newest_anchor();
17656        let head = selection.head();
17657
17658        let multi_buffer = self.buffer.read(cx);
17659
17660        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17661        let workspace = self.workspace()?;
17662        let project = workspace.read(cx).project().clone();
17663        let references =
17664            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17665        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17666            let Some(locations) = references.await? else {
17667                return Ok(());
17668            };
17669
17670            if locations.is_empty() {
17671                // totally normal - the cursor may be on something which is not
17672                // a symbol (e.g. a keyword)
17673                log::info!("no references found under cursor");
17674                return Ok(());
17675            }
17676
17677            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17678
17679            let (locations, current_location_index) =
17680                multi_buffer.update(cx, |multi_buffer, cx| {
17681                    let mut locations = locations
17682                        .into_iter()
17683                        .filter_map(|loc| {
17684                            let start = multi_buffer.buffer_anchor_to_anchor(
17685                                &loc.buffer,
17686                                loc.range.start,
17687                                cx,
17688                            )?;
17689                            let end = multi_buffer.buffer_anchor_to_anchor(
17690                                &loc.buffer,
17691                                loc.range.end,
17692                                cx,
17693                            )?;
17694                            Some(start..end)
17695                        })
17696                        .collect::<Vec<_>>();
17697
17698                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17699                    // There is an O(n) implementation, but given this list will be
17700                    // small (usually <100 items), the extra O(log(n)) factor isn't
17701                    // worth the (surprisingly large amount of) extra complexity.
17702                    locations
17703                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17704
17705                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17706
17707                    let current_location_index = locations.iter().position(|loc| {
17708                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17709                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17710                    });
17711
17712                    (locations, current_location_index)
17713                });
17714
17715            let Some(current_location_index) = current_location_index else {
17716                // This indicates something has gone wrong, because we already
17717                // handle the "no references" case above
17718                log::error!(
17719                    "failed to find current reference under cursor. Total references: {}",
17720                    locations.len()
17721                );
17722                return Ok(());
17723            };
17724
17725            let destination_location_index = match direction {
17726                Direction::Next => (current_location_index + count) % locations.len(),
17727                Direction::Prev => {
17728                    (current_location_index + locations.len() - count % locations.len())
17729                        % locations.len()
17730                }
17731            };
17732
17733            // TODO(cameron): is this needed?
17734            // the thinking is to avoid "jumping to the current location" (avoid
17735            // polluting "jumplist" in vim terms)
17736            if current_location_index == destination_location_index {
17737                return Ok(());
17738            }
17739
17740            let Range { start, end } = locations[destination_location_index];
17741
17742            editor.update_in(cx, |editor, window, cx| {
17743                let effects = SelectionEffects::default();
17744
17745                editor.unfold_ranges(&[start..end], false, false, cx);
17746                editor.change_selections(effects, window, cx, |s| {
17747                    s.select_ranges([start..start]);
17748                });
17749            })?;
17750
17751            Ok(())
17752        }))
17753    }
17754
17755    pub fn find_all_references(
17756        &mut self,
17757        action: &FindAllReferences,
17758        window: &mut Window,
17759        cx: &mut Context<Self>,
17760    ) -> Option<Task<Result<Navigated>>> {
17761        let always_open_multibuffer = action.always_open_multibuffer;
17762        let selection = self.selections.newest_anchor();
17763        let multi_buffer = self.buffer.read(cx);
17764        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17765        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17766        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17767        let head = selection_offset.head();
17768
17769        let head_anchor = multi_buffer_snapshot.anchor_at(
17770            head,
17771            if head < selection_offset.tail() {
17772                Bias::Right
17773            } else {
17774                Bias::Left
17775            },
17776        );
17777
17778        match self
17779            .find_all_references_task_sources
17780            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17781        {
17782            Ok(_) => {
17783                log::info!(
17784                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17785                );
17786                return None;
17787            }
17788            Err(i) => {
17789                self.find_all_references_task_sources.insert(i, head_anchor);
17790            }
17791        }
17792
17793        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17794        let workspace = self.workspace()?;
17795        let project = workspace.read(cx).project().clone();
17796        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17797        Some(cx.spawn_in(window, async move |editor, cx| {
17798            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17799                if let Ok(i) = editor
17800                    .find_all_references_task_sources
17801                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17802                {
17803                    editor.find_all_references_task_sources.remove(i);
17804                }
17805            });
17806
17807            let Some(locations) = references.await? else {
17808                return anyhow::Ok(Navigated::No);
17809            };
17810            let mut locations = cx.update(|_, cx| {
17811                locations
17812                    .into_iter()
17813                    .map(|location| {
17814                        let buffer = location.buffer.read(cx);
17815                        (location.buffer, location.range.to_point(buffer))
17816                    })
17817                    // if special-casing the single-match case, remove ranges
17818                    // that intersect current selection
17819                    .filter(|(location_buffer, location)| {
17820                        if always_open_multibuffer || &buffer != location_buffer {
17821                            return true;
17822                        }
17823
17824                        !location.contains_inclusive(&selection_point.range())
17825                    })
17826                    .into_group_map()
17827            })?;
17828            if locations.is_empty() {
17829                return anyhow::Ok(Navigated::No);
17830            }
17831            for ranges in locations.values_mut() {
17832                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17833                ranges.dedup();
17834            }
17835            let mut num_locations = 0;
17836            for ranges in locations.values_mut() {
17837                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17838                ranges.dedup();
17839                num_locations += ranges.len();
17840            }
17841
17842            if num_locations == 1 && !always_open_multibuffer {
17843                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17844                let target_range = target_ranges.first().unwrap().clone();
17845
17846                return editor.update_in(cx, |editor, window, cx| {
17847                    let range = target_range.to_point(target_buffer.read(cx));
17848                    let range = editor.range_for_match(&range);
17849                    let range = range.start..range.start;
17850
17851                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17852                        editor.go_to_singleton_buffer_range(range, window, cx);
17853                    } else {
17854                        let pane = workspace.read(cx).active_pane().clone();
17855                        window.defer(cx, move |window, cx| {
17856                            let target_editor: Entity<Self> =
17857                                workspace.update(cx, |workspace, cx| {
17858                                    let pane = workspace.active_pane().clone();
17859
17860                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17861                                    let keep_old_preview = preview_tabs_settings
17862                                        .enable_keep_preview_on_code_navigation;
17863                                    let allow_new_preview = preview_tabs_settings
17864                                        .enable_preview_file_from_code_navigation;
17865
17866                                    workspace.open_project_item(
17867                                        pane,
17868                                        target_buffer.clone(),
17869                                        true,
17870                                        true,
17871                                        keep_old_preview,
17872                                        allow_new_preview,
17873                                        window,
17874                                        cx,
17875                                    )
17876                                });
17877                            target_editor.update(cx, |target_editor, cx| {
17878                                // When selecting a definition in a different buffer, disable the nav history
17879                                // to avoid creating a history entry at the previous cursor location.
17880                                pane.update(cx, |pane, _| pane.disable_history());
17881                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17882                                pane.update(cx, |pane, _| pane.enable_history());
17883                            });
17884                        });
17885                    }
17886                    Navigated::No
17887                });
17888            }
17889
17890            workspace.update_in(cx, |workspace, window, cx| {
17891                let target = locations
17892                    .iter()
17893                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17894                    .map(|(buffer, location)| {
17895                        buffer
17896                            .read(cx)
17897                            .text_for_range(location.clone())
17898                            .collect::<String>()
17899                    })
17900                    .filter(|text| !text.contains('\n'))
17901                    .unique()
17902                    .take(3)
17903                    .join(", ");
17904                let title = if target.is_empty() {
17905                    "References".to_owned()
17906                } else {
17907                    format!("References to {target}")
17908                };
17909                let allow_preview = PreviewTabsSettings::get_global(cx)
17910                    .enable_preview_multibuffer_from_code_navigation;
17911                Self::open_locations_in_multibuffer(
17912                    workspace,
17913                    locations,
17914                    title,
17915                    false,
17916                    allow_preview,
17917                    MultibufferSelectionMode::First,
17918                    window,
17919                    cx,
17920                );
17921                Navigated::Yes
17922            })
17923        }))
17924    }
17925
17926    /// Opens a multibuffer with the given project locations in it.
17927    pub fn open_locations_in_multibuffer(
17928        workspace: &mut Workspace,
17929        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17930        title: String,
17931        split: bool,
17932        allow_preview: bool,
17933        multibuffer_selection_mode: MultibufferSelectionMode,
17934        window: &mut Window,
17935        cx: &mut Context<Workspace>,
17936    ) {
17937        if locations.is_empty() {
17938            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17939            return;
17940        }
17941
17942        let capability = workspace.project().read(cx).capability();
17943        let mut ranges = <Vec<Range<Anchor>>>::new();
17944
17945        // a key to find existing multibuffer editors with the same set of locations
17946        // to prevent us from opening more and more multibuffer tabs for searches and the like
17947        let mut key = (title.clone(), vec![]);
17948        let excerpt_buffer = cx.new(|cx| {
17949            let key = &mut key.1;
17950            let mut multibuffer = MultiBuffer::new(capability);
17951            for (buffer, mut ranges_for_buffer) in locations {
17952                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17953                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17954                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17955                    PathKey::for_buffer(&buffer, cx),
17956                    buffer.clone(),
17957                    ranges_for_buffer,
17958                    multibuffer_context_lines(cx),
17959                    cx,
17960                );
17961                ranges.extend(new_ranges)
17962            }
17963
17964            multibuffer.with_title(title)
17965        });
17966        let existing = workspace.active_pane().update(cx, |pane, cx| {
17967            pane.items()
17968                .filter_map(|item| item.downcast::<Editor>())
17969                .find(|editor| {
17970                    editor
17971                        .read(cx)
17972                        .lookup_key
17973                        .as_ref()
17974                        .and_then(|it| {
17975                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17976                        })
17977                        .is_some_and(|it| *it == key)
17978                })
17979        });
17980        let was_existing = existing.is_some();
17981        let editor = existing.unwrap_or_else(|| {
17982            cx.new(|cx| {
17983                let mut editor = Editor::for_multibuffer(
17984                    excerpt_buffer,
17985                    Some(workspace.project().clone()),
17986                    window,
17987                    cx,
17988                );
17989                editor.lookup_key = Some(Box::new(key));
17990                editor
17991            })
17992        });
17993        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17994            MultibufferSelectionMode::First => {
17995                if let Some(first_range) = ranges.first() {
17996                    editor.change_selections(
17997                        SelectionEffects::no_scroll(),
17998                        window,
17999                        cx,
18000                        |selections| {
18001                            selections.clear_disjoint();
18002                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18003                        },
18004                    );
18005                }
18006                editor.highlight_background::<Self>(
18007                    &ranges,
18008                    |_, theme| theme.colors().editor_highlighted_line_background,
18009                    cx,
18010                );
18011            }
18012            MultibufferSelectionMode::All => {
18013                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18014                    selections.clear_disjoint();
18015                    selections.select_anchor_ranges(ranges);
18016                });
18017            }
18018        });
18019
18020        let item = Box::new(editor);
18021
18022        let pane = if split {
18023            workspace.adjacent_pane(window, cx)
18024        } else {
18025            workspace.active_pane().clone()
18026        };
18027        let activate_pane = split;
18028
18029        let mut destination_index = None;
18030        pane.update(cx, |pane, cx| {
18031            if allow_preview && !was_existing {
18032                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18033            }
18034            if was_existing && !allow_preview {
18035                pane.unpreview_item_if_preview(item.item_id());
18036            }
18037            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18038        });
18039    }
18040
18041    pub fn rename(
18042        &mut self,
18043        _: &Rename,
18044        window: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) -> Option<Task<Result<()>>> {
18047        use language::ToOffset as _;
18048
18049        let provider = self.semantics_provider.clone()?;
18050        let selection = self.selections.newest_anchor().clone();
18051        let (cursor_buffer, cursor_buffer_position) = self
18052            .buffer
18053            .read(cx)
18054            .text_anchor_for_position(selection.head(), cx)?;
18055        let (tail_buffer, cursor_buffer_position_end) = self
18056            .buffer
18057            .read(cx)
18058            .text_anchor_for_position(selection.tail(), cx)?;
18059        if tail_buffer != cursor_buffer {
18060            return None;
18061        }
18062
18063        let snapshot = cursor_buffer.read(cx).snapshot();
18064        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18065        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18066        let prepare_rename = provider
18067            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18068            .unwrap_or_else(|| Task::ready(Ok(None)));
18069        drop(snapshot);
18070
18071        Some(cx.spawn_in(window, async move |this, cx| {
18072            let rename_range = if let Some(range) = prepare_rename.await? {
18073                Some(range)
18074            } else {
18075                this.update(cx, |this, cx| {
18076                    let buffer = this.buffer.read(cx).snapshot(cx);
18077                    let mut buffer_highlights = this
18078                        .document_highlights_for_position(selection.head(), &buffer)
18079                        .filter(|highlight| {
18080                            highlight.start.excerpt_id == selection.head().excerpt_id
18081                                && highlight.end.excerpt_id == selection.head().excerpt_id
18082                        });
18083                    buffer_highlights
18084                        .next()
18085                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18086                })?
18087            };
18088            if let Some(rename_range) = rename_range {
18089                this.update_in(cx, |this, window, cx| {
18090                    let snapshot = cursor_buffer.read(cx).snapshot();
18091                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18092                    let cursor_offset_in_rename_range =
18093                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18094                    let cursor_offset_in_rename_range_end =
18095                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18096
18097                    this.take_rename(false, window, cx);
18098                    let buffer = this.buffer.read(cx).read(cx);
18099                    let cursor_offset = selection.head().to_offset(&buffer);
18100                    let rename_start =
18101                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18102                    let rename_end = rename_start + rename_buffer_range.len();
18103                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18104                    let mut old_highlight_id = None;
18105                    let old_name: Arc<str> = buffer
18106                        .chunks(rename_start..rename_end, true)
18107                        .map(|chunk| {
18108                            if old_highlight_id.is_none() {
18109                                old_highlight_id = chunk.syntax_highlight_id;
18110                            }
18111                            chunk.text
18112                        })
18113                        .collect::<String>()
18114                        .into();
18115
18116                    drop(buffer);
18117
18118                    // Position the selection in the rename editor so that it matches the current selection.
18119                    this.show_local_selections = false;
18120                    let rename_editor = cx.new(|cx| {
18121                        let mut editor = Editor::single_line(window, cx);
18122                        editor.buffer.update(cx, |buffer, cx| {
18123                            buffer.edit(
18124                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18125                                None,
18126                                cx,
18127                            )
18128                        });
18129                        let cursor_offset_in_rename_range =
18130                            MultiBufferOffset(cursor_offset_in_rename_range);
18131                        let cursor_offset_in_rename_range_end =
18132                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18133                        let rename_selection_range = match cursor_offset_in_rename_range
18134                            .cmp(&cursor_offset_in_rename_range_end)
18135                        {
18136                            Ordering::Equal => {
18137                                editor.select_all(&SelectAll, window, cx);
18138                                return editor;
18139                            }
18140                            Ordering::Less => {
18141                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18142                            }
18143                            Ordering::Greater => {
18144                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18145                            }
18146                        };
18147                        if rename_selection_range.end.0 > old_name.len() {
18148                            editor.select_all(&SelectAll, window, cx);
18149                        } else {
18150                            editor.change_selections(Default::default(), window, cx, |s| {
18151                                s.select_ranges([rename_selection_range]);
18152                            });
18153                        }
18154                        editor
18155                    });
18156                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18157                        if e == &EditorEvent::Focused {
18158                            cx.emit(EditorEvent::FocusedIn)
18159                        }
18160                    })
18161                    .detach();
18162
18163                    let write_highlights =
18164                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18165                    let read_highlights =
18166                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18167                    let ranges = write_highlights
18168                        .iter()
18169                        .flat_map(|(_, ranges)| ranges.iter())
18170                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18171                        .cloned()
18172                        .collect();
18173
18174                    this.highlight_text::<Rename>(
18175                        ranges,
18176                        HighlightStyle {
18177                            fade_out: Some(0.6),
18178                            ..Default::default()
18179                        },
18180                        cx,
18181                    );
18182                    let rename_focus_handle = rename_editor.focus_handle(cx);
18183                    window.focus(&rename_focus_handle, cx);
18184                    let block_id = this.insert_blocks(
18185                        [BlockProperties {
18186                            style: BlockStyle::Flex,
18187                            placement: BlockPlacement::Below(range.start),
18188                            height: Some(1),
18189                            render: Arc::new({
18190                                let rename_editor = rename_editor.clone();
18191                                move |cx: &mut BlockContext| {
18192                                    let mut text_style = cx.editor_style.text.clone();
18193                                    if let Some(highlight_style) = old_highlight_id
18194                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18195                                    {
18196                                        text_style = text_style.highlight(highlight_style);
18197                                    }
18198                                    div()
18199                                        .block_mouse_except_scroll()
18200                                        .pl(cx.anchor_x)
18201                                        .child(EditorElement::new(
18202                                            &rename_editor,
18203                                            EditorStyle {
18204                                                background: cx.theme().system().transparent,
18205                                                local_player: cx.editor_style.local_player,
18206                                                text: text_style,
18207                                                scrollbar_width: cx.editor_style.scrollbar_width,
18208                                                syntax: cx.editor_style.syntax.clone(),
18209                                                status: cx.editor_style.status.clone(),
18210                                                inlay_hints_style: HighlightStyle {
18211                                                    font_weight: Some(FontWeight::BOLD),
18212                                                    ..make_inlay_hints_style(cx.app)
18213                                                },
18214                                                edit_prediction_styles: make_suggestion_styles(
18215                                                    cx.app,
18216                                                ),
18217                                                ..EditorStyle::default()
18218                                            },
18219                                        ))
18220                                        .into_any_element()
18221                                }
18222                            }),
18223                            priority: 0,
18224                        }],
18225                        Some(Autoscroll::fit()),
18226                        cx,
18227                    )[0];
18228                    this.pending_rename = Some(RenameState {
18229                        range,
18230                        old_name,
18231                        editor: rename_editor,
18232                        block_id,
18233                    });
18234                })?;
18235            }
18236
18237            Ok(())
18238        }))
18239    }
18240
18241    pub fn confirm_rename(
18242        &mut self,
18243        _: &ConfirmRename,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) -> Option<Task<Result<()>>> {
18247        let rename = self.take_rename(false, window, cx)?;
18248        let workspace = self.workspace()?.downgrade();
18249        let (buffer, start) = self
18250            .buffer
18251            .read(cx)
18252            .text_anchor_for_position(rename.range.start, cx)?;
18253        let (end_buffer, _) = self
18254            .buffer
18255            .read(cx)
18256            .text_anchor_for_position(rename.range.end, cx)?;
18257        if buffer != end_buffer {
18258            return None;
18259        }
18260
18261        let old_name = rename.old_name;
18262        let new_name = rename.editor.read(cx).text(cx);
18263
18264        let rename = self.semantics_provider.as_ref()?.perform_rename(
18265            &buffer,
18266            start,
18267            new_name.clone(),
18268            cx,
18269        )?;
18270
18271        Some(cx.spawn_in(window, async move |editor, cx| {
18272            let project_transaction = rename.await?;
18273            Self::open_project_transaction(
18274                &editor,
18275                workspace,
18276                project_transaction,
18277                format!("Rename: {}{}", old_name, new_name),
18278                cx,
18279            )
18280            .await?;
18281
18282            editor.update(cx, |editor, cx| {
18283                editor.refresh_document_highlights(cx);
18284            })?;
18285            Ok(())
18286        }))
18287    }
18288
18289    fn take_rename(
18290        &mut self,
18291        moving_cursor: bool,
18292        window: &mut Window,
18293        cx: &mut Context<Self>,
18294    ) -> Option<RenameState> {
18295        let rename = self.pending_rename.take()?;
18296        if rename.editor.focus_handle(cx).is_focused(window) {
18297            window.focus(&self.focus_handle, cx);
18298        }
18299
18300        self.remove_blocks(
18301            [rename.block_id].into_iter().collect(),
18302            Some(Autoscroll::fit()),
18303            cx,
18304        );
18305        self.clear_highlights::<Rename>(cx);
18306        self.show_local_selections = true;
18307
18308        if moving_cursor {
18309            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18310                editor
18311                    .selections
18312                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18313                    .head()
18314            });
18315
18316            // Update the selection to match the position of the selection inside
18317            // the rename editor.
18318            let snapshot = self.buffer.read(cx).read(cx);
18319            let rename_range = rename.range.to_offset(&snapshot);
18320            let cursor_in_editor = snapshot
18321                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18322                .min(rename_range.end);
18323            drop(snapshot);
18324
18325            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18326                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18327            });
18328        } else {
18329            self.refresh_document_highlights(cx);
18330        }
18331
18332        Some(rename)
18333    }
18334
18335    pub fn pending_rename(&self) -> Option<&RenameState> {
18336        self.pending_rename.as_ref()
18337    }
18338
18339    fn format(
18340        &mut self,
18341        _: &Format,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Option<Task<Result<()>>> {
18345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18346
18347        let project = match &self.project {
18348            Some(project) => project.clone(),
18349            None => return None,
18350        };
18351
18352        Some(self.perform_format(
18353            project,
18354            FormatTrigger::Manual,
18355            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18356            window,
18357            cx,
18358        ))
18359    }
18360
18361    fn format_selections(
18362        &mut self,
18363        _: &FormatSelections,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) -> Option<Task<Result<()>>> {
18367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18368
18369        let project = match &self.project {
18370            Some(project) => project.clone(),
18371            None => return None,
18372        };
18373
18374        let ranges = self
18375            .selections
18376            .all_adjusted(&self.display_snapshot(cx))
18377            .into_iter()
18378            .map(|selection| selection.range())
18379            .collect_vec();
18380
18381        Some(self.perform_format(
18382            project,
18383            FormatTrigger::Manual,
18384            FormatTarget::Ranges(ranges),
18385            window,
18386            cx,
18387        ))
18388    }
18389
18390    fn perform_format(
18391        &mut self,
18392        project: Entity<Project>,
18393        trigger: FormatTrigger,
18394        target: FormatTarget,
18395        window: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) -> Task<Result<()>> {
18398        let buffer = self.buffer.clone();
18399        let (buffers, target) = match target {
18400            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18401            FormatTarget::Ranges(selection_ranges) => {
18402                let multi_buffer = buffer.read(cx);
18403                let snapshot = multi_buffer.read(cx);
18404                let mut buffers = HashSet::default();
18405                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18406                    BTreeMap::new();
18407                for selection_range in selection_ranges {
18408                    for (buffer, buffer_range, _) in
18409                        snapshot.range_to_buffer_ranges(selection_range)
18410                    {
18411                        let buffer_id = buffer.remote_id();
18412                        let start = buffer.anchor_before(buffer_range.start);
18413                        let end = buffer.anchor_after(buffer_range.end);
18414                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18415                        buffer_id_to_ranges
18416                            .entry(buffer_id)
18417                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18418                            .or_insert_with(|| vec![start..end]);
18419                    }
18420                }
18421                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18422            }
18423        };
18424
18425        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18426        let selections_prev = transaction_id_prev
18427            .and_then(|transaction_id_prev| {
18428                // default to selections as they were after the last edit, if we have them,
18429                // instead of how they are now.
18430                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18431                // will take you back to where you made the last edit, instead of staying where you scrolled
18432                self.selection_history
18433                    .transaction(transaction_id_prev)
18434                    .map(|t| t.0.clone())
18435            })
18436            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18437
18438        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18439        let format = project.update(cx, |project, cx| {
18440            project.format(buffers, target, true, trigger, cx)
18441        });
18442
18443        cx.spawn_in(window, async move |editor, cx| {
18444            let transaction = futures::select_biased! {
18445                transaction = format.log_err().fuse() => transaction,
18446                () = timeout => {
18447                    log::warn!("timed out waiting for formatting");
18448                    None
18449                }
18450            };
18451
18452            buffer.update(cx, |buffer, cx| {
18453                if let Some(transaction) = transaction
18454                    && !buffer.is_singleton()
18455                {
18456                    buffer.push_transaction(&transaction.0, cx);
18457                }
18458                cx.notify();
18459            });
18460
18461            if let Some(transaction_id_now) =
18462                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18463            {
18464                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18465                if has_new_transaction {
18466                    editor
18467                        .update(cx, |editor, _| {
18468                            editor
18469                                .selection_history
18470                                .insert_transaction(transaction_id_now, selections_prev);
18471                        })
18472                        .ok();
18473                }
18474            }
18475
18476            Ok(())
18477        })
18478    }
18479
18480    fn organize_imports(
18481        &mut self,
18482        _: &OrganizeImports,
18483        window: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) -> Option<Task<Result<()>>> {
18486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18487        let project = match &self.project {
18488            Some(project) => project.clone(),
18489            None => return None,
18490        };
18491        Some(self.perform_code_action_kind(
18492            project,
18493            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18494            window,
18495            cx,
18496        ))
18497    }
18498
18499    fn perform_code_action_kind(
18500        &mut self,
18501        project: Entity<Project>,
18502        kind: CodeActionKind,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) -> Task<Result<()>> {
18506        let buffer = self.buffer.clone();
18507        let buffers = buffer.read(cx).all_buffers();
18508        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18509        let apply_action = project.update(cx, |project, cx| {
18510            project.apply_code_action_kind(buffers, kind, true, cx)
18511        });
18512        cx.spawn_in(window, async move |_, cx| {
18513            let transaction = futures::select_biased! {
18514                () = timeout => {
18515                    log::warn!("timed out waiting for executing code action");
18516                    None
18517                }
18518                transaction = apply_action.log_err().fuse() => transaction,
18519            };
18520            buffer.update(cx, |buffer, cx| {
18521                // check if we need this
18522                if let Some(transaction) = transaction
18523                    && !buffer.is_singleton()
18524                {
18525                    buffer.push_transaction(&transaction.0, cx);
18526                }
18527                cx.notify();
18528            });
18529            Ok(())
18530        })
18531    }
18532
18533    pub fn restart_language_server(
18534        &mut self,
18535        _: &RestartLanguageServer,
18536        _: &mut Window,
18537        cx: &mut Context<Self>,
18538    ) {
18539        if let Some(project) = self.project.clone() {
18540            self.buffer.update(cx, |multi_buffer, cx| {
18541                project.update(cx, |project, cx| {
18542                    project.restart_language_servers_for_buffers(
18543                        multi_buffer.all_buffers().into_iter().collect(),
18544                        HashSet::default(),
18545                        cx,
18546                    );
18547                });
18548            })
18549        }
18550    }
18551
18552    pub fn stop_language_server(
18553        &mut self,
18554        _: &StopLanguageServer,
18555        _: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        if let Some(project) = self.project.clone() {
18559            self.buffer.update(cx, |multi_buffer, cx| {
18560                project.update(cx, |project, cx| {
18561                    project.stop_language_servers_for_buffers(
18562                        multi_buffer.all_buffers().into_iter().collect(),
18563                        HashSet::default(),
18564                        cx,
18565                    );
18566                });
18567            });
18568            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18569        }
18570    }
18571
18572    fn cancel_language_server_work(
18573        workspace: &mut Workspace,
18574        _: &actions::CancelLanguageServerWork,
18575        _: &mut Window,
18576        cx: &mut Context<Workspace>,
18577    ) {
18578        let project = workspace.project();
18579        let buffers = workspace
18580            .active_item(cx)
18581            .and_then(|item| item.act_as::<Editor>(cx))
18582            .map_or(HashSet::default(), |editor| {
18583                editor.read(cx).buffer.read(cx).all_buffers()
18584            });
18585        project.update(cx, |project, cx| {
18586            project.cancel_language_server_work_for_buffers(buffers, cx);
18587        });
18588    }
18589
18590    fn show_character_palette(
18591        &mut self,
18592        _: &ShowCharacterPalette,
18593        window: &mut Window,
18594        _: &mut Context<Self>,
18595    ) {
18596        window.show_character_palette();
18597    }
18598
18599    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18600        if !self.diagnostics_enabled() {
18601            return;
18602        }
18603
18604        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18605            let buffer = self.buffer.read(cx).snapshot(cx);
18606            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18607            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18608            let is_valid = buffer
18609                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18610                .any(|entry| {
18611                    entry.diagnostic.is_primary
18612                        && !entry.range.is_empty()
18613                        && entry.range.start == primary_range_start
18614                        && entry.diagnostic.message == active_diagnostics.active_message
18615                });
18616
18617            if !is_valid {
18618                self.dismiss_diagnostics(cx);
18619            }
18620        }
18621    }
18622
18623    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18624        match &self.active_diagnostics {
18625            ActiveDiagnostic::Group(group) => Some(group),
18626            _ => None,
18627        }
18628    }
18629
18630    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18631        if !self.diagnostics_enabled() {
18632            return;
18633        }
18634        self.dismiss_diagnostics(cx);
18635        self.active_diagnostics = ActiveDiagnostic::All;
18636    }
18637
18638    fn activate_diagnostics(
18639        &mut self,
18640        buffer_id: BufferId,
18641        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18642        window: &mut Window,
18643        cx: &mut Context<Self>,
18644    ) {
18645        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18646            return;
18647        }
18648        self.dismiss_diagnostics(cx);
18649        let snapshot = self.snapshot(window, cx);
18650        let buffer = self.buffer.read(cx).snapshot(cx);
18651        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18652            return;
18653        };
18654
18655        let diagnostic_group = buffer
18656            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18657            .collect::<Vec<_>>();
18658
18659        let language_registry = self
18660            .project()
18661            .map(|project| project.read(cx).languages().clone());
18662
18663        let blocks = renderer.render_group(
18664            diagnostic_group,
18665            buffer_id,
18666            snapshot,
18667            cx.weak_entity(),
18668            language_registry,
18669            cx,
18670        );
18671
18672        let blocks = self.display_map.update(cx, |display_map, cx| {
18673            display_map.insert_blocks(blocks, cx).into_iter().collect()
18674        });
18675        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18676            active_range: buffer.anchor_before(diagnostic.range.start)
18677                ..buffer.anchor_after(diagnostic.range.end),
18678            active_message: diagnostic.diagnostic.message.clone(),
18679            group_id: diagnostic.diagnostic.group_id,
18680            blocks,
18681        });
18682        cx.notify();
18683    }
18684
18685    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18686        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18687            return;
18688        };
18689
18690        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18691        if let ActiveDiagnostic::Group(group) = prev {
18692            self.display_map.update(cx, |display_map, cx| {
18693                display_map.remove_blocks(group.blocks, cx);
18694            });
18695            cx.notify();
18696        }
18697    }
18698
18699    /// Disable inline diagnostics rendering for this editor.
18700    pub fn disable_inline_diagnostics(&mut self) {
18701        self.inline_diagnostics_enabled = false;
18702        self.inline_diagnostics_update = Task::ready(());
18703        self.inline_diagnostics.clear();
18704    }
18705
18706    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18707        self.diagnostics_enabled = false;
18708        self.dismiss_diagnostics(cx);
18709        self.inline_diagnostics_update = Task::ready(());
18710        self.inline_diagnostics.clear();
18711    }
18712
18713    pub fn disable_word_completions(&mut self) {
18714        self.word_completions_enabled = false;
18715    }
18716
18717    pub fn diagnostics_enabled(&self) -> bool {
18718        self.diagnostics_enabled && self.mode.is_full()
18719    }
18720
18721    pub fn inline_diagnostics_enabled(&self) -> bool {
18722        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18723    }
18724
18725    pub fn show_inline_diagnostics(&self) -> bool {
18726        self.show_inline_diagnostics
18727    }
18728
18729    pub fn toggle_inline_diagnostics(
18730        &mut self,
18731        _: &ToggleInlineDiagnostics,
18732        window: &mut Window,
18733        cx: &mut Context<Editor>,
18734    ) {
18735        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18736        self.refresh_inline_diagnostics(false, window, cx);
18737    }
18738
18739    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18740        self.diagnostics_max_severity = severity;
18741        self.display_map.update(cx, |display_map, _| {
18742            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18743        });
18744    }
18745
18746    pub fn toggle_diagnostics(
18747        &mut self,
18748        _: &ToggleDiagnostics,
18749        window: &mut Window,
18750        cx: &mut Context<Editor>,
18751    ) {
18752        if !self.diagnostics_enabled() {
18753            return;
18754        }
18755
18756        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18757            EditorSettings::get_global(cx)
18758                .diagnostics_max_severity
18759                .filter(|severity| severity != &DiagnosticSeverity::Off)
18760                .unwrap_or(DiagnosticSeverity::Hint)
18761        } else {
18762            DiagnosticSeverity::Off
18763        };
18764        self.set_max_diagnostics_severity(new_severity, cx);
18765        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18766            self.active_diagnostics = ActiveDiagnostic::None;
18767            self.inline_diagnostics_update = Task::ready(());
18768            self.inline_diagnostics.clear();
18769        } else {
18770            self.refresh_inline_diagnostics(false, window, cx);
18771        }
18772
18773        cx.notify();
18774    }
18775
18776    pub fn toggle_minimap(
18777        &mut self,
18778        _: &ToggleMinimap,
18779        window: &mut Window,
18780        cx: &mut Context<Editor>,
18781    ) {
18782        if self.supports_minimap(cx) {
18783            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18784        }
18785    }
18786
18787    fn refresh_inline_diagnostics(
18788        &mut self,
18789        debounce: bool,
18790        window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) {
18793        let max_severity = ProjectSettings::get_global(cx)
18794            .diagnostics
18795            .inline
18796            .max_severity
18797            .unwrap_or(self.diagnostics_max_severity);
18798
18799        if !self.inline_diagnostics_enabled()
18800            || !self.diagnostics_enabled()
18801            || !self.show_inline_diagnostics
18802            || max_severity == DiagnosticSeverity::Off
18803        {
18804            self.inline_diagnostics_update = Task::ready(());
18805            self.inline_diagnostics.clear();
18806            return;
18807        }
18808
18809        let debounce_ms = ProjectSettings::get_global(cx)
18810            .diagnostics
18811            .inline
18812            .update_debounce_ms;
18813        let debounce = if debounce && debounce_ms > 0 {
18814            Some(Duration::from_millis(debounce_ms))
18815        } else {
18816            None
18817        };
18818        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18819            if let Some(debounce) = debounce {
18820                cx.background_executor().timer(debounce).await;
18821            }
18822            let Some(snapshot) = editor.upgrade().map(|editor| {
18823                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18824            }) else {
18825                return;
18826            };
18827
18828            let new_inline_diagnostics = cx
18829                .background_spawn(async move {
18830                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18831                    for diagnostic_entry in
18832                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18833                    {
18834                        let message = diagnostic_entry
18835                            .diagnostic
18836                            .message
18837                            .split_once('\n')
18838                            .map(|(line, _)| line)
18839                            .map(SharedString::new)
18840                            .unwrap_or_else(|| {
18841                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18842                            });
18843                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18844                        let (Ok(i) | Err(i)) = inline_diagnostics
18845                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18846                        inline_diagnostics.insert(
18847                            i,
18848                            (
18849                                start_anchor,
18850                                InlineDiagnostic {
18851                                    message,
18852                                    group_id: diagnostic_entry.diagnostic.group_id,
18853                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18854                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18855                                    severity: diagnostic_entry.diagnostic.severity,
18856                                },
18857                            ),
18858                        );
18859                    }
18860                    inline_diagnostics
18861                })
18862                .await;
18863
18864            editor
18865                .update(cx, |editor, cx| {
18866                    editor.inline_diagnostics = new_inline_diagnostics;
18867                    cx.notify();
18868                })
18869                .ok();
18870        });
18871    }
18872
18873    fn pull_diagnostics(
18874        &mut self,
18875        buffer_id: Option<BufferId>,
18876        window: &Window,
18877        cx: &mut Context<Self>,
18878    ) -> Option<()> {
18879        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18880            return None;
18881        }
18882        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18883            .diagnostics
18884            .lsp_pull_diagnostics;
18885        if !pull_diagnostics_settings.enabled {
18886            return None;
18887        }
18888        let project = self.project()?.downgrade();
18889
18890        let mut edited_buffer_ids = HashSet::default();
18891        let mut edited_worktree_ids = HashSet::default();
18892        let edited_buffers = match buffer_id {
18893            Some(buffer_id) => {
18894                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18895                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18896                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18897                edited_worktree_ids.insert(worktree_id);
18898                vec![buffer]
18899            }
18900            None => self
18901                .buffer()
18902                .read(cx)
18903                .all_buffers()
18904                .into_iter()
18905                .filter(|buffer| {
18906                    let buffer = buffer.read(cx);
18907                    match buffer.file().map(|f| f.worktree_id(cx)) {
18908                        Some(worktree_id) => {
18909                            edited_buffer_ids.insert(buffer.remote_id());
18910                            edited_worktree_ids.insert(worktree_id);
18911                            true
18912                        }
18913                        None => false,
18914                    }
18915                })
18916                .collect::<Vec<_>>(),
18917        };
18918
18919        if edited_buffers.is_empty() {
18920            self.pull_diagnostics_task = Task::ready(());
18921            self.pull_diagnostics_background_task = Task::ready(());
18922            return None;
18923        }
18924
18925        let mut already_used_buffers = HashSet::default();
18926        let related_open_buffers = self
18927            .workspace
18928            .as_ref()
18929            .and_then(|(workspace, _)| workspace.upgrade())
18930            .into_iter()
18931            .flat_map(|workspace| workspace.read(cx).panes())
18932            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18933            .filter(|editor| editor != &cx.entity())
18934            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18935            .filter(|buffer| {
18936                let buffer = buffer.read(cx);
18937                let buffer_id = buffer.remote_id();
18938                if already_used_buffers.insert(buffer_id) {
18939                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18940                        return !edited_buffer_ids.contains(&buffer_id)
18941                            && edited_worktree_ids.contains(&worktree_id);
18942                    }
18943                }
18944                false
18945            })
18946            .collect::<Vec<_>>();
18947
18948        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18949        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18950            if buffers.is_empty() {
18951                return Task::ready(());
18952            }
18953            let project_weak = project.clone();
18954            cx.spawn_in(window, async move |_, cx| {
18955                cx.background_executor().timer(delay).await;
18956
18957                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18958                    buffers
18959                        .into_iter()
18960                        .filter_map(|buffer| {
18961                            project_weak
18962                                .update(cx, |project, cx| {
18963                                    project.lsp_store().update(cx, |lsp_store, cx| {
18964                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18965                                    })
18966                                })
18967                                .ok()
18968                        })
18969                        .collect::<FuturesUnordered<_>>()
18970                }) else {
18971                    return;
18972                };
18973
18974                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18975                    if let Err(e) = pull_task {
18976                        log::error!("Failed to update project diagnostics: {e:#}");
18977                    }
18978                }
18979            })
18980        };
18981
18982        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18983        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18984
18985        Some(())
18986    }
18987
18988    pub fn set_selections_from_remote(
18989        &mut self,
18990        selections: Vec<Selection<Anchor>>,
18991        pending_selection: Option<Selection<Anchor>>,
18992        window: &mut Window,
18993        cx: &mut Context<Self>,
18994    ) {
18995        let old_cursor_position = self.selections.newest_anchor().head();
18996        self.selections
18997            .change_with(&self.display_snapshot(cx), |s| {
18998                s.select_anchors(selections);
18999                if let Some(pending_selection) = pending_selection {
19000                    s.set_pending(pending_selection, SelectMode::Character);
19001                } else {
19002                    s.clear_pending();
19003                }
19004            });
19005        self.selections_did_change(
19006            false,
19007            &old_cursor_position,
19008            SelectionEffects::default(),
19009            window,
19010            cx,
19011        );
19012    }
19013
19014    pub fn transact(
19015        &mut self,
19016        window: &mut Window,
19017        cx: &mut Context<Self>,
19018        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19019    ) -> Option<TransactionId> {
19020        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19021            this.start_transaction_at(Instant::now(), window, cx);
19022            update(this, window, cx);
19023            this.end_transaction_at(Instant::now(), cx)
19024        })
19025    }
19026
19027    pub fn start_transaction_at(
19028        &mut self,
19029        now: Instant,
19030        window: &mut Window,
19031        cx: &mut Context<Self>,
19032    ) -> Option<TransactionId> {
19033        self.end_selection(window, cx);
19034        if let Some(tx_id) = self
19035            .buffer
19036            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19037        {
19038            self.selection_history
19039                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19040            cx.emit(EditorEvent::TransactionBegun {
19041                transaction_id: tx_id,
19042            });
19043            Some(tx_id)
19044        } else {
19045            None
19046        }
19047    }
19048
19049    pub fn end_transaction_at(
19050        &mut self,
19051        now: Instant,
19052        cx: &mut Context<Self>,
19053    ) -> Option<TransactionId> {
19054        if let Some(transaction_id) = self
19055            .buffer
19056            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19057        {
19058            if let Some((_, end_selections)) =
19059                self.selection_history.transaction_mut(transaction_id)
19060            {
19061                *end_selections = Some(self.selections.disjoint_anchors_arc());
19062            } else {
19063                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19064            }
19065
19066            cx.emit(EditorEvent::Edited { transaction_id });
19067            Some(transaction_id)
19068        } else {
19069            None
19070        }
19071    }
19072
19073    pub fn modify_transaction_selection_history(
19074        &mut self,
19075        transaction_id: TransactionId,
19076        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19077    ) -> bool {
19078        self.selection_history
19079            .transaction_mut(transaction_id)
19080            .map(modify)
19081            .is_some()
19082    }
19083
19084    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19085        if self.selection_mark_mode {
19086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19087                s.move_with(|_, sel| {
19088                    sel.collapse_to(sel.head(), SelectionGoal::None);
19089                });
19090            })
19091        }
19092        self.selection_mark_mode = true;
19093        cx.notify();
19094    }
19095
19096    pub fn swap_selection_ends(
19097        &mut self,
19098        _: &actions::SwapSelectionEnds,
19099        window: &mut Window,
19100        cx: &mut Context<Self>,
19101    ) {
19102        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19103            s.move_with(|_, sel| {
19104                if sel.start != sel.end {
19105                    sel.reversed = !sel.reversed
19106                }
19107            });
19108        });
19109        self.request_autoscroll(Autoscroll::newest(), cx);
19110        cx.notify();
19111    }
19112
19113    pub fn toggle_focus(
19114        workspace: &mut Workspace,
19115        _: &actions::ToggleFocus,
19116        window: &mut Window,
19117        cx: &mut Context<Workspace>,
19118    ) {
19119        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19120            return;
19121        };
19122        workspace.activate_item(&item, true, true, window, cx);
19123    }
19124
19125    pub fn toggle_fold(
19126        &mut self,
19127        _: &actions::ToggleFold,
19128        window: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19132            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19133            let selection = self.selections.newest::<Point>(&display_map);
19134
19135            let range = if selection.is_empty() {
19136                let point = selection.head().to_display_point(&display_map);
19137                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19138                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19139                    .to_point(&display_map);
19140                start..end
19141            } else {
19142                selection.range()
19143            };
19144            if display_map.folds_in_range(range).next().is_some() {
19145                self.unfold_lines(&Default::default(), window, cx)
19146            } else {
19147                self.fold(&Default::default(), window, cx)
19148            }
19149        } else {
19150            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19151            let buffer_ids: HashSet<_> = self
19152                .selections
19153                .disjoint_anchor_ranges()
19154                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19155                .collect();
19156
19157            let should_unfold = buffer_ids
19158                .iter()
19159                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19160
19161            for buffer_id in buffer_ids {
19162                if should_unfold {
19163                    self.unfold_buffer(buffer_id, cx);
19164                } else {
19165                    self.fold_buffer(buffer_id, cx);
19166                }
19167            }
19168        }
19169    }
19170
19171    pub fn toggle_fold_recursive(
19172        &mut self,
19173        _: &actions::ToggleFoldRecursive,
19174        window: &mut Window,
19175        cx: &mut Context<Self>,
19176    ) {
19177        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19178
19179        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19180        let range = if selection.is_empty() {
19181            let point = selection.head().to_display_point(&display_map);
19182            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19183            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19184                .to_point(&display_map);
19185            start..end
19186        } else {
19187            selection.range()
19188        };
19189        if display_map.folds_in_range(range).next().is_some() {
19190            self.unfold_recursive(&Default::default(), window, cx)
19191        } else {
19192            self.fold_recursive(&Default::default(), window, cx)
19193        }
19194    }
19195
19196    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19197        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19198            let mut to_fold = Vec::new();
19199            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19200            let selections = self.selections.all_adjusted(&display_map);
19201
19202            for selection in selections {
19203                let range = selection.range().sorted();
19204                let buffer_start_row = range.start.row;
19205
19206                if range.start.row != range.end.row {
19207                    let mut found = false;
19208                    let mut row = range.start.row;
19209                    while row <= range.end.row {
19210                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19211                        {
19212                            found = true;
19213                            row = crease.range().end.row + 1;
19214                            to_fold.push(crease);
19215                        } else {
19216                            row += 1
19217                        }
19218                    }
19219                    if found {
19220                        continue;
19221                    }
19222                }
19223
19224                for row in (0..=range.start.row).rev() {
19225                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19226                        && crease.range().end.row >= buffer_start_row
19227                    {
19228                        to_fold.push(crease);
19229                        if row <= range.start.row {
19230                            break;
19231                        }
19232                    }
19233                }
19234            }
19235
19236            self.fold_creases(to_fold, true, window, cx);
19237        } else {
19238            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19239            let buffer_ids = self
19240                .selections
19241                .disjoint_anchor_ranges()
19242                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19243                .collect::<HashSet<_>>();
19244            for buffer_id in buffer_ids {
19245                self.fold_buffer(buffer_id, cx);
19246            }
19247        }
19248    }
19249
19250    pub fn toggle_fold_all(
19251        &mut self,
19252        _: &actions::ToggleFoldAll,
19253        window: &mut Window,
19254        cx: &mut Context<Self>,
19255    ) {
19256        let has_folds = if self.buffer.read(cx).is_singleton() {
19257            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19258            let has_folds = display_map
19259                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19260                .next()
19261                .is_some();
19262            has_folds
19263        } else {
19264            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19265            let has_folds = buffer_ids
19266                .iter()
19267                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19268            has_folds
19269        };
19270
19271        if has_folds {
19272            self.unfold_all(&actions::UnfoldAll, window, cx);
19273        } else {
19274            self.fold_all(&actions::FoldAll, window, cx);
19275        }
19276    }
19277
19278    fn fold_at_level(
19279        &mut self,
19280        fold_at: &FoldAtLevel,
19281        window: &mut Window,
19282        cx: &mut Context<Self>,
19283    ) {
19284        if !self.buffer.read(cx).is_singleton() {
19285            return;
19286        }
19287
19288        let fold_at_level = fold_at.0;
19289        let snapshot = self.buffer.read(cx).snapshot(cx);
19290        let mut to_fold = Vec::new();
19291        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19292
19293        let row_ranges_to_keep: Vec<Range<u32>> = self
19294            .selections
19295            .all::<Point>(&self.display_snapshot(cx))
19296            .into_iter()
19297            .map(|sel| sel.start.row..sel.end.row)
19298            .collect();
19299
19300        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19301            while start_row < end_row {
19302                match self
19303                    .snapshot(window, cx)
19304                    .crease_for_buffer_row(MultiBufferRow(start_row))
19305                {
19306                    Some(crease) => {
19307                        let nested_start_row = crease.range().start.row + 1;
19308                        let nested_end_row = crease.range().end.row;
19309
19310                        if current_level < fold_at_level {
19311                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19312                        } else if current_level == fold_at_level {
19313                            // Fold iff there is no selection completely contained within the fold region
19314                            if !row_ranges_to_keep.iter().any(|selection| {
19315                                selection.end >= nested_start_row
19316                                    && selection.start <= nested_end_row
19317                            }) {
19318                                to_fold.push(crease);
19319                            }
19320                        }
19321
19322                        start_row = nested_end_row + 1;
19323                    }
19324                    None => start_row += 1,
19325                }
19326            }
19327        }
19328
19329        self.fold_creases(to_fold, true, window, cx);
19330    }
19331
19332    pub fn fold_at_level_1(
19333        &mut self,
19334        _: &actions::FoldAtLevel1,
19335        window: &mut Window,
19336        cx: &mut Context<Self>,
19337    ) {
19338        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19339    }
19340
19341    pub fn fold_at_level_2(
19342        &mut self,
19343        _: &actions::FoldAtLevel2,
19344        window: &mut Window,
19345        cx: &mut Context<Self>,
19346    ) {
19347        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19348    }
19349
19350    pub fn fold_at_level_3(
19351        &mut self,
19352        _: &actions::FoldAtLevel3,
19353        window: &mut Window,
19354        cx: &mut Context<Self>,
19355    ) {
19356        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19357    }
19358
19359    pub fn fold_at_level_4(
19360        &mut self,
19361        _: &actions::FoldAtLevel4,
19362        window: &mut Window,
19363        cx: &mut Context<Self>,
19364    ) {
19365        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19366    }
19367
19368    pub fn fold_at_level_5(
19369        &mut self,
19370        _: &actions::FoldAtLevel5,
19371        window: &mut Window,
19372        cx: &mut Context<Self>,
19373    ) {
19374        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19375    }
19376
19377    pub fn fold_at_level_6(
19378        &mut self,
19379        _: &actions::FoldAtLevel6,
19380        window: &mut Window,
19381        cx: &mut Context<Self>,
19382    ) {
19383        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19384    }
19385
19386    pub fn fold_at_level_7(
19387        &mut self,
19388        _: &actions::FoldAtLevel7,
19389        window: &mut Window,
19390        cx: &mut Context<Self>,
19391    ) {
19392        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19393    }
19394
19395    pub fn fold_at_level_8(
19396        &mut self,
19397        _: &actions::FoldAtLevel8,
19398        window: &mut Window,
19399        cx: &mut Context<Self>,
19400    ) {
19401        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19402    }
19403
19404    pub fn fold_at_level_9(
19405        &mut self,
19406        _: &actions::FoldAtLevel9,
19407        window: &mut Window,
19408        cx: &mut Context<Self>,
19409    ) {
19410        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19411    }
19412
19413    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19414        if self.buffer.read(cx).is_singleton() {
19415            let mut fold_ranges = Vec::new();
19416            let snapshot = self.buffer.read(cx).snapshot(cx);
19417
19418            for row in 0..snapshot.max_row().0 {
19419                if let Some(foldable_range) = self
19420                    .snapshot(window, cx)
19421                    .crease_for_buffer_row(MultiBufferRow(row))
19422                {
19423                    fold_ranges.push(foldable_range);
19424                }
19425            }
19426
19427            self.fold_creases(fold_ranges, true, window, cx);
19428        } else {
19429            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19430                editor
19431                    .update_in(cx, |editor, _, cx| {
19432                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19433                            editor.fold_buffer(buffer_id, cx);
19434                        }
19435                    })
19436                    .ok();
19437            });
19438        }
19439        cx.emit(SearchEvent::ResultsCollapsedChanged(
19440            CollapseDirection::Collapsed,
19441        ));
19442    }
19443
19444    pub fn fold_function_bodies(
19445        &mut self,
19446        _: &actions::FoldFunctionBodies,
19447        window: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        let snapshot = self.buffer.read(cx).snapshot(cx);
19451
19452        let ranges = snapshot
19453            .text_object_ranges(
19454                MultiBufferOffset(0)..snapshot.len(),
19455                TreeSitterOptions::default(),
19456            )
19457            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19458            .collect::<Vec<_>>();
19459
19460        let creases = ranges
19461            .into_iter()
19462            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19463            .collect();
19464
19465        self.fold_creases(creases, true, window, cx);
19466    }
19467
19468    pub fn fold_recursive(
19469        &mut self,
19470        _: &actions::FoldRecursive,
19471        window: &mut Window,
19472        cx: &mut Context<Self>,
19473    ) {
19474        let mut to_fold = Vec::new();
19475        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19476        let selections = self.selections.all_adjusted(&display_map);
19477
19478        for selection in selections {
19479            let range = selection.range().sorted();
19480            let buffer_start_row = range.start.row;
19481
19482            if range.start.row != range.end.row {
19483                let mut found = false;
19484                for row in range.start.row..=range.end.row {
19485                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19486                        found = true;
19487                        to_fold.push(crease);
19488                    }
19489                }
19490                if found {
19491                    continue;
19492                }
19493            }
19494
19495            for row in (0..=range.start.row).rev() {
19496                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19497                    if crease.range().end.row >= buffer_start_row {
19498                        to_fold.push(crease);
19499                    } else {
19500                        break;
19501                    }
19502                }
19503            }
19504        }
19505
19506        self.fold_creases(to_fold, true, window, cx);
19507    }
19508
19509    pub fn fold_at(
19510        &mut self,
19511        buffer_row: MultiBufferRow,
19512        window: &mut Window,
19513        cx: &mut Context<Self>,
19514    ) {
19515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19516
19517        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19518            let autoscroll = self
19519                .selections
19520                .all::<Point>(&display_map)
19521                .iter()
19522                .any(|selection| crease.range().overlaps(&selection.range()));
19523
19524            self.fold_creases(vec![crease], autoscroll, window, cx);
19525        }
19526    }
19527
19528    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19529        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19530            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19531            let buffer = display_map.buffer_snapshot();
19532            let selections = self.selections.all::<Point>(&display_map);
19533            let ranges = selections
19534                .iter()
19535                .map(|s| {
19536                    let range = s.display_range(&display_map).sorted();
19537                    let mut start = range.start.to_point(&display_map);
19538                    let mut end = range.end.to_point(&display_map);
19539                    start.column = 0;
19540                    end.column = buffer.line_len(MultiBufferRow(end.row));
19541                    start..end
19542                })
19543                .collect::<Vec<_>>();
19544
19545            self.unfold_ranges(&ranges, true, true, cx);
19546        } else {
19547            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19548            let buffer_ids = self
19549                .selections
19550                .disjoint_anchor_ranges()
19551                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19552                .collect::<HashSet<_>>();
19553            for buffer_id in buffer_ids {
19554                self.unfold_buffer(buffer_id, cx);
19555            }
19556        }
19557    }
19558
19559    pub fn unfold_recursive(
19560        &mut self,
19561        _: &UnfoldRecursive,
19562        _window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) {
19565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19566        let selections = self.selections.all::<Point>(&display_map);
19567        let ranges = selections
19568            .iter()
19569            .map(|s| {
19570                let mut range = s.display_range(&display_map).sorted();
19571                *range.start.column_mut() = 0;
19572                *range.end.column_mut() = display_map.line_len(range.end.row());
19573                let start = range.start.to_point(&display_map);
19574                let end = range.end.to_point(&display_map);
19575                start..end
19576            })
19577            .collect::<Vec<_>>();
19578
19579        self.unfold_ranges(&ranges, true, true, cx);
19580    }
19581
19582    pub fn unfold_at(
19583        &mut self,
19584        buffer_row: MultiBufferRow,
19585        _window: &mut Window,
19586        cx: &mut Context<Self>,
19587    ) {
19588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19589
19590        let intersection_range = Point::new(buffer_row.0, 0)
19591            ..Point::new(
19592                buffer_row.0,
19593                display_map.buffer_snapshot().line_len(buffer_row),
19594            );
19595
19596        let autoscroll = self
19597            .selections
19598            .all::<Point>(&display_map)
19599            .iter()
19600            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19601
19602        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19603    }
19604
19605    pub fn unfold_all(
19606        &mut self,
19607        _: &actions::UnfoldAll,
19608        _window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        if self.buffer.read(cx).is_singleton() {
19612            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19613            self.unfold_ranges(
19614                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19615                true,
19616                true,
19617                cx,
19618            );
19619        } else {
19620            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19621                editor
19622                    .update(cx, |editor, cx| {
19623                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19624                            editor.unfold_buffer(buffer_id, cx);
19625                        }
19626                    })
19627                    .ok();
19628            });
19629        }
19630        cx.emit(SearchEvent::ResultsCollapsedChanged(
19631            CollapseDirection::Expanded,
19632        ));
19633    }
19634
19635    pub fn fold_selected_ranges(
19636        &mut self,
19637        _: &FoldSelectedRanges,
19638        window: &mut Window,
19639        cx: &mut Context<Self>,
19640    ) {
19641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19642        let selections = self.selections.all_adjusted(&display_map);
19643        let ranges = selections
19644            .into_iter()
19645            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19646            .collect::<Vec<_>>();
19647        self.fold_creases(ranges, true, window, cx);
19648    }
19649
19650    pub fn fold_ranges<T: ToOffset + Clone>(
19651        &mut self,
19652        ranges: Vec<Range<T>>,
19653        auto_scroll: bool,
19654        window: &mut Window,
19655        cx: &mut Context<Self>,
19656    ) {
19657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19658        let ranges = ranges
19659            .into_iter()
19660            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19661            .collect::<Vec<_>>();
19662        self.fold_creases(ranges, auto_scroll, window, cx);
19663    }
19664
19665    pub fn fold_creases<T: ToOffset + Clone>(
19666        &mut self,
19667        creases: Vec<Crease<T>>,
19668        auto_scroll: bool,
19669        _window: &mut Window,
19670        cx: &mut Context<Self>,
19671    ) {
19672        if creases.is_empty() {
19673            return;
19674        }
19675
19676        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19677
19678        if auto_scroll {
19679            self.request_autoscroll(Autoscroll::fit(), cx);
19680        }
19681
19682        cx.notify();
19683
19684        self.scrollbar_marker_state.dirty = true;
19685        self.folds_did_change(cx);
19686    }
19687
19688    /// Removes any folds whose ranges intersect any of the given ranges.
19689    pub fn unfold_ranges<T: ToOffset + Clone>(
19690        &mut self,
19691        ranges: &[Range<T>],
19692        inclusive: bool,
19693        auto_scroll: bool,
19694        cx: &mut Context<Self>,
19695    ) {
19696        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19697            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19698        });
19699        self.folds_did_change(cx);
19700    }
19701
19702    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19703        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19704            return;
19705        }
19706
19707        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19708        self.display_map.update(cx, |display_map, cx| {
19709            display_map.fold_buffers([buffer_id], cx)
19710        });
19711
19712        let snapshot = self.display_snapshot(cx);
19713        self.selections.change_with(&snapshot, |selections| {
19714            selections.remove_selections_from_buffer(buffer_id);
19715        });
19716
19717        cx.emit(EditorEvent::BufferFoldToggled {
19718            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19719            folded: true,
19720        });
19721        cx.notify();
19722    }
19723
19724    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19725        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19726            return;
19727        }
19728        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19729        self.display_map.update(cx, |display_map, cx| {
19730            display_map.unfold_buffers([buffer_id], cx);
19731        });
19732        cx.emit(EditorEvent::BufferFoldToggled {
19733            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19734            folded: false,
19735        });
19736        cx.notify();
19737    }
19738
19739    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19740        self.display_map.read(cx).is_buffer_folded(buffer)
19741    }
19742
19743    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19744        self.display_map.read(cx).folded_buffers()
19745    }
19746
19747    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19748        self.display_map.update(cx, |display_map, cx| {
19749            display_map.disable_header_for_buffer(buffer_id, cx);
19750        });
19751        cx.notify();
19752    }
19753
19754    /// Removes any folds with the given ranges.
19755    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19756        &mut self,
19757        ranges: &[Range<T>],
19758        type_id: TypeId,
19759        auto_scroll: bool,
19760        cx: &mut Context<Self>,
19761    ) {
19762        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19763            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19764        });
19765        self.folds_did_change(cx);
19766    }
19767
19768    fn remove_folds_with<T: ToOffset + Clone>(
19769        &mut self,
19770        ranges: &[Range<T>],
19771        auto_scroll: bool,
19772        cx: &mut Context<Self>,
19773        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19774    ) {
19775        if ranges.is_empty() {
19776            return;
19777        }
19778
19779        let mut buffers_affected = HashSet::default();
19780        let multi_buffer = self.buffer().read(cx);
19781        for range in ranges {
19782            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19783                buffers_affected.insert(buffer.read(cx).remote_id());
19784            };
19785        }
19786
19787        self.display_map.update(cx, update);
19788
19789        if auto_scroll {
19790            self.request_autoscroll(Autoscroll::fit(), cx);
19791        }
19792
19793        cx.notify();
19794        self.scrollbar_marker_state.dirty = true;
19795        self.active_indent_guides_state.dirty = true;
19796    }
19797
19798    pub fn update_renderer_widths(
19799        &mut self,
19800        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19801        cx: &mut Context<Self>,
19802    ) -> bool {
19803        self.display_map
19804            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19805    }
19806
19807    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19808        self.display_map.read(cx).fold_placeholder.clone()
19809    }
19810
19811    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19812        self.buffer.update(cx, |buffer, cx| {
19813            buffer.set_all_diff_hunks_expanded(cx);
19814        });
19815    }
19816
19817    pub fn expand_all_diff_hunks(
19818        &mut self,
19819        _: &ExpandAllDiffHunks,
19820        _window: &mut Window,
19821        cx: &mut Context<Self>,
19822    ) {
19823        self.buffer.update(cx, |buffer, cx| {
19824            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19825        });
19826    }
19827
19828    pub fn collapse_all_diff_hunks(
19829        &mut self,
19830        _: &CollapseAllDiffHunks,
19831        _window: &mut Window,
19832        cx: &mut Context<Self>,
19833    ) {
19834        self.buffer.update(cx, |buffer, cx| {
19835            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19836        });
19837    }
19838
19839    pub fn toggle_selected_diff_hunks(
19840        &mut self,
19841        _: &ToggleSelectedDiffHunks,
19842        _window: &mut Window,
19843        cx: &mut Context<Self>,
19844    ) {
19845        let ranges: Vec<_> = self
19846            .selections
19847            .disjoint_anchors()
19848            .iter()
19849            .map(|s| s.range())
19850            .collect();
19851        self.toggle_diff_hunks_in_ranges(ranges, cx);
19852    }
19853
19854    pub fn diff_hunks_in_ranges<'a>(
19855        &'a self,
19856        ranges: &'a [Range<Anchor>],
19857        buffer: &'a MultiBufferSnapshot,
19858    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19859        ranges.iter().flat_map(move |range| {
19860            let end_excerpt_id = range.end.excerpt_id;
19861            let range = range.to_point(buffer);
19862            let mut peek_end = range.end;
19863            if range.end.row < buffer.max_row().0 {
19864                peek_end = Point::new(range.end.row + 1, 0);
19865            }
19866            buffer
19867                .diff_hunks_in_range(range.start..peek_end)
19868                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19869        })
19870    }
19871
19872    pub fn has_stageable_diff_hunks_in_ranges(
19873        &self,
19874        ranges: &[Range<Anchor>],
19875        snapshot: &MultiBufferSnapshot,
19876    ) -> bool {
19877        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19878        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19879    }
19880
19881    pub fn toggle_staged_selected_diff_hunks(
19882        &mut self,
19883        _: &::git::ToggleStaged,
19884        _: &mut Window,
19885        cx: &mut Context<Self>,
19886    ) {
19887        let snapshot = self.buffer.read(cx).snapshot(cx);
19888        let ranges: Vec<_> = self
19889            .selections
19890            .disjoint_anchors()
19891            .iter()
19892            .map(|s| s.range())
19893            .collect();
19894        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19895        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19896    }
19897
19898    pub fn set_render_diff_hunk_controls(
19899        &mut self,
19900        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19901        cx: &mut Context<Self>,
19902    ) {
19903        self.render_diff_hunk_controls = render_diff_hunk_controls;
19904        cx.notify();
19905    }
19906
19907    pub fn stage_and_next(
19908        &mut self,
19909        _: &::git::StageAndNext,
19910        window: &mut Window,
19911        cx: &mut Context<Self>,
19912    ) {
19913        self.do_stage_or_unstage_and_next(true, window, cx);
19914    }
19915
19916    pub fn unstage_and_next(
19917        &mut self,
19918        _: &::git::UnstageAndNext,
19919        window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        self.do_stage_or_unstage_and_next(false, window, cx);
19923    }
19924
19925    pub fn stage_or_unstage_diff_hunks(
19926        &mut self,
19927        stage: bool,
19928        ranges: Vec<Range<Anchor>>,
19929        cx: &mut Context<Self>,
19930    ) {
19931        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19932        cx.spawn(async move |this, cx| {
19933            task.await?;
19934            this.update(cx, |this, cx| {
19935                let snapshot = this.buffer.read(cx).snapshot(cx);
19936                let chunk_by = this
19937                    .diff_hunks_in_ranges(&ranges, &snapshot)
19938                    .chunk_by(|hunk| hunk.buffer_id);
19939                for (buffer_id, hunks) in &chunk_by {
19940                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19941                }
19942            })
19943        })
19944        .detach_and_log_err(cx);
19945    }
19946
19947    fn save_buffers_for_ranges_if_needed(
19948        &mut self,
19949        ranges: &[Range<Anchor>],
19950        cx: &mut Context<Editor>,
19951    ) -> Task<Result<()>> {
19952        let multibuffer = self.buffer.read(cx);
19953        let snapshot = multibuffer.read(cx);
19954        let buffer_ids: HashSet<_> = ranges
19955            .iter()
19956            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19957            .collect();
19958        drop(snapshot);
19959
19960        let mut buffers = HashSet::default();
19961        for buffer_id in buffer_ids {
19962            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19963                let buffer = buffer_entity.read(cx);
19964                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19965                {
19966                    buffers.insert(buffer_entity);
19967                }
19968            }
19969        }
19970
19971        if let Some(project) = &self.project {
19972            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19973        } else {
19974            Task::ready(Ok(()))
19975        }
19976    }
19977
19978    fn do_stage_or_unstage_and_next(
19979        &mut self,
19980        stage: bool,
19981        window: &mut Window,
19982        cx: &mut Context<Self>,
19983    ) {
19984        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19985
19986        if ranges.iter().any(|range| range.start != range.end) {
19987            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19988            return;
19989        }
19990
19991        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19992        let snapshot = self.snapshot(window, cx);
19993        let position = self
19994            .selections
19995            .newest::<Point>(&snapshot.display_snapshot)
19996            .head();
19997        let mut row = snapshot
19998            .buffer_snapshot()
19999            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20000            .find(|hunk| hunk.row_range.start.0 > position.row)
20001            .map(|hunk| hunk.row_range.start);
20002
20003        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20004        // Outside of the project diff editor, wrap around to the beginning.
20005        if !all_diff_hunks_expanded {
20006            row = row.or_else(|| {
20007                snapshot
20008                    .buffer_snapshot()
20009                    .diff_hunks_in_range(Point::zero()..position)
20010                    .find(|hunk| hunk.row_range.end.0 < position.row)
20011                    .map(|hunk| hunk.row_range.start)
20012            });
20013        }
20014
20015        if let Some(row) = row {
20016            let destination = Point::new(row.0, 0);
20017            let autoscroll = Autoscroll::center();
20018
20019            self.unfold_ranges(&[destination..destination], false, false, cx);
20020            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20021                s.select_ranges([destination..destination]);
20022            });
20023        }
20024    }
20025
20026    fn do_stage_or_unstage(
20027        &self,
20028        stage: bool,
20029        buffer_id: BufferId,
20030        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20031        cx: &mut App,
20032    ) -> Option<()> {
20033        let project = self.project()?;
20034        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20035        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20036        let buffer_snapshot = buffer.read(cx).snapshot();
20037        let file_exists = buffer_snapshot
20038            .file()
20039            .is_some_and(|file| file.disk_state().exists());
20040        diff.update(cx, |diff, cx| {
20041            diff.stage_or_unstage_hunks(
20042                stage,
20043                &hunks
20044                    .map(|hunk| buffer_diff::DiffHunk {
20045                        buffer_range: hunk.buffer_range,
20046                        // We don't need to pass in word diffs here because they're only used for rendering and
20047                        // this function changes internal state
20048                        base_word_diffs: Vec::default(),
20049                        buffer_word_diffs: Vec::default(),
20050                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20051                            ..hunk.diff_base_byte_range.end.0,
20052                        secondary_status: hunk.status.secondary,
20053                        range: Point::zero()..Point::zero(), // unused
20054                    })
20055                    .collect::<Vec<_>>(),
20056                &buffer_snapshot,
20057                file_exists,
20058                cx,
20059            )
20060        });
20061        None
20062    }
20063
20064    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20065        let ranges: Vec<_> = self
20066            .selections
20067            .disjoint_anchors()
20068            .iter()
20069            .map(|s| s.range())
20070            .collect();
20071        self.buffer
20072            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20073    }
20074
20075    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20076        self.buffer.update(cx, |buffer, cx| {
20077            let ranges = vec![Anchor::min()..Anchor::max()];
20078            if !buffer.all_diff_hunks_expanded()
20079                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20080            {
20081                buffer.collapse_diff_hunks(ranges, cx);
20082                true
20083            } else {
20084                false
20085            }
20086        })
20087    }
20088
20089    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20090        if self.buffer.read(cx).all_diff_hunks_expanded() {
20091            return true;
20092        }
20093        let ranges = vec![Anchor::min()..Anchor::max()];
20094        self.buffer
20095            .read(cx)
20096            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20097    }
20098
20099    fn toggle_diff_hunks_in_ranges(
20100        &mut self,
20101        ranges: Vec<Range<Anchor>>,
20102        cx: &mut Context<Editor>,
20103    ) {
20104        self.buffer.update(cx, |buffer, cx| {
20105            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20106            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20107        })
20108    }
20109
20110    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20111        self.buffer.update(cx, |buffer, cx| {
20112            let snapshot = buffer.snapshot(cx);
20113            let excerpt_id = range.end.excerpt_id;
20114            let point_range = range.to_point(&snapshot);
20115            let expand = !buffer.single_hunk_is_expanded(range, cx);
20116            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20117        })
20118    }
20119
20120    pub(crate) fn apply_all_diff_hunks(
20121        &mut self,
20122        _: &ApplyAllDiffHunks,
20123        window: &mut Window,
20124        cx: &mut Context<Self>,
20125    ) {
20126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20127
20128        let buffers = self.buffer.read(cx).all_buffers();
20129        for branch_buffer in buffers {
20130            branch_buffer.update(cx, |branch_buffer, cx| {
20131                branch_buffer.merge_into_base(Vec::new(), cx);
20132            });
20133        }
20134
20135        if let Some(project) = self.project.clone() {
20136            self.save(
20137                SaveOptions {
20138                    format: true,
20139                    autosave: false,
20140                },
20141                project,
20142                window,
20143                cx,
20144            )
20145            .detach_and_log_err(cx);
20146        }
20147    }
20148
20149    pub(crate) fn apply_selected_diff_hunks(
20150        &mut self,
20151        _: &ApplyDiffHunk,
20152        window: &mut Window,
20153        cx: &mut Context<Self>,
20154    ) {
20155        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20156        let snapshot = self.snapshot(window, cx);
20157        let hunks = snapshot.hunks_for_ranges(
20158            self.selections
20159                .all(&snapshot.display_snapshot)
20160                .into_iter()
20161                .map(|selection| selection.range()),
20162        );
20163        let mut ranges_by_buffer = HashMap::default();
20164        self.transact(window, cx, |editor, _window, cx| {
20165            for hunk in hunks {
20166                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20167                    ranges_by_buffer
20168                        .entry(buffer.clone())
20169                        .or_insert_with(Vec::new)
20170                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20171                }
20172            }
20173
20174            for (buffer, ranges) in ranges_by_buffer {
20175                buffer.update(cx, |buffer, cx| {
20176                    buffer.merge_into_base(ranges, cx);
20177                });
20178            }
20179        });
20180
20181        if let Some(project) = self.project.clone() {
20182            self.save(
20183                SaveOptions {
20184                    format: true,
20185                    autosave: false,
20186                },
20187                project,
20188                window,
20189                cx,
20190            )
20191            .detach_and_log_err(cx);
20192        }
20193    }
20194
20195    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20196        if hovered != self.gutter_hovered {
20197            self.gutter_hovered = hovered;
20198            cx.notify();
20199        }
20200    }
20201
20202    pub fn insert_blocks(
20203        &mut self,
20204        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20205        autoscroll: Option<Autoscroll>,
20206        cx: &mut Context<Self>,
20207    ) -> Vec<CustomBlockId> {
20208        let blocks = self
20209            .display_map
20210            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20211        if let Some(autoscroll) = autoscroll {
20212            self.request_autoscroll(autoscroll, cx);
20213        }
20214        cx.notify();
20215        blocks
20216    }
20217
20218    pub fn resize_blocks(
20219        &mut self,
20220        heights: HashMap<CustomBlockId, u32>,
20221        autoscroll: Option<Autoscroll>,
20222        cx: &mut Context<Self>,
20223    ) {
20224        self.display_map
20225            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20226        if let Some(autoscroll) = autoscroll {
20227            self.request_autoscroll(autoscroll, cx);
20228        }
20229        cx.notify();
20230    }
20231
20232    pub fn replace_blocks(
20233        &mut self,
20234        renderers: HashMap<CustomBlockId, RenderBlock>,
20235        autoscroll: Option<Autoscroll>,
20236        cx: &mut Context<Self>,
20237    ) {
20238        self.display_map
20239            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20240        if let Some(autoscroll) = autoscroll {
20241            self.request_autoscroll(autoscroll, cx);
20242        }
20243        cx.notify();
20244    }
20245
20246    pub fn remove_blocks(
20247        &mut self,
20248        block_ids: HashSet<CustomBlockId>,
20249        autoscroll: Option<Autoscroll>,
20250        cx: &mut Context<Self>,
20251    ) {
20252        self.display_map.update(cx, |display_map, cx| {
20253            display_map.remove_blocks(block_ids, cx)
20254        });
20255        if let Some(autoscroll) = autoscroll {
20256            self.request_autoscroll(autoscroll, cx);
20257        }
20258        cx.notify();
20259    }
20260
20261    pub fn row_for_block(
20262        &self,
20263        block_id: CustomBlockId,
20264        cx: &mut Context<Self>,
20265    ) -> Option<DisplayRow> {
20266        self.display_map
20267            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20268    }
20269
20270    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20271        self.focused_block = Some(focused_block);
20272    }
20273
20274    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20275        self.focused_block.take()
20276    }
20277
20278    pub fn insert_creases(
20279        &mut self,
20280        creases: impl IntoIterator<Item = Crease<Anchor>>,
20281        cx: &mut Context<Self>,
20282    ) -> Vec<CreaseId> {
20283        self.display_map
20284            .update(cx, |map, cx| map.insert_creases(creases, cx))
20285    }
20286
20287    pub fn remove_creases(
20288        &mut self,
20289        ids: impl IntoIterator<Item = CreaseId>,
20290        cx: &mut Context<Self>,
20291    ) -> Vec<(CreaseId, Range<Anchor>)> {
20292        self.display_map
20293            .update(cx, |map, cx| map.remove_creases(ids, cx))
20294    }
20295
20296    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20297        self.display_map
20298            .update(cx, |map, cx| map.snapshot(cx))
20299            .longest_row()
20300    }
20301
20302    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20303        self.display_map
20304            .update(cx, |map, cx| map.snapshot(cx))
20305            .max_point()
20306    }
20307
20308    pub fn text(&self, cx: &App) -> String {
20309        self.buffer.read(cx).read(cx).text()
20310    }
20311
20312    pub fn is_empty(&self, cx: &App) -> bool {
20313        self.buffer.read(cx).read(cx).is_empty()
20314    }
20315
20316    pub fn text_option(&self, cx: &App) -> Option<String> {
20317        let text = self.text(cx);
20318        let text = text.trim();
20319
20320        if text.is_empty() {
20321            return None;
20322        }
20323
20324        Some(text.to_string())
20325    }
20326
20327    pub fn set_text(
20328        &mut self,
20329        text: impl Into<Arc<str>>,
20330        window: &mut Window,
20331        cx: &mut Context<Self>,
20332    ) {
20333        self.transact(window, cx, |this, _, cx| {
20334            this.buffer
20335                .read(cx)
20336                .as_singleton()
20337                .expect("you can only call set_text on editors for singleton buffers")
20338                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20339        });
20340    }
20341
20342    pub fn display_text(&self, cx: &mut App) -> String {
20343        self.display_map
20344            .update(cx, |map, cx| map.snapshot(cx))
20345            .text()
20346    }
20347
20348    fn create_minimap(
20349        &self,
20350        minimap_settings: MinimapSettings,
20351        window: &mut Window,
20352        cx: &mut Context<Self>,
20353    ) -> Option<Entity<Self>> {
20354        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20355            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20356    }
20357
20358    fn initialize_new_minimap(
20359        &self,
20360        minimap_settings: MinimapSettings,
20361        window: &mut Window,
20362        cx: &mut Context<Self>,
20363    ) -> Entity<Self> {
20364        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20365        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20366
20367        let mut minimap = Editor::new_internal(
20368            EditorMode::Minimap {
20369                parent: cx.weak_entity(),
20370            },
20371            self.buffer.clone(),
20372            None,
20373            Some(self.display_map.clone()),
20374            window,
20375            cx,
20376        );
20377        minimap.scroll_manager.clone_state(&self.scroll_manager);
20378        minimap.set_text_style_refinement(TextStyleRefinement {
20379            font_size: Some(MINIMAP_FONT_SIZE),
20380            font_weight: Some(MINIMAP_FONT_WEIGHT),
20381            font_family: Some(MINIMAP_FONT_FAMILY),
20382            ..Default::default()
20383        });
20384        minimap.update_minimap_configuration(minimap_settings, cx);
20385        cx.new(|_| minimap)
20386    }
20387
20388    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20389        let current_line_highlight = minimap_settings
20390            .current_line_highlight
20391            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20392        self.set_current_line_highlight(Some(current_line_highlight));
20393    }
20394
20395    pub fn minimap(&self) -> Option<&Entity<Self>> {
20396        self.minimap
20397            .as_ref()
20398            .filter(|_| self.minimap_visibility.visible())
20399    }
20400
20401    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20402        let mut wrap_guides = smallvec![];
20403
20404        if self.show_wrap_guides == Some(false) {
20405            return wrap_guides;
20406        }
20407
20408        let settings = self.buffer.read(cx).language_settings(cx);
20409        if settings.show_wrap_guides {
20410            match self.soft_wrap_mode(cx) {
20411                SoftWrap::Column(soft_wrap) => {
20412                    wrap_guides.push((soft_wrap as usize, true));
20413                }
20414                SoftWrap::Bounded(soft_wrap) => {
20415                    wrap_guides.push((soft_wrap as usize, true));
20416                }
20417                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20418            }
20419            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20420        }
20421
20422        wrap_guides
20423    }
20424
20425    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20426        let settings = self.buffer.read(cx).language_settings(cx);
20427        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20428        match mode {
20429            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20430                SoftWrap::None
20431            }
20432            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20433            language_settings::SoftWrap::PreferredLineLength => {
20434                SoftWrap::Column(settings.preferred_line_length)
20435            }
20436            language_settings::SoftWrap::Bounded => {
20437                SoftWrap::Bounded(settings.preferred_line_length)
20438            }
20439        }
20440    }
20441
20442    pub fn set_soft_wrap_mode(
20443        &mut self,
20444        mode: language_settings::SoftWrap,
20445
20446        cx: &mut Context<Self>,
20447    ) {
20448        self.soft_wrap_mode_override = Some(mode);
20449        cx.notify();
20450    }
20451
20452    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20453        self.hard_wrap = hard_wrap;
20454        cx.notify();
20455    }
20456
20457    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20458        self.text_style_refinement = Some(style);
20459    }
20460
20461    /// called by the Element so we know what style we were most recently rendered with.
20462    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20463        // We intentionally do not inform the display map about the minimap style
20464        // so that wrapping is not recalculated and stays consistent for the editor
20465        // and its linked minimap.
20466        if !self.mode.is_minimap() {
20467            let font = style.text.font();
20468            let font_size = style.text.font_size.to_pixels(window.rem_size());
20469            let display_map = self
20470                .placeholder_display_map
20471                .as_ref()
20472                .filter(|_| self.is_empty(cx))
20473                .unwrap_or(&self.display_map);
20474
20475            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20476        }
20477        self.style = Some(style);
20478    }
20479
20480    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20481        if self.style.is_none() {
20482            self.style = Some(self.create_style(cx));
20483        }
20484        self.style.as_ref().unwrap()
20485    }
20486
20487    // Called by the element. This method is not designed to be called outside of the editor
20488    // element's layout code because it does not notify when rewrapping is computed synchronously.
20489    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20490        if self.is_empty(cx) {
20491            self.placeholder_display_map
20492                .as_ref()
20493                .map_or(false, |display_map| {
20494                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20495                })
20496        } else {
20497            self.display_map
20498                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20499        }
20500    }
20501
20502    pub fn set_soft_wrap(&mut self) {
20503        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20504    }
20505
20506    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20507        if self.soft_wrap_mode_override.is_some() {
20508            self.soft_wrap_mode_override.take();
20509        } else {
20510            let soft_wrap = match self.soft_wrap_mode(cx) {
20511                SoftWrap::GitDiff => return,
20512                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20513                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20514                    language_settings::SoftWrap::None
20515                }
20516            };
20517            self.soft_wrap_mode_override = Some(soft_wrap);
20518        }
20519        cx.notify();
20520    }
20521
20522    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20523        let Some(workspace) = self.workspace() else {
20524            return;
20525        };
20526        let fs = workspace.read(cx).app_state().fs.clone();
20527        let current_show = TabBarSettings::get_global(cx).show;
20528        update_settings_file(fs, cx, move |setting, _| {
20529            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20530        });
20531    }
20532
20533    pub fn toggle_indent_guides(
20534        &mut self,
20535        _: &ToggleIndentGuides,
20536        _: &mut Window,
20537        cx: &mut Context<Self>,
20538    ) {
20539        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20540            self.buffer
20541                .read(cx)
20542                .language_settings(cx)
20543                .indent_guides
20544                .enabled
20545        });
20546        self.show_indent_guides = Some(!currently_enabled);
20547        cx.notify();
20548    }
20549
20550    fn should_show_indent_guides(&self) -> Option<bool> {
20551        self.show_indent_guides
20552    }
20553
20554    pub fn disable_indent_guides_for_buffer(
20555        &mut self,
20556        buffer_id: BufferId,
20557        cx: &mut Context<Self>,
20558    ) {
20559        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20560        cx.notify();
20561    }
20562
20563    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20564        self.buffers_with_disabled_indent_guides
20565            .contains(&buffer_id)
20566    }
20567
20568    pub fn toggle_line_numbers(
20569        &mut self,
20570        _: &ToggleLineNumbers,
20571        _: &mut Window,
20572        cx: &mut Context<Self>,
20573    ) {
20574        let mut editor_settings = EditorSettings::get_global(cx).clone();
20575        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20576        EditorSettings::override_global(editor_settings, cx);
20577    }
20578
20579    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20580        if let Some(show_line_numbers) = self.show_line_numbers {
20581            return show_line_numbers;
20582        }
20583        EditorSettings::get_global(cx).gutter.line_numbers
20584    }
20585
20586    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20587        match (
20588            self.use_relative_line_numbers,
20589            EditorSettings::get_global(cx).relative_line_numbers,
20590        ) {
20591            (None, setting) => setting,
20592            (Some(false), _) => RelativeLineNumbers::Disabled,
20593            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20594            (Some(true), _) => RelativeLineNumbers::Enabled,
20595        }
20596    }
20597
20598    pub fn toggle_relative_line_numbers(
20599        &mut self,
20600        _: &ToggleRelativeLineNumbers,
20601        _: &mut Window,
20602        cx: &mut Context<Self>,
20603    ) {
20604        let is_relative = self.relative_line_numbers(cx);
20605        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20606    }
20607
20608    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20609        self.use_relative_line_numbers = is_relative;
20610        cx.notify();
20611    }
20612
20613    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20614        self.show_gutter = show_gutter;
20615        cx.notify();
20616    }
20617
20618    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20619        self.show_scrollbars = ScrollbarAxes {
20620            horizontal: show,
20621            vertical: show,
20622        };
20623        cx.notify();
20624    }
20625
20626    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20627        self.show_scrollbars.vertical = show;
20628        cx.notify();
20629    }
20630
20631    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20632        self.show_scrollbars.horizontal = show;
20633        cx.notify();
20634    }
20635
20636    pub fn set_minimap_visibility(
20637        &mut self,
20638        minimap_visibility: MinimapVisibility,
20639        window: &mut Window,
20640        cx: &mut Context<Self>,
20641    ) {
20642        if self.minimap_visibility != minimap_visibility {
20643            if minimap_visibility.visible() && self.minimap.is_none() {
20644                let minimap_settings = EditorSettings::get_global(cx).minimap;
20645                self.minimap =
20646                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20647            }
20648            self.minimap_visibility = minimap_visibility;
20649            cx.notify();
20650        }
20651    }
20652
20653    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20654        self.set_show_scrollbars(false, cx);
20655        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20656    }
20657
20658    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20659        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20660    }
20661
20662    /// Normally the text in full mode and auto height editors is padded on the
20663    /// left side by roughly half a character width for improved hit testing.
20664    ///
20665    /// Use this method to disable this for cases where this is not wanted (e.g.
20666    /// if you want to align the editor text with some other text above or below)
20667    /// or if you want to add this padding to single-line editors.
20668    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20669        self.offset_content = offset_content;
20670        cx.notify();
20671    }
20672
20673    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20674        self.show_line_numbers = Some(show_line_numbers);
20675        cx.notify();
20676    }
20677
20678    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20679        self.disable_expand_excerpt_buttons = true;
20680        cx.notify();
20681    }
20682
20683    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20684        self.delegate_expand_excerpts = delegate;
20685    }
20686
20687    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20688        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20689        cx.notify();
20690    }
20691
20692    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20693        self.show_code_actions = Some(show_code_actions);
20694        cx.notify();
20695    }
20696
20697    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20698        self.show_runnables = Some(show_runnables);
20699        cx.notify();
20700    }
20701
20702    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20703        self.show_breakpoints = Some(show_breakpoints);
20704        cx.notify();
20705    }
20706
20707    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20708        if self.display_map.read(cx).masked != masked {
20709            self.display_map.update(cx, |map, _| map.masked = masked);
20710        }
20711        cx.notify()
20712    }
20713
20714    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20715        self.show_wrap_guides = Some(show_wrap_guides);
20716        cx.notify();
20717    }
20718
20719    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20720        self.show_indent_guides = Some(show_indent_guides);
20721        cx.notify();
20722    }
20723
20724    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20725        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20726            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20727                && let Some(dir) = file.abs_path(cx).parent()
20728            {
20729                return Some(dir.to_owned());
20730            }
20731        }
20732
20733        None
20734    }
20735
20736    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20737        self.active_excerpt(cx)?
20738            .1
20739            .read(cx)
20740            .file()
20741            .and_then(|f| f.as_local())
20742    }
20743
20744    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20745        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20746            let buffer = buffer.read(cx);
20747            if let Some(project_path) = buffer.project_path(cx) {
20748                let project = self.project()?.read(cx);
20749                project.absolute_path(&project_path, cx)
20750            } else {
20751                buffer
20752                    .file()
20753                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20754            }
20755        })
20756    }
20757
20758    pub fn reveal_in_finder(
20759        &mut self,
20760        _: &RevealInFileManager,
20761        _window: &mut Window,
20762        cx: &mut Context<Self>,
20763    ) {
20764        if let Some(target) = self.target_file(cx) {
20765            cx.reveal_path(&target.abs_path(cx));
20766        }
20767    }
20768
20769    pub fn copy_path(
20770        &mut self,
20771        _: &zed_actions::workspace::CopyPath,
20772        _window: &mut Window,
20773        cx: &mut Context<Self>,
20774    ) {
20775        if let Some(path) = self.target_file_abs_path(cx)
20776            && let Some(path) = path.to_str()
20777        {
20778            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20779        } else {
20780            cx.propagate();
20781        }
20782    }
20783
20784    pub fn copy_relative_path(
20785        &mut self,
20786        _: &zed_actions::workspace::CopyRelativePath,
20787        _window: &mut Window,
20788        cx: &mut Context<Self>,
20789    ) {
20790        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20791            let project = self.project()?.read(cx);
20792            let path = buffer.read(cx).file()?.path();
20793            let path = path.display(project.path_style(cx));
20794            Some(path)
20795        }) {
20796            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20797        } else {
20798            cx.propagate();
20799        }
20800    }
20801
20802    /// Returns the project path for the editor's buffer, if any buffer is
20803    /// opened in the editor.
20804    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20805        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20806            buffer.read(cx).project_path(cx)
20807        } else {
20808            None
20809        }
20810    }
20811
20812    // Returns true if the editor handled a go-to-line request
20813    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20814        maybe!({
20815            let breakpoint_store = self.breakpoint_store.as_ref()?;
20816
20817            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20818            else {
20819                self.clear_row_highlights::<ActiveDebugLine>();
20820                return None;
20821            };
20822
20823            let position = active_stack_frame.position;
20824            let buffer_id = position.buffer_id?;
20825            let snapshot = self
20826                .project
20827                .as_ref()?
20828                .read(cx)
20829                .buffer_for_id(buffer_id, cx)?
20830                .read(cx)
20831                .snapshot();
20832
20833            let mut handled = false;
20834            for (id, ExcerptRange { context, .. }) in
20835                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20836            {
20837                if context.start.cmp(&position, &snapshot).is_ge()
20838                    || context.end.cmp(&position, &snapshot).is_lt()
20839                {
20840                    continue;
20841                }
20842                let snapshot = self.buffer.read(cx).snapshot(cx);
20843                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20844
20845                handled = true;
20846                self.clear_row_highlights::<ActiveDebugLine>();
20847
20848                self.go_to_line::<ActiveDebugLine>(
20849                    multibuffer_anchor,
20850                    Some(cx.theme().colors().editor_debugger_active_line_background),
20851                    window,
20852                    cx,
20853                );
20854
20855                cx.notify();
20856            }
20857
20858            handled.then_some(())
20859        })
20860        .is_some()
20861    }
20862
20863    pub fn copy_file_name_without_extension(
20864        &mut self,
20865        _: &CopyFileNameWithoutExtension,
20866        _: &mut Window,
20867        cx: &mut Context<Self>,
20868    ) {
20869        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20870            let file = buffer.read(cx).file()?;
20871            file.path().file_stem()
20872        }) {
20873            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20874        }
20875    }
20876
20877    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20878        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20879            let file = buffer.read(cx).file()?;
20880            Some(file.file_name(cx))
20881        }) {
20882            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20883        }
20884    }
20885
20886    pub fn toggle_git_blame(
20887        &mut self,
20888        _: &::git::Blame,
20889        window: &mut Window,
20890        cx: &mut Context<Self>,
20891    ) {
20892        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20893
20894        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20895            self.start_git_blame(true, window, cx);
20896        }
20897
20898        cx.notify();
20899    }
20900
20901    pub fn toggle_git_blame_inline(
20902        &mut self,
20903        _: &ToggleGitBlameInline,
20904        window: &mut Window,
20905        cx: &mut Context<Self>,
20906    ) {
20907        self.toggle_git_blame_inline_internal(true, window, cx);
20908        cx.notify();
20909    }
20910
20911    pub fn open_git_blame_commit(
20912        &mut self,
20913        _: &OpenGitBlameCommit,
20914        window: &mut Window,
20915        cx: &mut Context<Self>,
20916    ) {
20917        self.open_git_blame_commit_internal(window, cx);
20918    }
20919
20920    fn open_git_blame_commit_internal(
20921        &mut self,
20922        window: &mut Window,
20923        cx: &mut Context<Self>,
20924    ) -> Option<()> {
20925        let blame = self.blame.as_ref()?;
20926        let snapshot = self.snapshot(window, cx);
20927        let cursor = self
20928            .selections
20929            .newest::<Point>(&snapshot.display_snapshot)
20930            .head();
20931        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20932        let (_, blame_entry) = blame
20933            .update(cx, |blame, cx| {
20934                blame
20935                    .blame_for_rows(
20936                        &[RowInfo {
20937                            buffer_id: Some(buffer.remote_id()),
20938                            buffer_row: Some(point.row),
20939                            ..Default::default()
20940                        }],
20941                        cx,
20942                    )
20943                    .next()
20944            })
20945            .flatten()?;
20946        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20947        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20948        let workspace = self.workspace()?.downgrade();
20949        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20950        None
20951    }
20952
20953    pub fn git_blame_inline_enabled(&self) -> bool {
20954        self.git_blame_inline_enabled
20955    }
20956
20957    pub fn toggle_selection_menu(
20958        &mut self,
20959        _: &ToggleSelectionMenu,
20960        _: &mut Window,
20961        cx: &mut Context<Self>,
20962    ) {
20963        self.show_selection_menu = self
20964            .show_selection_menu
20965            .map(|show_selections_menu| !show_selections_menu)
20966            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20967
20968        cx.notify();
20969    }
20970
20971    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20972        self.show_selection_menu
20973            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20974    }
20975
20976    fn start_git_blame(
20977        &mut self,
20978        user_triggered: bool,
20979        window: &mut Window,
20980        cx: &mut Context<Self>,
20981    ) {
20982        if let Some(project) = self.project() {
20983            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20984                && buffer.read(cx).file().is_none()
20985            {
20986                return;
20987            }
20988
20989            let focused = self.focus_handle(cx).contains_focused(window, cx);
20990
20991            let project = project.clone();
20992            let blame = cx
20993                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20994            self.blame_subscription =
20995                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20996            self.blame = Some(blame);
20997        }
20998    }
20999
21000    fn toggle_git_blame_inline_internal(
21001        &mut self,
21002        user_triggered: bool,
21003        window: &mut Window,
21004        cx: &mut Context<Self>,
21005    ) {
21006        if self.git_blame_inline_enabled {
21007            self.git_blame_inline_enabled = false;
21008            self.show_git_blame_inline = false;
21009            self.show_git_blame_inline_delay_task.take();
21010        } else {
21011            self.git_blame_inline_enabled = true;
21012            self.start_git_blame_inline(user_triggered, window, cx);
21013        }
21014
21015        cx.notify();
21016    }
21017
21018    fn start_git_blame_inline(
21019        &mut self,
21020        user_triggered: bool,
21021        window: &mut Window,
21022        cx: &mut Context<Self>,
21023    ) {
21024        self.start_git_blame(user_triggered, window, cx);
21025
21026        if ProjectSettings::get_global(cx)
21027            .git
21028            .inline_blame_delay()
21029            .is_some()
21030        {
21031            self.start_inline_blame_timer(window, cx);
21032        } else {
21033            self.show_git_blame_inline = true
21034        }
21035    }
21036
21037    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21038        self.blame.as_ref()
21039    }
21040
21041    pub fn show_git_blame_gutter(&self) -> bool {
21042        self.show_git_blame_gutter
21043    }
21044
21045    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21046        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21047    }
21048
21049    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21050        self.show_git_blame_inline
21051            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21052            && !self.newest_selection_head_on_empty_line(cx)
21053            && self.has_blame_entries(cx)
21054    }
21055
21056    fn has_blame_entries(&self, cx: &App) -> bool {
21057        self.blame()
21058            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21059    }
21060
21061    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21062        let cursor_anchor = self.selections.newest_anchor().head();
21063
21064        let snapshot = self.buffer.read(cx).snapshot(cx);
21065        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21066
21067        snapshot.line_len(buffer_row) == 0
21068    }
21069
21070    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21071        let buffer_and_selection = maybe!({
21072            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21073            let selection_range = selection.range();
21074
21075            let multi_buffer = self.buffer().read(cx);
21076            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21077            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21078
21079            let (buffer, range, _) = if selection.reversed {
21080                buffer_ranges.first()
21081            } else {
21082                buffer_ranges.last()
21083            }?;
21084
21085            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21086            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21087
21088            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21089                let selection = start_row_in_buffer..end_row_in_buffer;
21090
21091                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21092            };
21093
21094            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21095
21096            Some((
21097                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21098                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21099                    ..buffer_diff_snapshot.row_to_base_text_row(
21100                        end_row_in_buffer,
21101                        Bias::Left,
21102                        buffer,
21103                    ),
21104            ))
21105        });
21106
21107        let Some((buffer, selection)) = buffer_and_selection else {
21108            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21109        };
21110
21111        let Some(project) = self.project() else {
21112            return Task::ready(Err(anyhow!("editor does not have project")));
21113        };
21114
21115        project.update(cx, |project, cx| {
21116            project.get_permalink_to_line(&buffer, selection, cx)
21117        })
21118    }
21119
21120    pub fn copy_permalink_to_line(
21121        &mut self,
21122        _: &CopyPermalinkToLine,
21123        window: &mut Window,
21124        cx: &mut Context<Self>,
21125    ) {
21126        let permalink_task = self.get_permalink_to_line(cx);
21127        let workspace = self.workspace();
21128
21129        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21130            Ok(permalink) => {
21131                cx.update(|_, cx| {
21132                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21133                })
21134                .ok();
21135            }
21136            Err(err) => {
21137                let message = format!("Failed to copy permalink: {err}");
21138
21139                anyhow::Result::<()>::Err(err).log_err();
21140
21141                if let Some(workspace) = workspace {
21142                    workspace
21143                        .update_in(cx, |workspace, _, cx| {
21144                            struct CopyPermalinkToLine;
21145
21146                            workspace.show_toast(
21147                                Toast::new(
21148                                    NotificationId::unique::<CopyPermalinkToLine>(),
21149                                    message,
21150                                ),
21151                                cx,
21152                            )
21153                        })
21154                        .ok();
21155                }
21156            }
21157        })
21158        .detach();
21159    }
21160
21161    pub fn copy_file_location(
21162        &mut self,
21163        _: &CopyFileLocation,
21164        _: &mut Window,
21165        cx: &mut Context<Self>,
21166    ) {
21167        let selection = self
21168            .selections
21169            .newest::<Point>(&self.display_snapshot(cx))
21170            .start
21171            .row
21172            + 1;
21173        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21174            let project = self.project()?.read(cx);
21175            let file = buffer.read(cx).file()?;
21176            let path = file.path().display(project.path_style(cx));
21177
21178            Some(format!("{path}:{selection}"))
21179        }) {
21180            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21181        }
21182    }
21183
21184    pub fn open_permalink_to_line(
21185        &mut self,
21186        _: &OpenPermalinkToLine,
21187        window: &mut Window,
21188        cx: &mut Context<Self>,
21189    ) {
21190        let permalink_task = self.get_permalink_to_line(cx);
21191        let workspace = self.workspace();
21192
21193        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21194            Ok(permalink) => {
21195                cx.update(|_, cx| {
21196                    cx.open_url(permalink.as_ref());
21197                })
21198                .ok();
21199            }
21200            Err(err) => {
21201                let message = format!("Failed to open permalink: {err}");
21202
21203                anyhow::Result::<()>::Err(err).log_err();
21204
21205                if let Some(workspace) = workspace {
21206                    workspace.update(cx, |workspace, cx| {
21207                        struct OpenPermalinkToLine;
21208
21209                        workspace.show_toast(
21210                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
21211                            cx,
21212                        )
21213                    });
21214                }
21215            }
21216        })
21217        .detach();
21218    }
21219
21220    pub fn insert_uuid_v4(
21221        &mut self,
21222        _: &InsertUuidV4,
21223        window: &mut Window,
21224        cx: &mut Context<Self>,
21225    ) {
21226        self.insert_uuid(UuidVersion::V4, window, cx);
21227    }
21228
21229    pub fn insert_uuid_v7(
21230        &mut self,
21231        _: &InsertUuidV7,
21232        window: &mut Window,
21233        cx: &mut Context<Self>,
21234    ) {
21235        self.insert_uuid(UuidVersion::V7, window, cx);
21236    }
21237
21238    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21240        self.transact(window, cx, |this, window, cx| {
21241            let edits = this
21242                .selections
21243                .all::<Point>(&this.display_snapshot(cx))
21244                .into_iter()
21245                .map(|selection| {
21246                    let uuid = match version {
21247                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21248                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21249                    };
21250
21251                    (selection.range(), uuid.to_string())
21252                });
21253            this.edit(edits, cx);
21254            this.refresh_edit_prediction(true, false, window, cx);
21255        });
21256    }
21257
21258    pub fn open_selections_in_multibuffer(
21259        &mut self,
21260        _: &OpenSelectionsInMultibuffer,
21261        window: &mut Window,
21262        cx: &mut Context<Self>,
21263    ) {
21264        let multibuffer = self.buffer.read(cx);
21265
21266        let Some(buffer) = multibuffer.as_singleton() else {
21267            return;
21268        };
21269
21270        let Some(workspace) = self.workspace() else {
21271            return;
21272        };
21273
21274        let title = multibuffer.title(cx).to_string();
21275
21276        let locations = self
21277            .selections
21278            .all_anchors(&self.display_snapshot(cx))
21279            .iter()
21280            .map(|selection| {
21281                (
21282                    buffer.clone(),
21283                    (selection.start.text_anchor..selection.end.text_anchor)
21284                        .to_point(buffer.read(cx)),
21285                )
21286            })
21287            .into_group_map();
21288
21289        cx.spawn_in(window, async move |_, cx| {
21290            workspace.update_in(cx, |workspace, window, cx| {
21291                Self::open_locations_in_multibuffer(
21292                    workspace,
21293                    locations,
21294                    format!("Selections for '{title}'"),
21295                    false,
21296                    false,
21297                    MultibufferSelectionMode::All,
21298                    window,
21299                    cx,
21300                );
21301            })
21302        })
21303        .detach();
21304    }
21305
21306    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21307    /// last highlight added will be used.
21308    ///
21309    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21310    pub fn highlight_rows<T: 'static>(
21311        &mut self,
21312        range: Range<Anchor>,
21313        color: Hsla,
21314        options: RowHighlightOptions,
21315        cx: &mut Context<Self>,
21316    ) {
21317        let snapshot = self.buffer().read(cx).snapshot(cx);
21318        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21319        let ix = row_highlights.binary_search_by(|highlight| {
21320            Ordering::Equal
21321                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21322                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21323        });
21324
21325        if let Err(mut ix) = ix {
21326            let index = post_inc(&mut self.highlight_order);
21327
21328            // If this range intersects with the preceding highlight, then merge it with
21329            // the preceding highlight. Otherwise insert a new highlight.
21330            let mut merged = false;
21331            if ix > 0 {
21332                let prev_highlight = &mut row_highlights[ix - 1];
21333                if prev_highlight
21334                    .range
21335                    .end
21336                    .cmp(&range.start, &snapshot)
21337                    .is_ge()
21338                {
21339                    ix -= 1;
21340                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21341                        prev_highlight.range.end = range.end;
21342                    }
21343                    merged = true;
21344                    prev_highlight.index = index;
21345                    prev_highlight.color = color;
21346                    prev_highlight.options = options;
21347                }
21348            }
21349
21350            if !merged {
21351                row_highlights.insert(
21352                    ix,
21353                    RowHighlight {
21354                        range,
21355                        index,
21356                        color,
21357                        options,
21358                        type_id: TypeId::of::<T>(),
21359                    },
21360                );
21361            }
21362
21363            // If any of the following highlights intersect with this one, merge them.
21364            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21365                let highlight = &row_highlights[ix];
21366                if next_highlight
21367                    .range
21368                    .start
21369                    .cmp(&highlight.range.end, &snapshot)
21370                    .is_le()
21371                {
21372                    if next_highlight
21373                        .range
21374                        .end
21375                        .cmp(&highlight.range.end, &snapshot)
21376                        .is_gt()
21377                    {
21378                        row_highlights[ix].range.end = next_highlight.range.end;
21379                    }
21380                    row_highlights.remove(ix + 1);
21381                } else {
21382                    break;
21383                }
21384            }
21385        }
21386    }
21387
21388    /// Remove any highlighted row ranges of the given type that intersect the
21389    /// given ranges.
21390    pub fn remove_highlighted_rows<T: 'static>(
21391        &mut self,
21392        ranges_to_remove: Vec<Range<Anchor>>,
21393        cx: &mut Context<Self>,
21394    ) {
21395        let snapshot = self.buffer().read(cx).snapshot(cx);
21396        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21397        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21398        row_highlights.retain(|highlight| {
21399            while let Some(range_to_remove) = ranges_to_remove.peek() {
21400                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21401                    Ordering::Less | Ordering::Equal => {
21402                        ranges_to_remove.next();
21403                    }
21404                    Ordering::Greater => {
21405                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21406                            Ordering::Less | Ordering::Equal => {
21407                                return false;
21408                            }
21409                            Ordering::Greater => break,
21410                        }
21411                    }
21412                }
21413            }
21414
21415            true
21416        })
21417    }
21418
21419    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21420    pub fn clear_row_highlights<T: 'static>(&mut self) {
21421        self.highlighted_rows.remove(&TypeId::of::<T>());
21422    }
21423
21424    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21425    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21426        self.highlighted_rows
21427            .get(&TypeId::of::<T>())
21428            .map_or(&[] as &[_], |vec| vec.as_slice())
21429            .iter()
21430            .map(|highlight| (highlight.range.clone(), highlight.color))
21431    }
21432
21433    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21434    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21435    /// Allows to ignore certain kinds of highlights.
21436    pub fn highlighted_display_rows(
21437        &self,
21438        window: &mut Window,
21439        cx: &mut App,
21440    ) -> BTreeMap<DisplayRow, LineHighlight> {
21441        let snapshot = self.snapshot(window, cx);
21442        let mut used_highlight_orders = HashMap::default();
21443        self.highlighted_rows
21444            .iter()
21445            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21446            .fold(
21447                BTreeMap::<DisplayRow, LineHighlight>::new(),
21448                |mut unique_rows, highlight| {
21449                    let start = highlight.range.start.to_display_point(&snapshot);
21450                    let end = highlight.range.end.to_display_point(&snapshot);
21451                    let start_row = start.row().0;
21452                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21453                    {
21454                        end.row().0.saturating_sub(1)
21455                    } else {
21456                        end.row().0
21457                    };
21458                    for row in start_row..=end_row {
21459                        let used_index =
21460                            used_highlight_orders.entry(row).or_insert(highlight.index);
21461                        if highlight.index >= *used_index {
21462                            *used_index = highlight.index;
21463                            unique_rows.insert(
21464                                DisplayRow(row),
21465                                LineHighlight {
21466                                    include_gutter: highlight.options.include_gutter,
21467                                    border: None,
21468                                    background: highlight.color.into(),
21469                                    type_id: Some(highlight.type_id),
21470                                },
21471                            );
21472                        }
21473                    }
21474                    unique_rows
21475                },
21476            )
21477    }
21478
21479    pub fn highlighted_display_row_for_autoscroll(
21480        &self,
21481        snapshot: &DisplaySnapshot,
21482    ) -> Option<DisplayRow> {
21483        self.highlighted_rows
21484            .values()
21485            .flat_map(|highlighted_rows| highlighted_rows.iter())
21486            .filter_map(|highlight| {
21487                if highlight.options.autoscroll {
21488                    Some(highlight.range.start.to_display_point(snapshot).row())
21489                } else {
21490                    None
21491                }
21492            })
21493            .min()
21494    }
21495
21496    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21497        self.highlight_background::<SearchWithinRange>(
21498            ranges,
21499            |_, colors| colors.colors().editor_document_highlight_read_background,
21500            cx,
21501        )
21502    }
21503
21504    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21505        self.breadcrumb_header = Some(new_header);
21506    }
21507
21508    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21509        self.clear_background_highlights::<SearchWithinRange>(cx);
21510    }
21511
21512    pub fn highlight_background<T: 'static>(
21513        &mut self,
21514        ranges: &[Range<Anchor>],
21515        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21516        cx: &mut Context<Self>,
21517    ) {
21518        self.background_highlights.insert(
21519            HighlightKey::Type(TypeId::of::<T>()),
21520            (Arc::new(color_fetcher), Arc::from(ranges)),
21521        );
21522        self.scrollbar_marker_state.dirty = true;
21523        cx.notify();
21524    }
21525
21526    pub fn highlight_background_key<T: 'static>(
21527        &mut self,
21528        key: usize,
21529        ranges: &[Range<Anchor>],
21530        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21531        cx: &mut Context<Self>,
21532    ) {
21533        self.background_highlights.insert(
21534            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21535            (Arc::new(color_fetcher), Arc::from(ranges)),
21536        );
21537        self.scrollbar_marker_state.dirty = true;
21538        cx.notify();
21539    }
21540
21541    pub fn clear_background_highlights<T: 'static>(
21542        &mut self,
21543        cx: &mut Context<Self>,
21544    ) -> Option<BackgroundHighlight> {
21545        let text_highlights = self
21546            .background_highlights
21547            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21548        if !text_highlights.1.is_empty() {
21549            self.scrollbar_marker_state.dirty = true;
21550            cx.notify();
21551        }
21552        Some(text_highlights)
21553    }
21554
21555    pub fn highlight_gutter<T: 'static>(
21556        &mut self,
21557        ranges: impl Into<Vec<Range<Anchor>>>,
21558        color_fetcher: fn(&App) -> Hsla,
21559        cx: &mut Context<Self>,
21560    ) {
21561        self.gutter_highlights
21562            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21563        cx.notify();
21564    }
21565
21566    pub fn clear_gutter_highlights<T: 'static>(
21567        &mut self,
21568        cx: &mut Context<Self>,
21569    ) -> Option<GutterHighlight> {
21570        cx.notify();
21571        self.gutter_highlights.remove(&TypeId::of::<T>())
21572    }
21573
21574    pub fn insert_gutter_highlight<T: 'static>(
21575        &mut self,
21576        range: Range<Anchor>,
21577        color_fetcher: fn(&App) -> Hsla,
21578        cx: &mut Context<Self>,
21579    ) {
21580        let snapshot = self.buffer().read(cx).snapshot(cx);
21581        let mut highlights = self
21582            .gutter_highlights
21583            .remove(&TypeId::of::<T>())
21584            .map(|(_, highlights)| highlights)
21585            .unwrap_or_default();
21586        let ix = highlights.binary_search_by(|highlight| {
21587            Ordering::Equal
21588                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21589                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21590        });
21591        if let Err(ix) = ix {
21592            highlights.insert(ix, range);
21593        }
21594        self.gutter_highlights
21595            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21596    }
21597
21598    pub fn remove_gutter_highlights<T: 'static>(
21599        &mut self,
21600        ranges_to_remove: Vec<Range<Anchor>>,
21601        cx: &mut Context<Self>,
21602    ) {
21603        let snapshot = self.buffer().read(cx).snapshot(cx);
21604        let Some((color_fetcher, mut gutter_highlights)) =
21605            self.gutter_highlights.remove(&TypeId::of::<T>())
21606        else {
21607            return;
21608        };
21609        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21610        gutter_highlights.retain(|highlight| {
21611            while let Some(range_to_remove) = ranges_to_remove.peek() {
21612                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21613                    Ordering::Less | Ordering::Equal => {
21614                        ranges_to_remove.next();
21615                    }
21616                    Ordering::Greater => {
21617                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21618                            Ordering::Less | Ordering::Equal => {
21619                                return false;
21620                            }
21621                            Ordering::Greater => break,
21622                        }
21623                    }
21624                }
21625            }
21626
21627            true
21628        });
21629        self.gutter_highlights
21630            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21631    }
21632
21633    #[cfg(feature = "test-support")]
21634    pub fn all_text_highlights(
21635        &self,
21636        window: &mut Window,
21637        cx: &mut Context<Self>,
21638    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21639        let snapshot = self.snapshot(window, cx);
21640        self.display_map.update(cx, |display_map, _| {
21641            display_map
21642                .all_text_highlights()
21643                .map(|highlight| {
21644                    let (style, ranges) = highlight.as_ref();
21645                    (
21646                        *style,
21647                        ranges
21648                            .iter()
21649                            .map(|range| range.clone().to_display_points(&snapshot))
21650                            .collect(),
21651                    )
21652                })
21653                .collect()
21654        })
21655    }
21656
21657    #[cfg(feature = "test-support")]
21658    pub fn all_text_background_highlights(
21659        &self,
21660        window: &mut Window,
21661        cx: &mut Context<Self>,
21662    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21663        let snapshot = self.snapshot(window, cx);
21664        let buffer = &snapshot.buffer_snapshot();
21665        let start = buffer.anchor_before(MultiBufferOffset(0));
21666        let end = buffer.anchor_after(buffer.len());
21667        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21668    }
21669
21670    #[cfg(any(test, feature = "test-support"))]
21671    pub fn sorted_background_highlights_in_range(
21672        &self,
21673        search_range: Range<Anchor>,
21674        display_snapshot: &DisplaySnapshot,
21675        theme: &Theme,
21676    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21677        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21678        res.sort_by(|a, b| {
21679            a.0.start
21680                .cmp(&b.0.start)
21681                .then_with(|| a.0.end.cmp(&b.0.end))
21682                .then_with(|| a.1.cmp(&b.1))
21683        });
21684        res
21685    }
21686
21687    #[cfg(feature = "test-support")]
21688    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21689        let snapshot = self.buffer().read(cx).snapshot(cx);
21690
21691        let highlights = self
21692            .background_highlights
21693            .get(&HighlightKey::Type(TypeId::of::<
21694                items::BufferSearchHighlights,
21695            >()));
21696
21697        if let Some((_color, ranges)) = highlights {
21698            ranges
21699                .iter()
21700                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21701                .collect_vec()
21702        } else {
21703            vec![]
21704        }
21705    }
21706
21707    fn document_highlights_for_position<'a>(
21708        &'a self,
21709        position: Anchor,
21710        buffer: &'a MultiBufferSnapshot,
21711    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21712        let read_highlights = self
21713            .background_highlights
21714            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21715            .map(|h| &h.1);
21716        let write_highlights = self
21717            .background_highlights
21718            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21719            .map(|h| &h.1);
21720        let left_position = position.bias_left(buffer);
21721        let right_position = position.bias_right(buffer);
21722        read_highlights
21723            .into_iter()
21724            .chain(write_highlights)
21725            .flat_map(move |ranges| {
21726                let start_ix = match ranges.binary_search_by(|probe| {
21727                    let cmp = probe.end.cmp(&left_position, buffer);
21728                    if cmp.is_ge() {
21729                        Ordering::Greater
21730                    } else {
21731                        Ordering::Less
21732                    }
21733                }) {
21734                    Ok(i) | Err(i) => i,
21735                };
21736
21737                ranges[start_ix..]
21738                    .iter()
21739                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21740            })
21741    }
21742
21743    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21744        self.background_highlights
21745            .get(&HighlightKey::Type(TypeId::of::<T>()))
21746            .is_some_and(|(_, highlights)| !highlights.is_empty())
21747    }
21748
21749    /// Returns all background highlights for a given range.
21750    ///
21751    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21752    pub fn background_highlights_in_range(
21753        &self,
21754        search_range: Range<Anchor>,
21755        display_snapshot: &DisplaySnapshot,
21756        theme: &Theme,
21757    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21758        let mut results = Vec::new();
21759        for (color_fetcher, ranges) in self.background_highlights.values() {
21760            let start_ix = match ranges.binary_search_by(|probe| {
21761                let cmp = probe
21762                    .end
21763                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21764                if cmp.is_gt() {
21765                    Ordering::Greater
21766                } else {
21767                    Ordering::Less
21768                }
21769            }) {
21770                Ok(i) | Err(i) => i,
21771            };
21772            for (index, range) in ranges[start_ix..].iter().enumerate() {
21773                if range
21774                    .start
21775                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21776                    .is_ge()
21777                {
21778                    break;
21779                }
21780
21781                let color = color_fetcher(&(start_ix + index), theme);
21782                let start = range.start.to_display_point(display_snapshot);
21783                let end = range.end.to_display_point(display_snapshot);
21784                results.push((start..end, color))
21785            }
21786        }
21787        results
21788    }
21789
21790    pub fn gutter_highlights_in_range(
21791        &self,
21792        search_range: Range<Anchor>,
21793        display_snapshot: &DisplaySnapshot,
21794        cx: &App,
21795    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21796        let mut results = Vec::new();
21797        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21798            let color = color_fetcher(cx);
21799            let start_ix = match ranges.binary_search_by(|probe| {
21800                let cmp = probe
21801                    .end
21802                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21803                if cmp.is_gt() {
21804                    Ordering::Greater
21805                } else {
21806                    Ordering::Less
21807                }
21808            }) {
21809                Ok(i) | Err(i) => i,
21810            };
21811            for range in &ranges[start_ix..] {
21812                if range
21813                    .start
21814                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21815                    .is_ge()
21816                {
21817                    break;
21818                }
21819
21820                let start = range.start.to_display_point(display_snapshot);
21821                let end = range.end.to_display_point(display_snapshot);
21822                results.push((start..end, color))
21823            }
21824        }
21825        results
21826    }
21827
21828    /// Get the text ranges corresponding to the redaction query
21829    pub fn redacted_ranges(
21830        &self,
21831        search_range: Range<Anchor>,
21832        display_snapshot: &DisplaySnapshot,
21833        cx: &App,
21834    ) -> Vec<Range<DisplayPoint>> {
21835        display_snapshot
21836            .buffer_snapshot()
21837            .redacted_ranges(search_range, |file| {
21838                if let Some(file) = file {
21839                    file.is_private()
21840                        && EditorSettings::get(
21841                            Some(SettingsLocation {
21842                                worktree_id: file.worktree_id(cx),
21843                                path: file.path().as_ref(),
21844                            }),
21845                            cx,
21846                        )
21847                        .redact_private_values
21848                } else {
21849                    false
21850                }
21851            })
21852            .map(|range| {
21853                range.start.to_display_point(display_snapshot)
21854                    ..range.end.to_display_point(display_snapshot)
21855            })
21856            .collect()
21857    }
21858
21859    pub fn highlight_text_key<T: 'static>(
21860        &mut self,
21861        key: usize,
21862        ranges: Vec<Range<Anchor>>,
21863        style: HighlightStyle,
21864        merge: bool,
21865        cx: &mut Context<Self>,
21866    ) {
21867        self.display_map.update(cx, |map, cx| {
21868            map.highlight_text(
21869                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21870                ranges,
21871                style,
21872                merge,
21873                cx,
21874            );
21875        });
21876        cx.notify();
21877    }
21878
21879    pub fn highlight_text<T: 'static>(
21880        &mut self,
21881        ranges: Vec<Range<Anchor>>,
21882        style: HighlightStyle,
21883        cx: &mut Context<Self>,
21884    ) {
21885        self.display_map.update(cx, |map, cx| {
21886            map.highlight_text(
21887                HighlightKey::Type(TypeId::of::<T>()),
21888                ranges,
21889                style,
21890                false,
21891                cx,
21892            )
21893        });
21894        cx.notify();
21895    }
21896
21897    pub fn text_highlights<'a, T: 'static>(
21898        &'a self,
21899        cx: &'a App,
21900    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21901        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21902    }
21903
21904    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21905        let cleared = self
21906            .display_map
21907            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21908        if cleared {
21909            cx.notify();
21910        }
21911    }
21912
21913    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21914        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21915            && self.focus_handle.is_focused(window)
21916    }
21917
21918    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21919        self.show_cursor_when_unfocused = is_enabled;
21920        cx.notify();
21921    }
21922
21923    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21924        cx.notify();
21925    }
21926
21927    fn on_debug_session_event(
21928        &mut self,
21929        _session: Entity<Session>,
21930        event: &SessionEvent,
21931        cx: &mut Context<Self>,
21932    ) {
21933        if let SessionEvent::InvalidateInlineValue = event {
21934            self.refresh_inline_values(cx);
21935        }
21936    }
21937
21938    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21939        let Some(project) = self.project.clone() else {
21940            return;
21941        };
21942
21943        if !self.inline_value_cache.enabled {
21944            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21945            self.splice_inlays(&inlays, Vec::new(), cx);
21946            return;
21947        }
21948
21949        let current_execution_position = self
21950            .highlighted_rows
21951            .get(&TypeId::of::<ActiveDebugLine>())
21952            .and_then(|lines| lines.last().map(|line| line.range.end));
21953
21954        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21955            let inline_values = editor
21956                .update(cx, |editor, cx| {
21957                    let Some(current_execution_position) = current_execution_position else {
21958                        return Some(Task::ready(Ok(Vec::new())));
21959                    };
21960
21961                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21962                        let snapshot = buffer.snapshot(cx);
21963
21964                        let excerpt = snapshot.excerpt_containing(
21965                            current_execution_position..current_execution_position,
21966                        )?;
21967
21968                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21969                    })?;
21970
21971                    let range =
21972                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21973
21974                    project.inline_values(buffer, range, cx)
21975                })
21976                .ok()
21977                .flatten()?
21978                .await
21979                .context("refreshing debugger inlays")
21980                .log_err()?;
21981
21982            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21983
21984            for (buffer_id, inline_value) in inline_values
21985                .into_iter()
21986                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21987            {
21988                buffer_inline_values
21989                    .entry(buffer_id)
21990                    .or_default()
21991                    .push(inline_value);
21992            }
21993
21994            editor
21995                .update(cx, |editor, cx| {
21996                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21997                    let mut new_inlays = Vec::default();
21998
21999                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22000                        let buffer_id = buffer_snapshot.remote_id();
22001                        buffer_inline_values
22002                            .get(&buffer_id)
22003                            .into_iter()
22004                            .flatten()
22005                            .for_each(|hint| {
22006                                let inlay = Inlay::debugger(
22007                                    post_inc(&mut editor.next_inlay_id),
22008                                    Anchor::in_buffer(excerpt_id, hint.position),
22009                                    hint.text(),
22010                                );
22011                                if !inlay.text().chars().contains(&'\n') {
22012                                    new_inlays.push(inlay);
22013                                }
22014                            });
22015                    }
22016
22017                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22018                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22019
22020                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22021                })
22022                .ok()?;
22023            Some(())
22024        });
22025    }
22026
22027    fn on_buffer_event(
22028        &mut self,
22029        multibuffer: &Entity<MultiBuffer>,
22030        event: &multi_buffer::Event,
22031        window: &mut Window,
22032        cx: &mut Context<Self>,
22033    ) {
22034        match event {
22035            multi_buffer::Event::Edited { edited_buffer } => {
22036                self.scrollbar_marker_state.dirty = true;
22037                self.active_indent_guides_state.dirty = true;
22038                self.refresh_active_diagnostics(cx);
22039                self.refresh_code_actions(window, cx);
22040                self.refresh_single_line_folds(window, cx);
22041                self.refresh_matching_bracket_highlights(window, cx);
22042                if self.has_active_edit_prediction() {
22043                    self.update_visible_edit_prediction(window, cx);
22044                }
22045
22046                if let Some(buffer) = edited_buffer {
22047                    if buffer.read(cx).file().is_none() {
22048                        cx.emit(EditorEvent::TitleChanged);
22049                    }
22050
22051                    if self.project.is_some() {
22052                        let buffer_id = buffer.read(cx).remote_id();
22053                        self.register_buffer(buffer_id, cx);
22054                        self.update_lsp_data(Some(buffer_id), window, cx);
22055                        self.refresh_inlay_hints(
22056                            InlayHintRefreshReason::BufferEdited(buffer_id),
22057                            cx,
22058                        );
22059                    }
22060                }
22061
22062                cx.emit(EditorEvent::BufferEdited);
22063                cx.emit(SearchEvent::MatchesInvalidated);
22064
22065                let Some(project) = &self.project else { return };
22066                let (telemetry, is_via_ssh) = {
22067                    let project = project.read(cx);
22068                    let telemetry = project.client().telemetry().clone();
22069                    let is_via_ssh = project.is_via_remote_server();
22070                    (telemetry, is_via_ssh)
22071                };
22072                telemetry.log_edit_event("editor", is_via_ssh);
22073            }
22074            multi_buffer::Event::ExcerptsAdded {
22075                buffer,
22076                predecessor,
22077                excerpts,
22078            } => {
22079                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22080                let buffer_id = buffer.read(cx).remote_id();
22081                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22082                    && let Some(project) = &self.project
22083                {
22084                    update_uncommitted_diff_for_buffer(
22085                        cx.entity(),
22086                        project,
22087                        [buffer.clone()],
22088                        self.buffer.clone(),
22089                        cx,
22090                    )
22091                    .detach();
22092                }
22093                self.update_lsp_data(Some(buffer_id), window, cx);
22094                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22095                self.colorize_brackets(false, cx);
22096                cx.emit(EditorEvent::ExcerptsAdded {
22097                    buffer: buffer.clone(),
22098                    predecessor: *predecessor,
22099                    excerpts: excerpts.clone(),
22100                });
22101            }
22102            multi_buffer::Event::ExcerptsRemoved {
22103                ids,
22104                removed_buffer_ids,
22105            } => {
22106                if let Some(inlay_hints) = &mut self.inlay_hints {
22107                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22108                }
22109                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22110                for buffer_id in removed_buffer_ids {
22111                    self.registered_buffers.remove(buffer_id);
22112                }
22113                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22114                cx.emit(EditorEvent::ExcerptsRemoved {
22115                    ids: ids.clone(),
22116                    removed_buffer_ids: removed_buffer_ids.clone(),
22117                });
22118            }
22119            multi_buffer::Event::ExcerptsEdited {
22120                excerpt_ids,
22121                buffer_ids,
22122            } => {
22123                self.display_map.update(cx, |map, cx| {
22124                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22125                });
22126                cx.emit(EditorEvent::ExcerptsEdited {
22127                    ids: excerpt_ids.clone(),
22128                });
22129            }
22130            multi_buffer::Event::ExcerptsExpanded { ids } => {
22131                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22132                self.refresh_document_highlights(cx);
22133                for id in ids {
22134                    self.fetched_tree_sitter_chunks.remove(id);
22135                }
22136                self.colorize_brackets(false, cx);
22137                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22138            }
22139            multi_buffer::Event::Reparsed(buffer_id) => {
22140                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22141                self.refresh_selected_text_highlights(true, window, cx);
22142                self.colorize_brackets(true, cx);
22143                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22144
22145                cx.emit(EditorEvent::Reparsed(*buffer_id));
22146            }
22147            multi_buffer::Event::DiffHunksToggled => {
22148                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22149            }
22150            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22151                if !is_fresh_language {
22152                    self.registered_buffers.remove(&buffer_id);
22153                }
22154                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22155                cx.emit(EditorEvent::Reparsed(*buffer_id));
22156                cx.notify();
22157            }
22158            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22159            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22160            multi_buffer::Event::FileHandleChanged
22161            | multi_buffer::Event::Reloaded
22162            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22163            multi_buffer::Event::DiagnosticsUpdated => {
22164                self.update_diagnostics_state(window, cx);
22165            }
22166            _ => {}
22167        };
22168    }
22169
22170    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22171        if !self.diagnostics_enabled() {
22172            return;
22173        }
22174        self.refresh_active_diagnostics(cx);
22175        self.refresh_inline_diagnostics(true, window, cx);
22176        self.scrollbar_marker_state.dirty = true;
22177        cx.notify();
22178    }
22179
22180    pub fn start_temporary_diff_override(&mut self) {
22181        self.load_diff_task.take();
22182        self.temporary_diff_override = true;
22183    }
22184
22185    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22186        self.temporary_diff_override = false;
22187        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22188        self.buffer.update(cx, |buffer, cx| {
22189            buffer.set_all_diff_hunks_collapsed(cx);
22190        });
22191
22192        if let Some(project) = self.project.clone() {
22193            self.load_diff_task = Some(
22194                update_uncommitted_diff_for_buffer(
22195                    cx.entity(),
22196                    &project,
22197                    self.buffer.read(cx).all_buffers(),
22198                    self.buffer.clone(),
22199                    cx,
22200                )
22201                .shared(),
22202            );
22203        }
22204    }
22205
22206    fn on_display_map_changed(
22207        &mut self,
22208        _: Entity<DisplayMap>,
22209        _: &mut Window,
22210        cx: &mut Context<Self>,
22211    ) {
22212        cx.notify();
22213    }
22214
22215    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22216        if !self.mode.is_full() {
22217            return None;
22218        }
22219
22220        let theme_settings = theme::ThemeSettings::get_global(cx);
22221        let theme = cx.theme();
22222        let accent_colors = theme.accents().clone();
22223
22224        let accent_overrides = theme_settings
22225            .theme_overrides
22226            .get(theme.name.as_ref())
22227            .map(|theme_style| &theme_style.accents)
22228            .into_iter()
22229            .flatten()
22230            .chain(
22231                theme_settings
22232                    .experimental_theme_overrides
22233                    .as_ref()
22234                    .map(|overrides| &overrides.accents)
22235                    .into_iter()
22236                    .flatten(),
22237            )
22238            .flat_map(|accent| accent.0.clone())
22239            .collect();
22240
22241        Some(AccentData {
22242            colors: accent_colors,
22243            overrides: accent_overrides,
22244        })
22245    }
22246
22247    fn fetch_applicable_language_settings(
22248        &self,
22249        cx: &App,
22250    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22251        if !self.mode.is_full() {
22252            return HashMap::default();
22253        }
22254
22255        self.buffer().read(cx).all_buffers().into_iter().fold(
22256            HashMap::default(),
22257            |mut acc, buffer| {
22258                let buffer = buffer.read(cx);
22259                let language = buffer.language().map(|language| language.name());
22260                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22261                    let file = buffer.file();
22262                    v.insert(language_settings(language, file, cx).into_owned());
22263                }
22264                acc
22265            },
22266        )
22267    }
22268
22269    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22270        let new_language_settings = self.fetch_applicable_language_settings(cx);
22271        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22272        self.applicable_language_settings = new_language_settings;
22273
22274        let new_accents = self.fetch_accent_data(cx);
22275        let accents_changed = new_accents != self.accent_data;
22276        self.accent_data = new_accents;
22277
22278        if self.diagnostics_enabled() {
22279            let new_severity = EditorSettings::get_global(cx)
22280                .diagnostics_max_severity
22281                .unwrap_or(DiagnosticSeverity::Hint);
22282            self.set_max_diagnostics_severity(new_severity, cx);
22283        }
22284        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22285        self.update_edit_prediction_settings(cx);
22286        self.refresh_edit_prediction(true, false, window, cx);
22287        self.refresh_inline_values(cx);
22288        self.refresh_inlay_hints(
22289            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22290                self.selections.newest_anchor().head(),
22291                &self.buffer.read(cx).snapshot(cx),
22292                cx,
22293            )),
22294            cx,
22295        );
22296
22297        let old_cursor_shape = self.cursor_shape;
22298        let old_show_breadcrumbs = self.show_breadcrumbs;
22299
22300        {
22301            let editor_settings = EditorSettings::get_global(cx);
22302            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22303            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22304            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22305            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22306        }
22307
22308        if old_cursor_shape != self.cursor_shape {
22309            cx.emit(EditorEvent::CursorShapeChanged);
22310        }
22311
22312        if old_show_breadcrumbs != self.show_breadcrumbs {
22313            cx.emit(EditorEvent::BreadcrumbsChanged);
22314        }
22315
22316        let project_settings = ProjectSettings::get_global(cx);
22317        self.buffer_serialization = self
22318            .should_serialize_buffer()
22319            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22320
22321        if self.mode.is_full() {
22322            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22323            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22324            if self.show_inline_diagnostics != show_inline_diagnostics {
22325                self.show_inline_diagnostics = show_inline_diagnostics;
22326                self.refresh_inline_diagnostics(false, window, cx);
22327            }
22328
22329            if self.git_blame_inline_enabled != inline_blame_enabled {
22330                self.toggle_git_blame_inline_internal(false, window, cx);
22331            }
22332
22333            let minimap_settings = EditorSettings::get_global(cx).minimap;
22334            if self.minimap_visibility != MinimapVisibility::Disabled {
22335                if self.minimap_visibility.settings_visibility()
22336                    != minimap_settings.minimap_enabled()
22337                {
22338                    self.set_minimap_visibility(
22339                        MinimapVisibility::for_mode(self.mode(), cx),
22340                        window,
22341                        cx,
22342                    );
22343                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22344                    minimap_entity.update(cx, |minimap_editor, cx| {
22345                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22346                    })
22347                }
22348            }
22349
22350            if language_settings_changed || accents_changed {
22351                self.colorize_brackets(true, cx);
22352            }
22353
22354            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22355                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22356            }) {
22357                if !inlay_splice.is_empty() {
22358                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22359                }
22360                self.refresh_colors_for_visible_range(None, window, cx);
22361            }
22362        }
22363
22364        cx.notify();
22365    }
22366
22367    pub fn set_searchable(&mut self, searchable: bool) {
22368        self.searchable = searchable;
22369    }
22370
22371    pub fn searchable(&self) -> bool {
22372        self.searchable
22373    }
22374
22375    pub fn open_excerpts_in_split(
22376        &mut self,
22377        _: &OpenExcerptsSplit,
22378        window: &mut Window,
22379        cx: &mut Context<Self>,
22380    ) {
22381        self.open_excerpts_common(None, true, window, cx)
22382    }
22383
22384    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22385        self.open_excerpts_common(None, false, window, cx)
22386    }
22387
22388    fn open_excerpts_common(
22389        &mut self,
22390        jump_data: Option<JumpData>,
22391        split: bool,
22392        window: &mut Window,
22393        cx: &mut Context<Self>,
22394    ) {
22395        let Some(workspace) = self.workspace() else {
22396            cx.propagate();
22397            return;
22398        };
22399
22400        if self.buffer.read(cx).is_singleton() {
22401            cx.propagate();
22402            return;
22403        }
22404
22405        let mut new_selections_by_buffer = HashMap::default();
22406        match &jump_data {
22407            Some(JumpData::MultiBufferPoint {
22408                excerpt_id,
22409                position,
22410                anchor,
22411                line_offset_from_top,
22412            }) => {
22413                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22414                if let Some(buffer) = multi_buffer_snapshot
22415                    .buffer_id_for_excerpt(*excerpt_id)
22416                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22417                {
22418                    let buffer_snapshot = buffer.read(cx).snapshot();
22419                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22420                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22421                    } else {
22422                        buffer_snapshot.clip_point(*position, Bias::Left)
22423                    };
22424                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22425                    new_selections_by_buffer.insert(
22426                        buffer,
22427                        (
22428                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22429                            Some(*line_offset_from_top),
22430                        ),
22431                    );
22432                }
22433            }
22434            Some(JumpData::MultiBufferRow {
22435                row,
22436                line_offset_from_top,
22437            }) => {
22438                let point = MultiBufferPoint::new(row.0, 0);
22439                if let Some((buffer, buffer_point, _)) =
22440                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22441                {
22442                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22443                    new_selections_by_buffer
22444                        .entry(buffer)
22445                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22446                        .0
22447                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22448                }
22449            }
22450            None => {
22451                let selections = self
22452                    .selections
22453                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22454                let multi_buffer = self.buffer.read(cx);
22455                for selection in selections {
22456                    for (snapshot, range, _, anchor) in multi_buffer
22457                        .snapshot(cx)
22458                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22459                    {
22460                        if let Some(anchor) = anchor {
22461                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22462                            else {
22463                                continue;
22464                            };
22465                            let offset = text::ToOffset::to_offset(
22466                                &anchor.text_anchor,
22467                                &buffer_handle.read(cx).snapshot(),
22468                            );
22469                            let range = BufferOffset(offset)..BufferOffset(offset);
22470                            new_selections_by_buffer
22471                                .entry(buffer_handle)
22472                                .or_insert((Vec::new(), None))
22473                                .0
22474                                .push(range)
22475                        } else {
22476                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22477                            else {
22478                                continue;
22479                            };
22480                            new_selections_by_buffer
22481                                .entry(buffer_handle)
22482                                .or_insert((Vec::new(), None))
22483                                .0
22484                                .push(range)
22485                        }
22486                    }
22487                }
22488            }
22489        }
22490
22491        new_selections_by_buffer
22492            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
22493
22494        if new_selections_by_buffer.is_empty() {
22495            return;
22496        }
22497
22498        // We defer the pane interaction because we ourselves are a workspace item
22499        // and activating a new item causes the pane to call a method on us reentrantly,
22500        // which panics if we're on the stack.
22501        window.defer(cx, move |window, cx| {
22502            workspace.update(cx, |workspace, cx| {
22503                let pane = if split {
22504                    workspace.adjacent_pane(window, cx)
22505                } else {
22506                    workspace.active_pane().clone()
22507                };
22508
22509                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22510                    let buffer_read = buffer.read(cx);
22511                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22512                        (true, project::File::from_dyn(Some(file)).is_some())
22513                    } else {
22514                        (false, false)
22515                    };
22516
22517                    // If project file is none workspace.open_project_item will fail to open the excerpt
22518                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22519                    // so we check if there's a tab match in that case first
22520                    let editor = (!has_file || !is_project_file)
22521                        .then(|| {
22522                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22523                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22524                            // Instead, we try to activate the existing editor in the pane first.
22525                            let (editor, pane_item_index, pane_item_id) =
22526                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22527                                    let editor = item.downcast::<Editor>()?;
22528                                    let singleton_buffer =
22529                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22530                                    if singleton_buffer == buffer {
22531                                        Some((editor, i, item.item_id()))
22532                                    } else {
22533                                        None
22534                                    }
22535                                })?;
22536                            pane.update(cx, |pane, cx| {
22537                                pane.activate_item(pane_item_index, true, true, window, cx);
22538                                if !PreviewTabsSettings::get_global(cx)
22539                                    .enable_preview_from_multibuffer
22540                                {
22541                                    pane.unpreview_item_if_preview(pane_item_id);
22542                                }
22543                            });
22544                            Some(editor)
22545                        })
22546                        .flatten()
22547                        .unwrap_or_else(|| {
22548                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22549                                .enable_keep_preview_on_code_navigation;
22550                            let allow_new_preview =
22551                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22552                            workspace.open_project_item::<Self>(
22553                                pane.clone(),
22554                                buffer,
22555                                true,
22556                                true,
22557                                keep_old_preview,
22558                                allow_new_preview,
22559                                window,
22560                                cx,
22561                            )
22562                        });
22563
22564                    editor.update(cx, |editor, cx| {
22565                        if has_file && !is_project_file {
22566                            editor.set_read_only(true);
22567                        }
22568                        let autoscroll = match scroll_offset {
22569                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22570                            None => Autoscroll::newest(),
22571                        };
22572                        let nav_history = editor.nav_history.take();
22573                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22574                        let Some((&excerpt_id, _, buffer_snapshot)) =
22575                            multibuffer_snapshot.as_singleton()
22576                        else {
22577                            return;
22578                        };
22579                        editor.change_selections(
22580                            SelectionEffects::scroll(autoscroll),
22581                            window,
22582                            cx,
22583                            |s| {
22584                                s.select_ranges(ranges.into_iter().map(|range| {
22585                                    let range = buffer_snapshot.anchor_before(range.start)
22586                                        ..buffer_snapshot.anchor_after(range.end);
22587                                    multibuffer_snapshot
22588                                        .anchor_range_in_excerpt(excerpt_id, range)
22589                                        .unwrap()
22590                                }));
22591                            },
22592                        );
22593                        editor.nav_history = nav_history;
22594                    });
22595                }
22596            })
22597        });
22598    }
22599
22600    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22601        let snapshot = self.buffer.read(cx).read(cx);
22602        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22603        Some(
22604            ranges
22605                .iter()
22606                .map(move |range| {
22607                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22608                })
22609                .collect(),
22610        )
22611    }
22612
22613    fn selection_replacement_ranges(
22614        &self,
22615        range: Range<MultiBufferOffsetUtf16>,
22616        cx: &mut App,
22617    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22618        let selections = self
22619            .selections
22620            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22621        let newest_selection = selections
22622            .iter()
22623            .max_by_key(|selection| selection.id)
22624            .unwrap();
22625        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22626        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22627        let snapshot = self.buffer.read(cx).read(cx);
22628        selections
22629            .into_iter()
22630            .map(|mut selection| {
22631                selection.start.0.0 =
22632                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22633                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22634                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22635                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22636            })
22637            .collect()
22638    }
22639
22640    fn report_editor_event(
22641        &self,
22642        reported_event: ReportEditorEvent,
22643        file_extension: Option<String>,
22644        cx: &App,
22645    ) {
22646        if cfg!(any(test, feature = "test-support")) {
22647            return;
22648        }
22649
22650        let Some(project) = &self.project else { return };
22651
22652        // If None, we are in a file without an extension
22653        let file = self
22654            .buffer
22655            .read(cx)
22656            .as_singleton()
22657            .and_then(|b| b.read(cx).file());
22658        let file_extension = file_extension.or(file
22659            .as_ref()
22660            .and_then(|file| Path::new(file.file_name(cx)).extension())
22661            .and_then(|e| e.to_str())
22662            .map(|a| a.to_string()));
22663
22664        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22665            .map(|vim_mode| vim_mode.0)
22666            .unwrap_or(false);
22667
22668        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22669        let copilot_enabled = edit_predictions_provider
22670            == language::language_settings::EditPredictionProvider::Copilot;
22671        let copilot_enabled_for_language = self
22672            .buffer
22673            .read(cx)
22674            .language_settings(cx)
22675            .show_edit_predictions;
22676
22677        let project = project.read(cx);
22678        let event_type = reported_event.event_type();
22679
22680        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22681            telemetry::event!(
22682                event_type,
22683                type = if auto_saved {"autosave"} else {"manual"},
22684                file_extension,
22685                vim_mode,
22686                copilot_enabled,
22687                copilot_enabled_for_language,
22688                edit_predictions_provider,
22689                is_via_ssh = project.is_via_remote_server(),
22690            );
22691        } else {
22692            telemetry::event!(
22693                event_type,
22694                file_extension,
22695                vim_mode,
22696                copilot_enabled,
22697                copilot_enabled_for_language,
22698                edit_predictions_provider,
22699                is_via_ssh = project.is_via_remote_server(),
22700            );
22701        };
22702    }
22703
22704    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22705    /// with each line being an array of {text, highlight} objects.
22706    fn copy_highlight_json(
22707        &mut self,
22708        _: &CopyHighlightJson,
22709        window: &mut Window,
22710        cx: &mut Context<Self>,
22711    ) {
22712        #[derive(Serialize)]
22713        struct Chunk<'a> {
22714            text: String,
22715            highlight: Option<&'a str>,
22716        }
22717
22718        let snapshot = self.buffer.read(cx).snapshot(cx);
22719        let range = self
22720            .selected_text_range(false, window, cx)
22721            .and_then(|selection| {
22722                if selection.range.is_empty() {
22723                    None
22724                } else {
22725                    Some(
22726                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22727                            selection.range.start,
22728                        )))
22729                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22730                                selection.range.end,
22731                            ))),
22732                    )
22733                }
22734            })
22735            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22736
22737        let chunks = snapshot.chunks(range, true);
22738        let mut lines = Vec::new();
22739        let mut line: VecDeque<Chunk> = VecDeque::new();
22740
22741        let Some(style) = self.style.as_ref() else {
22742            return;
22743        };
22744
22745        for chunk in chunks {
22746            let highlight = chunk
22747                .syntax_highlight_id
22748                .and_then(|id| id.name(&style.syntax));
22749            let mut chunk_lines = chunk.text.split('\n').peekable();
22750            while let Some(text) = chunk_lines.next() {
22751                let mut merged_with_last_token = false;
22752                if let Some(last_token) = line.back_mut()
22753                    && last_token.highlight == highlight
22754                {
22755                    last_token.text.push_str(text);
22756                    merged_with_last_token = true;
22757                }
22758
22759                if !merged_with_last_token {
22760                    line.push_back(Chunk {
22761                        text: text.into(),
22762                        highlight,
22763                    });
22764                }
22765
22766                if chunk_lines.peek().is_some() {
22767                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22768                        line.pop_front();
22769                    }
22770                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22771                        line.pop_back();
22772                    }
22773
22774                    lines.push(mem::take(&mut line));
22775                }
22776            }
22777        }
22778
22779        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22780            return;
22781        };
22782        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22783    }
22784
22785    pub fn open_context_menu(
22786        &mut self,
22787        _: &OpenContextMenu,
22788        window: &mut Window,
22789        cx: &mut Context<Self>,
22790    ) {
22791        self.request_autoscroll(Autoscroll::newest(), cx);
22792        let position = self
22793            .selections
22794            .newest_display(&self.display_snapshot(cx))
22795            .start;
22796        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22797    }
22798
22799    pub fn replay_insert_event(
22800        &mut self,
22801        text: &str,
22802        relative_utf16_range: Option<Range<isize>>,
22803        window: &mut Window,
22804        cx: &mut Context<Self>,
22805    ) {
22806        if !self.input_enabled {
22807            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22808            return;
22809        }
22810        if let Some(relative_utf16_range) = relative_utf16_range {
22811            let selections = self
22812                .selections
22813                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22814            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22815                let new_ranges = selections.into_iter().map(|range| {
22816                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22817                        range
22818                            .head()
22819                            .0
22820                            .0
22821                            .saturating_add_signed(relative_utf16_range.start),
22822                    ));
22823                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22824                        range
22825                            .head()
22826                            .0
22827                            .0
22828                            .saturating_add_signed(relative_utf16_range.end),
22829                    ));
22830                    start..end
22831                });
22832                s.select_ranges(new_ranges);
22833            });
22834        }
22835
22836        self.handle_input(text, window, cx);
22837    }
22838
22839    pub fn is_focused(&self, window: &Window) -> bool {
22840        self.focus_handle.is_focused(window)
22841    }
22842
22843    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22844        cx.emit(EditorEvent::Focused);
22845
22846        if let Some(descendant) = self
22847            .last_focused_descendant
22848            .take()
22849            .and_then(|descendant| descendant.upgrade())
22850        {
22851            window.focus(&descendant, cx);
22852        } else {
22853            if let Some(blame) = self.blame.as_ref() {
22854                blame.update(cx, GitBlame::focus)
22855            }
22856
22857            self.blink_manager.update(cx, BlinkManager::enable);
22858            self.show_cursor_names(window, cx);
22859            self.buffer.update(cx, |buffer, cx| {
22860                buffer.finalize_last_transaction(cx);
22861                if self.leader_id.is_none() {
22862                    buffer.set_active_selections(
22863                        &self.selections.disjoint_anchors_arc(),
22864                        self.selections.line_mode(),
22865                        self.cursor_shape,
22866                        cx,
22867                    );
22868                }
22869            });
22870
22871            if let Some(position_map) = self.last_position_map.clone() {
22872                EditorElement::mouse_moved(
22873                    self,
22874                    &MouseMoveEvent {
22875                        position: window.mouse_position(),
22876                        pressed_button: None,
22877                        modifiers: window.modifiers(),
22878                    },
22879                    &position_map,
22880                    window,
22881                    cx,
22882                );
22883            }
22884        }
22885    }
22886
22887    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22888        cx.emit(EditorEvent::FocusedIn)
22889    }
22890
22891    fn handle_focus_out(
22892        &mut self,
22893        event: FocusOutEvent,
22894        _window: &mut Window,
22895        cx: &mut Context<Self>,
22896    ) {
22897        if event.blurred != self.focus_handle {
22898            self.last_focused_descendant = Some(event.blurred);
22899        }
22900        self.selection_drag_state = SelectionDragState::None;
22901        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22902    }
22903
22904    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22905        self.blink_manager.update(cx, BlinkManager::disable);
22906        self.buffer
22907            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22908
22909        if let Some(blame) = self.blame.as_ref() {
22910            blame.update(cx, GitBlame::blur)
22911        }
22912        if !self.hover_state.focused(window, cx) {
22913            hide_hover(self, cx);
22914        }
22915        if !self
22916            .context_menu
22917            .borrow()
22918            .as_ref()
22919            .is_some_and(|context_menu| context_menu.focused(window, cx))
22920        {
22921            self.hide_context_menu(window, cx);
22922        }
22923        self.take_active_edit_prediction(cx);
22924        cx.emit(EditorEvent::Blurred);
22925        cx.notify();
22926    }
22927
22928    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22929        let mut pending: String = window
22930            .pending_input_keystrokes()
22931            .into_iter()
22932            .flatten()
22933            .filter_map(|keystroke| keystroke.key_char.clone())
22934            .collect();
22935
22936        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22937            pending = "".to_string();
22938        }
22939
22940        let existing_pending = self
22941            .text_highlights::<PendingInput>(cx)
22942            .map(|(_, ranges)| ranges.to_vec());
22943        if existing_pending.is_none() && pending.is_empty() {
22944            return;
22945        }
22946        let transaction =
22947            self.transact(window, cx, |this, window, cx| {
22948                let selections = this
22949                    .selections
22950                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22951                let edits = selections
22952                    .iter()
22953                    .map(|selection| (selection.end..selection.end, pending.clone()));
22954                this.edit(edits, cx);
22955                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22956                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22957                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22958                    }));
22959                });
22960                if let Some(existing_ranges) = existing_pending {
22961                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22962                    this.edit(edits, cx);
22963                }
22964            });
22965
22966        let snapshot = self.snapshot(window, cx);
22967        let ranges = self
22968            .selections
22969            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22970            .into_iter()
22971            .map(|selection| {
22972                snapshot.buffer_snapshot().anchor_after(selection.end)
22973                    ..snapshot
22974                        .buffer_snapshot()
22975                        .anchor_before(selection.end + pending.len())
22976            })
22977            .collect();
22978
22979        if pending.is_empty() {
22980            self.clear_highlights::<PendingInput>(cx);
22981        } else {
22982            self.highlight_text::<PendingInput>(
22983                ranges,
22984                HighlightStyle {
22985                    underline: Some(UnderlineStyle {
22986                        thickness: px(1.),
22987                        color: None,
22988                        wavy: false,
22989                    }),
22990                    ..Default::default()
22991                },
22992                cx,
22993            );
22994        }
22995
22996        self.ime_transaction = self.ime_transaction.or(transaction);
22997        if let Some(transaction) = self.ime_transaction {
22998            self.buffer.update(cx, |buffer, cx| {
22999                buffer.group_until_transaction(transaction, cx);
23000            });
23001        }
23002
23003        if self.text_highlights::<PendingInput>(cx).is_none() {
23004            self.ime_transaction.take();
23005        }
23006    }
23007
23008    pub fn register_action_renderer(
23009        &mut self,
23010        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23011    ) -> Subscription {
23012        let id = self.next_editor_action_id.post_inc();
23013        self.editor_actions
23014            .borrow_mut()
23015            .insert(id, Box::new(listener));
23016
23017        let editor_actions = self.editor_actions.clone();
23018        Subscription::new(move || {
23019            editor_actions.borrow_mut().remove(&id);
23020        })
23021    }
23022
23023    pub fn register_action<A: Action>(
23024        &mut self,
23025        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23026    ) -> Subscription {
23027        let id = self.next_editor_action_id.post_inc();
23028        let listener = Arc::new(listener);
23029        self.editor_actions.borrow_mut().insert(
23030            id,
23031            Box::new(move |_, window, _| {
23032                let listener = listener.clone();
23033                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23034                    let action = action.downcast_ref().unwrap();
23035                    if phase == DispatchPhase::Bubble {
23036                        listener(action, window, cx)
23037                    }
23038                })
23039            }),
23040        );
23041
23042        let editor_actions = self.editor_actions.clone();
23043        Subscription::new(move || {
23044            editor_actions.borrow_mut().remove(&id);
23045        })
23046    }
23047
23048    pub fn file_header_size(&self) -> u32 {
23049        FILE_HEADER_HEIGHT
23050    }
23051
23052    pub fn restore(
23053        &mut self,
23054        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23055        window: &mut Window,
23056        cx: &mut Context<Self>,
23057    ) {
23058        self.buffer().update(cx, |multi_buffer, cx| {
23059            for (buffer_id, changes) in revert_changes {
23060                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23061                    buffer.update(cx, |buffer, cx| {
23062                        buffer.edit(
23063                            changes
23064                                .into_iter()
23065                                .map(|(range, text)| (range, text.to_string())),
23066                            None,
23067                            cx,
23068                        );
23069                    });
23070                }
23071            }
23072        });
23073        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23074            selections.refresh()
23075        });
23076    }
23077
23078    pub fn to_pixel_point(
23079        &mut self,
23080        source: multi_buffer::Anchor,
23081        editor_snapshot: &EditorSnapshot,
23082        window: &mut Window,
23083        cx: &App,
23084    ) -> Option<gpui::Point<Pixels>> {
23085        let source_point = source.to_display_point(editor_snapshot);
23086        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23087    }
23088
23089    pub fn display_to_pixel_point(
23090        &mut self,
23091        source: DisplayPoint,
23092        editor_snapshot: &EditorSnapshot,
23093        window: &mut Window,
23094        cx: &App,
23095    ) -> Option<gpui::Point<Pixels>> {
23096        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23097        let text_layout_details = self.text_layout_details(window);
23098        let scroll_top = text_layout_details
23099            .scroll_anchor
23100            .scroll_position(editor_snapshot)
23101            .y;
23102
23103        if source.row().as_f64() < scroll_top.floor() {
23104            return None;
23105        }
23106        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23107        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23108        Some(gpui::Point::new(source_x, source_y))
23109    }
23110
23111    pub fn has_visible_completions_menu(&self) -> bool {
23112        !self.edit_prediction_preview_is_active()
23113            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23114                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23115            })
23116    }
23117
23118    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23119        if self.mode.is_minimap() {
23120            return;
23121        }
23122        self.addons
23123            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23124    }
23125
23126    pub fn unregister_addon<T: Addon>(&mut self) {
23127        self.addons.remove(&std::any::TypeId::of::<T>());
23128    }
23129
23130    pub fn addon<T: Addon>(&self) -> Option<&T> {
23131        let type_id = std::any::TypeId::of::<T>();
23132        self.addons
23133            .get(&type_id)
23134            .and_then(|item| item.to_any().downcast_ref::<T>())
23135    }
23136
23137    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23138        let type_id = std::any::TypeId::of::<T>();
23139        self.addons
23140            .get_mut(&type_id)
23141            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23142    }
23143
23144    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23145        let text_layout_details = self.text_layout_details(window);
23146        let style = &text_layout_details.editor_style;
23147        let font_id = window.text_system().resolve_font(&style.text.font());
23148        let font_size = style.text.font_size.to_pixels(window.rem_size());
23149        let line_height = style.text.line_height_in_pixels(window.rem_size());
23150        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23151        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23152
23153        CharacterDimensions {
23154            em_width,
23155            em_advance,
23156            line_height,
23157        }
23158    }
23159
23160    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23161        self.load_diff_task.clone()
23162    }
23163
23164    fn read_metadata_from_db(
23165        &mut self,
23166        item_id: u64,
23167        workspace_id: WorkspaceId,
23168        window: &mut Window,
23169        cx: &mut Context<Editor>,
23170    ) {
23171        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23172            && !self.mode.is_minimap()
23173            && WorkspaceSettings::get(None, cx).restore_on_startup
23174                != RestoreOnStartupBehavior::EmptyTab
23175        {
23176            let buffer_snapshot = OnceCell::new();
23177
23178            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23179                && !folds.is_empty()
23180            {
23181                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23182                self.fold_ranges(
23183                    folds
23184                        .into_iter()
23185                        .map(|(start, end)| {
23186                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23187                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23188                        })
23189                        .collect(),
23190                    false,
23191                    window,
23192                    cx,
23193                );
23194            }
23195
23196            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23197                && !selections.is_empty()
23198            {
23199                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23200                // skip adding the initial selection to selection history
23201                self.selection_history.mode = SelectionHistoryMode::Skipping;
23202                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23203                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23204                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23205                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23206                    }));
23207                });
23208                self.selection_history.mode = SelectionHistoryMode::Normal;
23209            };
23210        }
23211
23212        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23213    }
23214
23215    fn update_lsp_data(
23216        &mut self,
23217        for_buffer: Option<BufferId>,
23218        window: &mut Window,
23219        cx: &mut Context<'_, Self>,
23220    ) {
23221        self.pull_diagnostics(for_buffer, window, cx);
23222        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23223    }
23224
23225    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23226        if self.ignore_lsp_data() {
23227            return;
23228        }
23229        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23230            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23231        }
23232    }
23233
23234    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23235        if self.ignore_lsp_data() {
23236            return;
23237        }
23238
23239        if !self.registered_buffers.contains_key(&buffer_id)
23240            && let Some(project) = self.project.as_ref()
23241        {
23242            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23243                project.update(cx, |project, cx| {
23244                    self.registered_buffers.insert(
23245                        buffer_id,
23246                        project.register_buffer_with_language_servers(&buffer, cx),
23247                    );
23248                });
23249            } else {
23250                self.registered_buffers.remove(&buffer_id);
23251            }
23252        }
23253    }
23254
23255    fn ignore_lsp_data(&self) -> bool {
23256        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23257        // skip any LSP updates for it.
23258        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23259    }
23260
23261    fn create_style(&self, cx: &App) -> EditorStyle {
23262        let settings = ThemeSettings::get_global(cx);
23263
23264        let mut text_style = match self.mode {
23265            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23266                color: cx.theme().colors().editor_foreground,
23267                font_family: settings.ui_font.family.clone(),
23268                font_features: settings.ui_font.features.clone(),
23269                font_fallbacks: settings.ui_font.fallbacks.clone(),
23270                font_size: rems(0.875).into(),
23271                font_weight: settings.ui_font.weight,
23272                line_height: relative(settings.buffer_line_height.value()),
23273                ..Default::default()
23274            },
23275            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23276                color: cx.theme().colors().editor_foreground,
23277                font_family: settings.buffer_font.family.clone(),
23278                font_features: settings.buffer_font.features.clone(),
23279                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23280                font_size: settings.buffer_font_size(cx).into(),
23281                font_weight: settings.buffer_font.weight,
23282                line_height: relative(settings.buffer_line_height.value()),
23283                ..Default::default()
23284            },
23285        };
23286        if let Some(text_style_refinement) = &self.text_style_refinement {
23287            text_style.refine(text_style_refinement)
23288        }
23289
23290        let background = match self.mode {
23291            EditorMode::SingleLine => cx.theme().system().transparent,
23292            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23293            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23294            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23295        };
23296
23297        EditorStyle {
23298            background,
23299            border: cx.theme().colors().border,
23300            local_player: cx.theme().players().local(),
23301            text: text_style,
23302            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23303            syntax: cx.theme().syntax().clone(),
23304            status: cx.theme().status().clone(),
23305            inlay_hints_style: make_inlay_hints_style(cx),
23306            edit_prediction_styles: make_suggestion_styles(cx),
23307            unnecessary_code_fade: settings.unnecessary_code_fade,
23308            show_underlines: self.diagnostics_enabled(),
23309        }
23310    }
23311    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23312        let cursor = self.selections.newest_anchor().head();
23313        let multibuffer = self.buffer().read(cx);
23314        let is_singleton = multibuffer.is_singleton();
23315        let (buffer_id, symbols) = multibuffer
23316            .read(cx)
23317            .symbols_containing(cursor, Some(variant.syntax()))?;
23318        let buffer = multibuffer.buffer(buffer_id)?;
23319
23320        let buffer = buffer.read(cx);
23321        let settings = ThemeSettings::get_global(cx);
23322        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23323        let mut breadcrumbs = if is_singleton {
23324            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23325                buffer
23326                    .snapshot()
23327                    .resolve_file_path(
23328                        self.project
23329                            .as_ref()
23330                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23331                            .unwrap_or_default(),
23332                        cx,
23333                    )
23334                    .unwrap_or_else(|| {
23335                        if multibuffer.is_singleton() {
23336                            multibuffer.title(cx).to_string()
23337                        } else {
23338                            "untitled".to_string()
23339                        }
23340                    })
23341            });
23342            vec![BreadcrumbText {
23343                text,
23344                highlights: None,
23345                font: Some(settings.buffer_font.clone()),
23346            }]
23347        } else {
23348            vec![]
23349        };
23350
23351        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23352            text: symbol.text,
23353            highlights: Some(symbol.highlight_ranges),
23354            font: Some(settings.buffer_font.clone()),
23355        }));
23356        Some(breadcrumbs)
23357    }
23358}
23359
23360fn edit_for_markdown_paste<'a>(
23361    buffer: &MultiBufferSnapshot,
23362    range: Range<MultiBufferOffset>,
23363    to_insert: &'a str,
23364    url: Option<url::Url>,
23365) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23366    if url.is_none() {
23367        return (range, Cow::Borrowed(to_insert));
23368    };
23369
23370    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23371
23372    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23373        Cow::Borrowed(to_insert)
23374    } else {
23375        Cow::Owned(format!("[{old_text}]({to_insert})"))
23376    };
23377    (range, new_text)
23378}
23379
23380fn process_completion_for_edit(
23381    completion: &Completion,
23382    intent: CompletionIntent,
23383    buffer: &Entity<Buffer>,
23384    cursor_position: &text::Anchor,
23385    cx: &mut Context<Editor>,
23386) -> CompletionEdit {
23387    let buffer = buffer.read(cx);
23388    let buffer_snapshot = buffer.snapshot();
23389    let (snippet, new_text) = if completion.is_snippet() {
23390        let mut snippet_source = completion.new_text.clone();
23391        // Workaround for typescript language server issues so that methods don't expand within
23392        // strings and functions with type expressions. The previous point is used because the query
23393        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23394        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23395        let previous_point = if previous_point.column > 0 {
23396            cursor_position.to_previous_offset(&buffer_snapshot)
23397        } else {
23398            cursor_position.to_offset(&buffer_snapshot)
23399        };
23400        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23401            && scope.prefers_label_for_snippet_in_completion()
23402            && let Some(label) = completion.label()
23403            && matches!(
23404                completion.kind(),
23405                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23406            )
23407        {
23408            snippet_source = label;
23409        }
23410        match Snippet::parse(&snippet_source).log_err() {
23411            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23412            None => (None, completion.new_text.clone()),
23413        }
23414    } else {
23415        (None, completion.new_text.clone())
23416    };
23417
23418    let mut range_to_replace = {
23419        let replace_range = &completion.replace_range;
23420        if let CompletionSource::Lsp {
23421            insert_range: Some(insert_range),
23422            ..
23423        } = &completion.source
23424        {
23425            debug_assert_eq!(
23426                insert_range.start, replace_range.start,
23427                "insert_range and replace_range should start at the same position"
23428            );
23429            debug_assert!(
23430                insert_range
23431                    .start
23432                    .cmp(cursor_position, &buffer_snapshot)
23433                    .is_le(),
23434                "insert_range should start before or at cursor position"
23435            );
23436            debug_assert!(
23437                replace_range
23438                    .start
23439                    .cmp(cursor_position, &buffer_snapshot)
23440                    .is_le(),
23441                "replace_range should start before or at cursor position"
23442            );
23443
23444            let should_replace = match intent {
23445                CompletionIntent::CompleteWithInsert => false,
23446                CompletionIntent::CompleteWithReplace => true,
23447                CompletionIntent::Complete | CompletionIntent::Compose => {
23448                    let insert_mode =
23449                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23450                            .completions
23451                            .lsp_insert_mode;
23452                    match insert_mode {
23453                        LspInsertMode::Insert => false,
23454                        LspInsertMode::Replace => true,
23455                        LspInsertMode::ReplaceSubsequence => {
23456                            let mut text_to_replace = buffer.chars_for_range(
23457                                buffer.anchor_before(replace_range.start)
23458                                    ..buffer.anchor_after(replace_range.end),
23459                            );
23460                            let mut current_needle = text_to_replace.next();
23461                            for haystack_ch in completion.label.text.chars() {
23462                                if let Some(needle_ch) = current_needle
23463                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23464                                {
23465                                    current_needle = text_to_replace.next();
23466                                }
23467                            }
23468                            current_needle.is_none()
23469                        }
23470                        LspInsertMode::ReplaceSuffix => {
23471                            if replace_range
23472                                .end
23473                                .cmp(cursor_position, &buffer_snapshot)
23474                                .is_gt()
23475                            {
23476                                let range_after_cursor = *cursor_position..replace_range.end;
23477                                let text_after_cursor = buffer
23478                                    .text_for_range(
23479                                        buffer.anchor_before(range_after_cursor.start)
23480                                            ..buffer.anchor_after(range_after_cursor.end),
23481                                    )
23482                                    .collect::<String>()
23483                                    .to_ascii_lowercase();
23484                                completion
23485                                    .label
23486                                    .text
23487                                    .to_ascii_lowercase()
23488                                    .ends_with(&text_after_cursor)
23489                            } else {
23490                                true
23491                            }
23492                        }
23493                    }
23494                }
23495            };
23496
23497            if should_replace {
23498                replace_range.clone()
23499            } else {
23500                insert_range.clone()
23501            }
23502        } else {
23503            replace_range.clone()
23504        }
23505    };
23506
23507    if range_to_replace
23508        .end
23509        .cmp(cursor_position, &buffer_snapshot)
23510        .is_lt()
23511    {
23512        range_to_replace.end = *cursor_position;
23513    }
23514
23515    let replace_range = range_to_replace.to_offset(buffer);
23516    CompletionEdit {
23517        new_text,
23518        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23519        snippet,
23520    }
23521}
23522
23523struct CompletionEdit {
23524    new_text: String,
23525    replace_range: Range<BufferOffset>,
23526    snippet: Option<Snippet>,
23527}
23528
23529fn comment_delimiter_for_newline(
23530    start_point: &Point,
23531    buffer: &MultiBufferSnapshot,
23532    language: &LanguageScope,
23533) -> Option<Arc<str>> {
23534    let delimiters = language.line_comment_prefixes();
23535    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23536    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23537
23538    let num_of_whitespaces = snapshot
23539        .chars_for_range(range.clone())
23540        .take_while(|c| c.is_whitespace())
23541        .count();
23542    let comment_candidate = snapshot
23543        .chars_for_range(range.clone())
23544        .skip(num_of_whitespaces)
23545        .take(max_len_of_delimiter)
23546        .collect::<String>();
23547    let (delimiter, trimmed_len) = delimiters
23548        .iter()
23549        .filter_map(|delimiter| {
23550            let prefix = delimiter.trim_end();
23551            if comment_candidate.starts_with(prefix) {
23552                Some((delimiter, prefix.len()))
23553            } else {
23554                None
23555            }
23556        })
23557        .max_by_key(|(_, len)| *len)?;
23558
23559    if let Some(BlockCommentConfig {
23560        start: block_start, ..
23561    }) = language.block_comment()
23562    {
23563        let block_start_trimmed = block_start.trim_end();
23564        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23565            let line_content = snapshot
23566                .chars_for_range(range)
23567                .skip(num_of_whitespaces)
23568                .take(block_start_trimmed.len())
23569                .collect::<String>();
23570
23571            if line_content.starts_with(block_start_trimmed) {
23572                return None;
23573            }
23574        }
23575    }
23576
23577    let cursor_is_placed_after_comment_marker =
23578        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23579    if cursor_is_placed_after_comment_marker {
23580        Some(delimiter.clone())
23581    } else {
23582        None
23583    }
23584}
23585
23586fn documentation_delimiter_for_newline(
23587    start_point: &Point,
23588    buffer: &MultiBufferSnapshot,
23589    language: &LanguageScope,
23590    newline_config: &mut NewlineConfig,
23591) -> Option<Arc<str>> {
23592    let BlockCommentConfig {
23593        start: start_tag,
23594        end: end_tag,
23595        prefix: delimiter,
23596        tab_size: len,
23597    } = language.documentation_comment()?;
23598    let is_within_block_comment = buffer
23599        .language_scope_at(*start_point)
23600        .is_some_and(|scope| scope.override_name() == Some("comment"));
23601    if !is_within_block_comment {
23602        return None;
23603    }
23604
23605    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23606
23607    let num_of_whitespaces = snapshot
23608        .chars_for_range(range.clone())
23609        .take_while(|c| c.is_whitespace())
23610        .count();
23611
23612    // 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.
23613    let column = start_point.column;
23614    let cursor_is_after_start_tag = {
23615        let start_tag_len = start_tag.len();
23616        let start_tag_line = snapshot
23617            .chars_for_range(range.clone())
23618            .skip(num_of_whitespaces)
23619            .take(start_tag_len)
23620            .collect::<String>();
23621        if start_tag_line.starts_with(start_tag.as_ref()) {
23622            num_of_whitespaces + start_tag_len <= column as usize
23623        } else {
23624            false
23625        }
23626    };
23627
23628    let cursor_is_after_delimiter = {
23629        let delimiter_trim = delimiter.trim_end();
23630        let delimiter_line = snapshot
23631            .chars_for_range(range.clone())
23632            .skip(num_of_whitespaces)
23633            .take(delimiter_trim.len())
23634            .collect::<String>();
23635        if delimiter_line.starts_with(delimiter_trim) {
23636            num_of_whitespaces + delimiter_trim.len() <= column as usize
23637        } else {
23638            false
23639        }
23640    };
23641
23642    let mut needs_extra_line = false;
23643    let mut extra_line_additional_indent = IndentSize::spaces(0);
23644
23645    let cursor_is_before_end_tag_if_exists = {
23646        let mut char_position = 0u32;
23647        let mut end_tag_offset = None;
23648
23649        'outer: for chunk in snapshot.text_for_range(range) {
23650            if let Some(byte_pos) = chunk.find(&**end_tag) {
23651                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23652                end_tag_offset = Some(char_position + chars_before_match);
23653                break 'outer;
23654            }
23655            char_position += chunk.chars().count() as u32;
23656        }
23657
23658        if let Some(end_tag_offset) = end_tag_offset {
23659            let cursor_is_before_end_tag = column <= end_tag_offset;
23660            if cursor_is_after_start_tag {
23661                if cursor_is_before_end_tag {
23662                    needs_extra_line = true;
23663                }
23664                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23665                if cursor_is_at_start_of_end_tag {
23666                    extra_line_additional_indent.len = *len;
23667                }
23668            }
23669            cursor_is_before_end_tag
23670        } else {
23671            true
23672        }
23673    };
23674
23675    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23676        && cursor_is_before_end_tag_if_exists
23677    {
23678        let additional_indent = if cursor_is_after_start_tag {
23679            IndentSize::spaces(*len)
23680        } else {
23681            IndentSize::spaces(0)
23682        };
23683
23684        *newline_config = NewlineConfig::Newline {
23685            additional_indent,
23686            extra_line_additional_indent: if needs_extra_line {
23687                Some(extra_line_additional_indent)
23688            } else {
23689                None
23690            },
23691            prevent_auto_indent: true,
23692        };
23693        Some(delimiter.clone())
23694    } else {
23695        None
23696    }
23697}
23698
23699const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23700
23701fn list_delimiter_for_newline(
23702    start_point: &Point,
23703    buffer: &MultiBufferSnapshot,
23704    language: &LanguageScope,
23705    newline_config: &mut NewlineConfig,
23706) -> Option<Arc<str>> {
23707    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23708
23709    let num_of_whitespaces = snapshot
23710        .chars_for_range(range.clone())
23711        .take_while(|c| c.is_whitespace())
23712        .count();
23713
23714    let task_list_entries: Vec<_> = language
23715        .task_list()
23716        .into_iter()
23717        .flat_map(|config| {
23718            config
23719                .prefixes
23720                .iter()
23721                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23722        })
23723        .collect();
23724    let unordered_list_entries: Vec<_> = language
23725        .unordered_list()
23726        .iter()
23727        .map(|marker| (marker.as_ref(), marker.as_ref()))
23728        .collect();
23729
23730    let all_entries: Vec<_> = task_list_entries
23731        .into_iter()
23732        .chain(unordered_list_entries)
23733        .collect();
23734
23735    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23736        let candidate: String = snapshot
23737            .chars_for_range(range.clone())
23738            .skip(num_of_whitespaces)
23739            .take(max_prefix_len)
23740            .collect();
23741
23742        if let Some((prefix, continuation)) = all_entries
23743            .iter()
23744            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23745            .max_by_key(|(prefix, _)| prefix.len())
23746        {
23747            let end_of_prefix = num_of_whitespaces + prefix.len();
23748            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23749            let has_content_after_marker = snapshot
23750                .chars_for_range(range)
23751                .skip(end_of_prefix)
23752                .any(|c| !c.is_whitespace());
23753
23754            if has_content_after_marker && cursor_is_after_prefix {
23755                return Some((*continuation).into());
23756            }
23757
23758            if start_point.column as usize == end_of_prefix {
23759                if num_of_whitespaces == 0 {
23760                    *newline_config = NewlineConfig::ClearCurrentLine;
23761                } else {
23762                    *newline_config = NewlineConfig::UnindentCurrentLine {
23763                        continuation: (*continuation).into(),
23764                    };
23765                }
23766            }
23767
23768            return None;
23769        }
23770    }
23771
23772    let candidate: String = snapshot
23773        .chars_for_range(range.clone())
23774        .skip(num_of_whitespaces)
23775        .take(ORDERED_LIST_MAX_MARKER_LEN)
23776        .collect();
23777
23778    for ordered_config in language.ordered_list() {
23779        let regex = match Regex::new(&ordered_config.pattern) {
23780            Ok(r) => r,
23781            Err(_) => continue,
23782        };
23783
23784        if let Some(captures) = regex.captures(&candidate) {
23785            let full_match = captures.get(0)?;
23786            let marker_len = full_match.len();
23787            let end_of_prefix = num_of_whitespaces + marker_len;
23788            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23789
23790            let has_content_after_marker = snapshot
23791                .chars_for_range(range)
23792                .skip(end_of_prefix)
23793                .any(|c| !c.is_whitespace());
23794
23795            if has_content_after_marker && cursor_is_after_prefix {
23796                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23797                let continuation = ordered_config
23798                    .format
23799                    .replace("{1}", &(number + 1).to_string());
23800                return Some(continuation.into());
23801            }
23802
23803            if start_point.column as usize == end_of_prefix {
23804                let continuation = ordered_config.format.replace("{1}", "1");
23805                if num_of_whitespaces == 0 {
23806                    *newline_config = NewlineConfig::ClearCurrentLine;
23807                } else {
23808                    *newline_config = NewlineConfig::UnindentCurrentLine {
23809                        continuation: continuation.into(),
23810                    };
23811                }
23812            }
23813
23814            return None;
23815        }
23816    }
23817
23818    None
23819}
23820
23821fn is_list_prefix_row(
23822    row: MultiBufferRow,
23823    buffer: &MultiBufferSnapshot,
23824    language: &LanguageScope,
23825) -> bool {
23826    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23827        return false;
23828    };
23829
23830    let num_of_whitespaces = snapshot
23831        .chars_for_range(range.clone())
23832        .take_while(|c| c.is_whitespace())
23833        .count();
23834
23835    let task_list_prefixes: Vec<_> = language
23836        .task_list()
23837        .into_iter()
23838        .flat_map(|config| {
23839            config
23840                .prefixes
23841                .iter()
23842                .map(|p| p.as_ref())
23843                .collect::<Vec<_>>()
23844        })
23845        .collect();
23846    let unordered_list_markers: Vec<_> = language
23847        .unordered_list()
23848        .iter()
23849        .map(|marker| marker.as_ref())
23850        .collect();
23851    let all_prefixes: Vec<_> = task_list_prefixes
23852        .into_iter()
23853        .chain(unordered_list_markers)
23854        .collect();
23855    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23856        let candidate: String = snapshot
23857            .chars_for_range(range.clone())
23858            .skip(num_of_whitespaces)
23859            .take(max_prefix_len)
23860            .collect();
23861        if all_prefixes
23862            .iter()
23863            .any(|prefix| candidate.starts_with(*prefix))
23864        {
23865            return true;
23866        }
23867    }
23868
23869    let ordered_list_candidate: String = snapshot
23870        .chars_for_range(range)
23871        .skip(num_of_whitespaces)
23872        .take(ORDERED_LIST_MAX_MARKER_LEN)
23873        .collect();
23874    for ordered_config in language.ordered_list() {
23875        let regex = match Regex::new(&ordered_config.pattern) {
23876            Ok(r) => r,
23877            Err(_) => continue,
23878        };
23879        if let Some(captures) = regex.captures(&ordered_list_candidate) {
23880            return captures.get(0).is_some();
23881        }
23882    }
23883
23884    false
23885}
23886
23887#[derive(Debug)]
23888enum NewlineConfig {
23889    /// Insert newline with optional additional indent and optional extra blank line
23890    Newline {
23891        additional_indent: IndentSize,
23892        extra_line_additional_indent: Option<IndentSize>,
23893        prevent_auto_indent: bool,
23894    },
23895    /// Clear the current line
23896    ClearCurrentLine,
23897    /// Unindent the current line and add continuation
23898    UnindentCurrentLine { continuation: Arc<str> },
23899}
23900
23901impl NewlineConfig {
23902    fn has_extra_line(&self) -> bool {
23903        matches!(
23904            self,
23905            Self::Newline {
23906                extra_line_additional_indent: Some(_),
23907                ..
23908            }
23909        )
23910    }
23911
23912    fn insert_extra_newline_brackets(
23913        buffer: &MultiBufferSnapshot,
23914        range: Range<MultiBufferOffset>,
23915        language: &language::LanguageScope,
23916    ) -> bool {
23917        let leading_whitespace_len = buffer
23918            .reversed_chars_at(range.start)
23919            .take_while(|c| c.is_whitespace() && *c != '\n')
23920            .map(|c| c.len_utf8())
23921            .sum::<usize>();
23922        let trailing_whitespace_len = buffer
23923            .chars_at(range.end)
23924            .take_while(|c| c.is_whitespace() && *c != '\n')
23925            .map(|c| c.len_utf8())
23926            .sum::<usize>();
23927        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23928
23929        language.brackets().any(|(pair, enabled)| {
23930            let pair_start = pair.start.trim_end();
23931            let pair_end = pair.end.trim_start();
23932
23933            enabled
23934                && pair.newline
23935                && buffer.contains_str_at(range.end, pair_end)
23936                && buffer.contains_str_at(
23937                    range.start.saturating_sub_usize(pair_start.len()),
23938                    pair_start,
23939                )
23940        })
23941    }
23942
23943    fn insert_extra_newline_tree_sitter(
23944        buffer: &MultiBufferSnapshot,
23945        range: Range<MultiBufferOffset>,
23946    ) -> bool {
23947        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23948            [(buffer, range, _)] => (*buffer, range.clone()),
23949            _ => return false,
23950        };
23951        let pair = {
23952            let mut result: Option<BracketMatch<usize>> = None;
23953
23954            for pair in buffer
23955                .all_bracket_ranges(range.start.0..range.end.0)
23956                .filter(move |pair| {
23957                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23958                })
23959            {
23960                let len = pair.close_range.end - pair.open_range.start;
23961
23962                if let Some(existing) = &result {
23963                    let existing_len = existing.close_range.end - existing.open_range.start;
23964                    if len > existing_len {
23965                        continue;
23966                    }
23967                }
23968
23969                result = Some(pair);
23970            }
23971
23972            result
23973        };
23974        let Some(pair) = pair else {
23975            return false;
23976        };
23977        pair.newline_only
23978            && buffer
23979                .chars_for_range(pair.open_range.end..range.start.0)
23980                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23981                .all(|c| c.is_whitespace() && c != '\n')
23982    }
23983}
23984
23985fn update_uncommitted_diff_for_buffer(
23986    editor: Entity<Editor>,
23987    project: &Entity<Project>,
23988    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23989    buffer: Entity<MultiBuffer>,
23990    cx: &mut App,
23991) -> Task<()> {
23992    let mut tasks = Vec::new();
23993    project.update(cx, |project, cx| {
23994        for buffer in buffers {
23995            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23996                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23997            }
23998        }
23999    });
24000    cx.spawn(async move |cx| {
24001        let diffs = future::join_all(tasks).await;
24002        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
24003            return;
24004        }
24005
24006        buffer.update(cx, |buffer, cx| {
24007            for diff in diffs.into_iter().flatten() {
24008                buffer.add_diff(diff, cx);
24009            }
24010        });
24011    })
24012}
24013
24014fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
24015    let tab_size = tab_size.get() as usize;
24016    let mut width = offset;
24017
24018    for ch in text.chars() {
24019        width += if ch == '\t' {
24020            tab_size - (width % tab_size)
24021        } else {
24022            1
24023        };
24024    }
24025
24026    width - offset
24027}
24028
24029#[cfg(test)]
24030mod tests {
24031    use super::*;
24032
24033    #[test]
24034    fn test_string_size_with_expanded_tabs() {
24035        let nz = |val| NonZeroU32::new(val).unwrap();
24036        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24037        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24038        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24039        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24040        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24041        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24042        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24043        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24044    }
24045}
24046
24047/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24048struct WordBreakingTokenizer<'a> {
24049    input: &'a str,
24050}
24051
24052impl<'a> WordBreakingTokenizer<'a> {
24053    fn new(input: &'a str) -> Self {
24054        Self { input }
24055    }
24056}
24057
24058fn is_char_ideographic(ch: char) -> bool {
24059    use unicode_script::Script::*;
24060    use unicode_script::UnicodeScript;
24061    matches!(ch.script(), Han | Tangut | Yi)
24062}
24063
24064fn is_grapheme_ideographic(text: &str) -> bool {
24065    text.chars().any(is_char_ideographic)
24066}
24067
24068fn is_grapheme_whitespace(text: &str) -> bool {
24069    text.chars().any(|x| x.is_whitespace())
24070}
24071
24072fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24073    text.chars()
24074        .next()
24075        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24076}
24077
24078#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24079enum WordBreakToken<'a> {
24080    Word { token: &'a str, grapheme_len: usize },
24081    InlineWhitespace { token: &'a str, grapheme_len: usize },
24082    Newline,
24083}
24084
24085impl<'a> Iterator for WordBreakingTokenizer<'a> {
24086    /// Yields a span, the count of graphemes in the token, and whether it was
24087    /// whitespace. Note that it also breaks at word boundaries.
24088    type Item = WordBreakToken<'a>;
24089
24090    fn next(&mut self) -> Option<Self::Item> {
24091        use unicode_segmentation::UnicodeSegmentation;
24092        if self.input.is_empty() {
24093            return None;
24094        }
24095
24096        let mut iter = self.input.graphemes(true).peekable();
24097        let mut offset = 0;
24098        let mut grapheme_len = 0;
24099        if let Some(first_grapheme) = iter.next() {
24100            let is_newline = first_grapheme == "\n";
24101            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24102            offset += first_grapheme.len();
24103            grapheme_len += 1;
24104            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24105                if let Some(grapheme) = iter.peek().copied()
24106                    && should_stay_with_preceding_ideograph(grapheme)
24107                {
24108                    offset += grapheme.len();
24109                    grapheme_len += 1;
24110                }
24111            } else {
24112                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24113                let mut next_word_bound = words.peek().copied();
24114                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24115                    next_word_bound = words.next();
24116                }
24117                while let Some(grapheme) = iter.peek().copied() {
24118                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24119                        break;
24120                    };
24121                    if is_grapheme_whitespace(grapheme) != is_whitespace
24122                        || (grapheme == "\n") != is_newline
24123                    {
24124                        break;
24125                    };
24126                    offset += grapheme.len();
24127                    grapheme_len += 1;
24128                    iter.next();
24129                }
24130            }
24131            let token = &self.input[..offset];
24132            self.input = &self.input[offset..];
24133            if token == "\n" {
24134                Some(WordBreakToken::Newline)
24135            } else if is_whitespace {
24136                Some(WordBreakToken::InlineWhitespace {
24137                    token,
24138                    grapheme_len,
24139                })
24140            } else {
24141                Some(WordBreakToken::Word {
24142                    token,
24143                    grapheme_len,
24144                })
24145            }
24146        } else {
24147            None
24148        }
24149    }
24150}
24151
24152#[test]
24153fn test_word_breaking_tokenizer() {
24154    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24155        ("", &[]),
24156        ("  ", &[whitespace("  ", 2)]),
24157        ("Ʒ", &[word("Ʒ", 1)]),
24158        ("Ǽ", &[word("Ǽ", 1)]),
24159        ("", &[word("", 1)]),
24160        ("⋑⋑", &[word("⋑⋑", 2)]),
24161        (
24162            "原理,进而",
24163            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24164        ),
24165        (
24166            "hello world",
24167            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24168        ),
24169        (
24170            "hello, world",
24171            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24172        ),
24173        (
24174            "  hello world",
24175            &[
24176                whitespace("  ", 2),
24177                word("hello", 5),
24178                whitespace(" ", 1),
24179                word("world", 5),
24180            ],
24181        ),
24182        (
24183            "这是什么 \n 钢笔",
24184            &[
24185                word("", 1),
24186                word("", 1),
24187                word("", 1),
24188                word("", 1),
24189                whitespace(" ", 1),
24190                newline(),
24191                whitespace(" ", 1),
24192                word("", 1),
24193                word("", 1),
24194            ],
24195        ),
24196        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24197    ];
24198
24199    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24200        WordBreakToken::Word {
24201            token,
24202            grapheme_len,
24203        }
24204    }
24205
24206    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24207        WordBreakToken::InlineWhitespace {
24208            token,
24209            grapheme_len,
24210        }
24211    }
24212
24213    fn newline() -> WordBreakToken<'static> {
24214        WordBreakToken::Newline
24215    }
24216
24217    for (input, result) in tests {
24218        assert_eq!(
24219            WordBreakingTokenizer::new(input)
24220                .collect::<Vec<_>>()
24221                .as_slice(),
24222            *result,
24223        );
24224    }
24225}
24226
24227fn wrap_with_prefix(
24228    first_line_prefix: String,
24229    subsequent_lines_prefix: String,
24230    unwrapped_text: String,
24231    wrap_column: usize,
24232    tab_size: NonZeroU32,
24233    preserve_existing_whitespace: bool,
24234) -> String {
24235    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24236    let subsequent_lines_prefix_len =
24237        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24238    let mut wrapped_text = String::new();
24239    let mut current_line = first_line_prefix;
24240    let mut is_first_line = true;
24241
24242    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24243    let mut current_line_len = first_line_prefix_len;
24244    let mut in_whitespace = false;
24245    for token in tokenizer {
24246        let have_preceding_whitespace = in_whitespace;
24247        match token {
24248            WordBreakToken::Word {
24249                token,
24250                grapheme_len,
24251            } => {
24252                in_whitespace = false;
24253                let current_prefix_len = if is_first_line {
24254                    first_line_prefix_len
24255                } else {
24256                    subsequent_lines_prefix_len
24257                };
24258                if current_line_len + grapheme_len > wrap_column
24259                    && current_line_len != current_prefix_len
24260                {
24261                    wrapped_text.push_str(current_line.trim_end());
24262                    wrapped_text.push('\n');
24263                    is_first_line = false;
24264                    current_line = subsequent_lines_prefix.clone();
24265                    current_line_len = subsequent_lines_prefix_len;
24266                }
24267                current_line.push_str(token);
24268                current_line_len += grapheme_len;
24269            }
24270            WordBreakToken::InlineWhitespace {
24271                mut token,
24272                mut grapheme_len,
24273            } => {
24274                in_whitespace = true;
24275                if have_preceding_whitespace && !preserve_existing_whitespace {
24276                    continue;
24277                }
24278                if !preserve_existing_whitespace {
24279                    // Keep a single whitespace grapheme as-is
24280                    if let Some(first) =
24281                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24282                    {
24283                        token = first;
24284                    } else {
24285                        token = " ";
24286                    }
24287                    grapheme_len = 1;
24288                }
24289                let current_prefix_len = if is_first_line {
24290                    first_line_prefix_len
24291                } else {
24292                    subsequent_lines_prefix_len
24293                };
24294                if current_line_len + grapheme_len > wrap_column {
24295                    wrapped_text.push_str(current_line.trim_end());
24296                    wrapped_text.push('\n');
24297                    is_first_line = false;
24298                    current_line = subsequent_lines_prefix.clone();
24299                    current_line_len = subsequent_lines_prefix_len;
24300                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24301                    current_line.push_str(token);
24302                    current_line_len += grapheme_len;
24303                }
24304            }
24305            WordBreakToken::Newline => {
24306                in_whitespace = true;
24307                let current_prefix_len = if is_first_line {
24308                    first_line_prefix_len
24309                } else {
24310                    subsequent_lines_prefix_len
24311                };
24312                if preserve_existing_whitespace {
24313                    wrapped_text.push_str(current_line.trim_end());
24314                    wrapped_text.push('\n');
24315                    is_first_line = false;
24316                    current_line = subsequent_lines_prefix.clone();
24317                    current_line_len = subsequent_lines_prefix_len;
24318                } else if have_preceding_whitespace {
24319                    continue;
24320                } else if current_line_len + 1 > wrap_column
24321                    && current_line_len != current_prefix_len
24322                {
24323                    wrapped_text.push_str(current_line.trim_end());
24324                    wrapped_text.push('\n');
24325                    is_first_line = false;
24326                    current_line = subsequent_lines_prefix.clone();
24327                    current_line_len = subsequent_lines_prefix_len;
24328                } else if current_line_len != current_prefix_len {
24329                    current_line.push(' ');
24330                    current_line_len += 1;
24331                }
24332            }
24333        }
24334    }
24335
24336    if !current_line.is_empty() {
24337        wrapped_text.push_str(&current_line);
24338    }
24339    wrapped_text
24340}
24341
24342#[test]
24343fn test_wrap_with_prefix() {
24344    assert_eq!(
24345        wrap_with_prefix(
24346            "# ".to_string(),
24347            "# ".to_string(),
24348            "abcdefg".to_string(),
24349            4,
24350            NonZeroU32::new(4).unwrap(),
24351            false,
24352        ),
24353        "# abcdefg"
24354    );
24355    assert_eq!(
24356        wrap_with_prefix(
24357            "".to_string(),
24358            "".to_string(),
24359            "\thello world".to_string(),
24360            8,
24361            NonZeroU32::new(4).unwrap(),
24362            false,
24363        ),
24364        "hello\nworld"
24365    );
24366    assert_eq!(
24367        wrap_with_prefix(
24368            "// ".to_string(),
24369            "// ".to_string(),
24370            "xx \nyy zz aa bb cc".to_string(),
24371            12,
24372            NonZeroU32::new(4).unwrap(),
24373            false,
24374        ),
24375        "// xx yy zz\n// aa bb cc"
24376    );
24377    assert_eq!(
24378        wrap_with_prefix(
24379            String::new(),
24380            String::new(),
24381            "这是什么 \n 钢笔".to_string(),
24382            3,
24383            NonZeroU32::new(4).unwrap(),
24384            false,
24385        ),
24386        "这是什\n么 钢\n"
24387    );
24388    assert_eq!(
24389        wrap_with_prefix(
24390            String::new(),
24391            String::new(),
24392            format!("foo{}bar", '\u{2009}'), // thin space
24393            80,
24394            NonZeroU32::new(4).unwrap(),
24395            false,
24396        ),
24397        format!("foo{}bar", '\u{2009}')
24398    );
24399}
24400
24401pub trait CollaborationHub {
24402    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24403    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24404    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24405}
24406
24407impl CollaborationHub for Entity<Project> {
24408    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24409        self.read(cx).collaborators()
24410    }
24411
24412    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24413        self.read(cx).user_store().read(cx).participant_indices()
24414    }
24415
24416    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24417        let this = self.read(cx);
24418        let user_ids = this.collaborators().values().map(|c| c.user_id);
24419        this.user_store().read(cx).participant_names(user_ids, cx)
24420    }
24421}
24422
24423pub trait SemanticsProvider {
24424    fn hover(
24425        &self,
24426        buffer: &Entity<Buffer>,
24427        position: text::Anchor,
24428        cx: &mut App,
24429    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24430
24431    fn inline_values(
24432        &self,
24433        buffer_handle: Entity<Buffer>,
24434        range: Range<text::Anchor>,
24435        cx: &mut App,
24436    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24437
24438    fn applicable_inlay_chunks(
24439        &self,
24440        buffer: &Entity<Buffer>,
24441        ranges: &[Range<text::Anchor>],
24442        cx: &mut App,
24443    ) -> Vec<Range<BufferRow>>;
24444
24445    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24446
24447    fn inlay_hints(
24448        &self,
24449        invalidate: InvalidationStrategy,
24450        buffer: Entity<Buffer>,
24451        ranges: Vec<Range<text::Anchor>>,
24452        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24453        cx: &mut App,
24454    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24455
24456    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24457
24458    fn document_highlights(
24459        &self,
24460        buffer: &Entity<Buffer>,
24461        position: text::Anchor,
24462        cx: &mut App,
24463    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24464
24465    fn definitions(
24466        &self,
24467        buffer: &Entity<Buffer>,
24468        position: text::Anchor,
24469        kind: GotoDefinitionKind,
24470        cx: &mut App,
24471    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24472
24473    fn range_for_rename(
24474        &self,
24475        buffer: &Entity<Buffer>,
24476        position: text::Anchor,
24477        cx: &mut App,
24478    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24479
24480    fn perform_rename(
24481        &self,
24482        buffer: &Entity<Buffer>,
24483        position: text::Anchor,
24484        new_name: String,
24485        cx: &mut App,
24486    ) -> Option<Task<Result<ProjectTransaction>>>;
24487}
24488
24489pub trait CompletionProvider {
24490    fn completions(
24491        &self,
24492        excerpt_id: ExcerptId,
24493        buffer: &Entity<Buffer>,
24494        buffer_position: text::Anchor,
24495        trigger: CompletionContext,
24496        window: &mut Window,
24497        cx: &mut Context<Editor>,
24498    ) -> Task<Result<Vec<CompletionResponse>>>;
24499
24500    fn resolve_completions(
24501        &self,
24502        _buffer: Entity<Buffer>,
24503        _completion_indices: Vec<usize>,
24504        _completions: Rc<RefCell<Box<[Completion]>>>,
24505        _cx: &mut Context<Editor>,
24506    ) -> Task<Result<bool>> {
24507        Task::ready(Ok(false))
24508    }
24509
24510    fn apply_additional_edits_for_completion(
24511        &self,
24512        _buffer: Entity<Buffer>,
24513        _completions: Rc<RefCell<Box<[Completion]>>>,
24514        _completion_index: usize,
24515        _push_to_history: bool,
24516        _cx: &mut Context<Editor>,
24517    ) -> Task<Result<Option<language::Transaction>>> {
24518        Task::ready(Ok(None))
24519    }
24520
24521    fn is_completion_trigger(
24522        &self,
24523        buffer: &Entity<Buffer>,
24524        position: language::Anchor,
24525        text: &str,
24526        trigger_in_words: bool,
24527        cx: &mut Context<Editor>,
24528    ) -> bool;
24529
24530    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24531
24532    fn sort_completions(&self) -> bool {
24533        true
24534    }
24535
24536    fn filter_completions(&self) -> bool {
24537        true
24538    }
24539
24540    fn show_snippets(&self) -> bool {
24541        false
24542    }
24543}
24544
24545pub trait CodeActionProvider {
24546    fn id(&self) -> Arc<str>;
24547
24548    fn code_actions(
24549        &self,
24550        buffer: &Entity<Buffer>,
24551        range: Range<text::Anchor>,
24552        window: &mut Window,
24553        cx: &mut App,
24554    ) -> Task<Result<Vec<CodeAction>>>;
24555
24556    fn apply_code_action(
24557        &self,
24558        buffer_handle: Entity<Buffer>,
24559        action: CodeAction,
24560        excerpt_id: ExcerptId,
24561        push_to_history: bool,
24562        window: &mut Window,
24563        cx: &mut App,
24564    ) -> Task<Result<ProjectTransaction>>;
24565}
24566
24567impl CodeActionProvider for Entity<Project> {
24568    fn id(&self) -> Arc<str> {
24569        "project".into()
24570    }
24571
24572    fn code_actions(
24573        &self,
24574        buffer: &Entity<Buffer>,
24575        range: Range<text::Anchor>,
24576        _window: &mut Window,
24577        cx: &mut App,
24578    ) -> Task<Result<Vec<CodeAction>>> {
24579        self.update(cx, |project, cx| {
24580            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24581            let code_actions = project.code_actions(buffer, range, None, cx);
24582            cx.background_spawn(async move {
24583                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24584                Ok(code_lens_actions
24585                    .context("code lens fetch")?
24586                    .into_iter()
24587                    .flatten()
24588                    .chain(
24589                        code_actions
24590                            .context("code action fetch")?
24591                            .into_iter()
24592                            .flatten(),
24593                    )
24594                    .collect())
24595            })
24596        })
24597    }
24598
24599    fn apply_code_action(
24600        &self,
24601        buffer_handle: Entity<Buffer>,
24602        action: CodeAction,
24603        _excerpt_id: ExcerptId,
24604        push_to_history: bool,
24605        _window: &mut Window,
24606        cx: &mut App,
24607    ) -> Task<Result<ProjectTransaction>> {
24608        self.update(cx, |project, cx| {
24609            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24610        })
24611    }
24612}
24613
24614fn snippet_completions(
24615    project: &Project,
24616    buffer: &Entity<Buffer>,
24617    buffer_anchor: text::Anchor,
24618    classifier: CharClassifier,
24619    cx: &mut App,
24620) -> Task<Result<CompletionResponse>> {
24621    let languages = buffer.read(cx).languages_at(buffer_anchor);
24622    let snippet_store = project.snippets().read(cx);
24623
24624    let scopes: Vec<_> = languages
24625        .iter()
24626        .filter_map(|language| {
24627            let language_name = language.lsp_id();
24628            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24629
24630            if snippets.is_empty() {
24631                None
24632            } else {
24633                Some((language.default_scope(), snippets))
24634            }
24635        })
24636        .collect();
24637
24638    if scopes.is_empty() {
24639        return Task::ready(Ok(CompletionResponse {
24640            completions: vec![],
24641            display_options: CompletionDisplayOptions::default(),
24642            is_incomplete: false,
24643        }));
24644    }
24645
24646    let snapshot = buffer.read(cx).text_snapshot();
24647    let executor = cx.background_executor().clone();
24648
24649    cx.background_spawn(async move {
24650        let is_word_char = |c| classifier.is_word(c);
24651
24652        let mut is_incomplete = false;
24653        let mut completions: Vec<Completion> = Vec::new();
24654
24655        const MAX_PREFIX_LEN: usize = 128;
24656        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24657        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24658        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24659
24660        let max_buffer_window: String = snapshot
24661            .text_for_range(window_start..buffer_offset)
24662            .collect();
24663
24664        if max_buffer_window.is_empty() {
24665            return Ok(CompletionResponse {
24666                completions: vec![],
24667                display_options: CompletionDisplayOptions::default(),
24668                is_incomplete: true,
24669            });
24670        }
24671
24672        for (_scope, snippets) in scopes.into_iter() {
24673            // Sort snippets by word count to match longer snippet prefixes first.
24674            let mut sorted_snippet_candidates = snippets
24675                .iter()
24676                .enumerate()
24677                .flat_map(|(snippet_ix, snippet)| {
24678                    snippet
24679                        .prefix
24680                        .iter()
24681                        .enumerate()
24682                        .map(move |(prefix_ix, prefix)| {
24683                            let word_count =
24684                                snippet_candidate_suffixes(prefix, is_word_char).count();
24685                            ((snippet_ix, prefix_ix), prefix, word_count)
24686                        })
24687                })
24688                .collect_vec();
24689            sorted_snippet_candidates
24690                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24691
24692            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24693
24694            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24695                .take(
24696                    sorted_snippet_candidates
24697                        .first()
24698                        .map(|(_, _, word_count)| *word_count)
24699                        .unwrap_or_default(),
24700                )
24701                .collect_vec();
24702
24703            const MAX_RESULTS: usize = 100;
24704            // Each match also remembers how many characters from the buffer it consumed
24705            let mut matches: Vec<(StringMatch, usize)> = vec![];
24706
24707            let mut snippet_list_cutoff_index = 0;
24708            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24709                let word_count = buffer_index + 1;
24710                // Increase `snippet_list_cutoff_index` until we have all of the
24711                // snippets with sufficiently many words.
24712                while sorted_snippet_candidates
24713                    .get(snippet_list_cutoff_index)
24714                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24715                        *snippet_word_count >= word_count
24716                    })
24717                {
24718                    snippet_list_cutoff_index += 1;
24719                }
24720
24721                // Take only the candidates with at least `word_count` many words
24722                let snippet_candidates_at_word_len =
24723                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24724
24725                let candidates = snippet_candidates_at_word_len
24726                    .iter()
24727                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24728                    .enumerate() // index in `sorted_snippet_candidates`
24729                    // First char must match
24730                    .filter(|(_ix, prefix)| {
24731                        itertools::equal(
24732                            prefix
24733                                .chars()
24734                                .next()
24735                                .into_iter()
24736                                .flat_map(|c| c.to_lowercase()),
24737                            buffer_window
24738                                .chars()
24739                                .next()
24740                                .into_iter()
24741                                .flat_map(|c| c.to_lowercase()),
24742                        )
24743                    })
24744                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24745                    .collect::<Vec<StringMatchCandidate>>();
24746
24747                matches.extend(
24748                    fuzzy::match_strings(
24749                        &candidates,
24750                        &buffer_window,
24751                        buffer_window.chars().any(|c| c.is_uppercase()),
24752                        true,
24753                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24754                        &Default::default(),
24755                        executor.clone(),
24756                    )
24757                    .await
24758                    .into_iter()
24759                    .map(|string_match| (string_match, buffer_window.len())),
24760                );
24761
24762                if matches.len() >= MAX_RESULTS {
24763                    break;
24764                }
24765            }
24766
24767            let to_lsp = |point: &text::Anchor| {
24768                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24769                point_to_lsp(end)
24770            };
24771            let lsp_end = to_lsp(&buffer_anchor);
24772
24773            if matches.len() >= MAX_RESULTS {
24774                is_incomplete = true;
24775            }
24776
24777            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24778                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24779                    sorted_snippet_candidates[string_match.candidate_id];
24780                let snippet = &snippets[snippet_index];
24781                let start = buffer_offset - buffer_window_len;
24782                let start = snapshot.anchor_before(start);
24783                let range = start..buffer_anchor;
24784                let lsp_start = to_lsp(&start);
24785                let lsp_range = lsp::Range {
24786                    start: lsp_start,
24787                    end: lsp_end,
24788                };
24789                Completion {
24790                    replace_range: range,
24791                    new_text: snippet.body.clone(),
24792                    source: CompletionSource::Lsp {
24793                        insert_range: None,
24794                        server_id: LanguageServerId(usize::MAX),
24795                        resolved: true,
24796                        lsp_completion: Box::new(lsp::CompletionItem {
24797                            label: snippet.prefix.first().unwrap().clone(),
24798                            kind: Some(CompletionItemKind::SNIPPET),
24799                            label_details: snippet.description.as_ref().map(|description| {
24800                                lsp::CompletionItemLabelDetails {
24801                                    detail: Some(description.clone()),
24802                                    description: None,
24803                                }
24804                            }),
24805                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24806                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24807                                lsp::InsertReplaceEdit {
24808                                    new_text: snippet.body.clone(),
24809                                    insert: lsp_range,
24810                                    replace: lsp_range,
24811                                },
24812                            )),
24813                            filter_text: Some(snippet.body.clone()),
24814                            sort_text: Some(char::MAX.to_string()),
24815                            ..lsp::CompletionItem::default()
24816                        }),
24817                        lsp_defaults: None,
24818                    },
24819                    label: CodeLabel {
24820                        text: matching_prefix.clone(),
24821                        runs: Vec::new(),
24822                        filter_range: 0..matching_prefix.len(),
24823                    },
24824                    icon_path: None,
24825                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24826                        single_line: snippet.name.clone().into(),
24827                        plain_text: snippet
24828                            .description
24829                            .clone()
24830                            .map(|description| description.into()),
24831                    }),
24832                    insert_text_mode: None,
24833                    confirm: None,
24834                    match_start: Some(start),
24835                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24836                }
24837            }));
24838        }
24839
24840        Ok(CompletionResponse {
24841            completions,
24842            display_options: CompletionDisplayOptions::default(),
24843            is_incomplete,
24844        })
24845    })
24846}
24847
24848impl CompletionProvider for Entity<Project> {
24849    fn completions(
24850        &self,
24851        _excerpt_id: ExcerptId,
24852        buffer: &Entity<Buffer>,
24853        buffer_position: text::Anchor,
24854        options: CompletionContext,
24855        _window: &mut Window,
24856        cx: &mut Context<Editor>,
24857    ) -> Task<Result<Vec<CompletionResponse>>> {
24858        self.update(cx, |project, cx| {
24859            let task = project.completions(buffer, buffer_position, options, cx);
24860            cx.background_spawn(task)
24861        })
24862    }
24863
24864    fn resolve_completions(
24865        &self,
24866        buffer: Entity<Buffer>,
24867        completion_indices: Vec<usize>,
24868        completions: Rc<RefCell<Box<[Completion]>>>,
24869        cx: &mut Context<Editor>,
24870    ) -> Task<Result<bool>> {
24871        self.update(cx, |project, cx| {
24872            project.lsp_store().update(cx, |lsp_store, cx| {
24873                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24874            })
24875        })
24876    }
24877
24878    fn apply_additional_edits_for_completion(
24879        &self,
24880        buffer: Entity<Buffer>,
24881        completions: Rc<RefCell<Box<[Completion]>>>,
24882        completion_index: usize,
24883        push_to_history: bool,
24884        cx: &mut Context<Editor>,
24885    ) -> Task<Result<Option<language::Transaction>>> {
24886        self.update(cx, |project, cx| {
24887            project.lsp_store().update(cx, |lsp_store, cx| {
24888                lsp_store.apply_additional_edits_for_completion(
24889                    buffer,
24890                    completions,
24891                    completion_index,
24892                    push_to_history,
24893                    cx,
24894                )
24895            })
24896        })
24897    }
24898
24899    fn is_completion_trigger(
24900        &self,
24901        buffer: &Entity<Buffer>,
24902        position: language::Anchor,
24903        text: &str,
24904        trigger_in_words: bool,
24905        cx: &mut Context<Editor>,
24906    ) -> bool {
24907        let mut chars = text.chars();
24908        let char = if let Some(char) = chars.next() {
24909            char
24910        } else {
24911            return false;
24912        };
24913        if chars.next().is_some() {
24914            return false;
24915        }
24916
24917        let buffer = buffer.read(cx);
24918        let snapshot = buffer.snapshot();
24919        let classifier = snapshot
24920            .char_classifier_at(position)
24921            .scope_context(Some(CharScopeContext::Completion));
24922        if trigger_in_words && classifier.is_word(char) {
24923            return true;
24924        }
24925
24926        buffer.completion_triggers().contains(text)
24927    }
24928
24929    fn show_snippets(&self) -> bool {
24930        true
24931    }
24932}
24933
24934impl SemanticsProvider for Entity<Project> {
24935    fn hover(
24936        &self,
24937        buffer: &Entity<Buffer>,
24938        position: text::Anchor,
24939        cx: &mut App,
24940    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24941        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24942    }
24943
24944    fn document_highlights(
24945        &self,
24946        buffer: &Entity<Buffer>,
24947        position: text::Anchor,
24948        cx: &mut App,
24949    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24950        Some(self.update(cx, |project, cx| {
24951            project.document_highlights(buffer, position, cx)
24952        }))
24953    }
24954
24955    fn definitions(
24956        &self,
24957        buffer: &Entity<Buffer>,
24958        position: text::Anchor,
24959        kind: GotoDefinitionKind,
24960        cx: &mut App,
24961    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24962        Some(self.update(cx, |project, cx| match kind {
24963            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24964            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24965            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24966            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24967        }))
24968    }
24969
24970    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24971        self.update(cx, |project, cx| {
24972            if project
24973                .active_debug_session(cx)
24974                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24975            {
24976                return true;
24977            }
24978
24979            buffer.update(cx, |buffer, cx| {
24980                project.any_language_server_supports_inlay_hints(buffer, cx)
24981            })
24982        })
24983    }
24984
24985    fn inline_values(
24986        &self,
24987        buffer_handle: Entity<Buffer>,
24988        range: Range<text::Anchor>,
24989        cx: &mut App,
24990    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24991        self.update(cx, |project, cx| {
24992            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24993
24994            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24995        })
24996    }
24997
24998    fn applicable_inlay_chunks(
24999        &self,
25000        buffer: &Entity<Buffer>,
25001        ranges: &[Range<text::Anchor>],
25002        cx: &mut App,
25003    ) -> Vec<Range<BufferRow>> {
25004        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25005            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
25006        })
25007    }
25008
25009    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
25010        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
25011            lsp_store.invalidate_inlay_hints(for_buffers)
25012        });
25013    }
25014
25015    fn inlay_hints(
25016        &self,
25017        invalidate: InvalidationStrategy,
25018        buffer: Entity<Buffer>,
25019        ranges: Vec<Range<text::Anchor>>,
25020        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25021        cx: &mut App,
25022    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25023        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25024            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25025        }))
25026    }
25027
25028    fn range_for_rename(
25029        &self,
25030        buffer: &Entity<Buffer>,
25031        position: text::Anchor,
25032        cx: &mut App,
25033    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25034        Some(self.update(cx, |project, cx| {
25035            let buffer = buffer.clone();
25036            let task = project.prepare_rename(buffer.clone(), position, cx);
25037            cx.spawn(async move |_, cx| {
25038                Ok(match task.await? {
25039                    PrepareRenameResponse::Success(range) => Some(range),
25040                    PrepareRenameResponse::InvalidPosition => None,
25041                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25042                        // Fallback on using TreeSitter info to determine identifier range
25043                        buffer.read_with(cx, |buffer, _| {
25044                            let snapshot = buffer.snapshot();
25045                            let (range, kind) = snapshot.surrounding_word(position, None);
25046                            if kind != Some(CharKind::Word) {
25047                                return None;
25048                            }
25049                            Some(
25050                                snapshot.anchor_before(range.start)
25051                                    ..snapshot.anchor_after(range.end),
25052                            )
25053                        })
25054                    }
25055                })
25056            })
25057        }))
25058    }
25059
25060    fn perform_rename(
25061        &self,
25062        buffer: &Entity<Buffer>,
25063        position: text::Anchor,
25064        new_name: String,
25065        cx: &mut App,
25066    ) -> Option<Task<Result<ProjectTransaction>>> {
25067        Some(self.update(cx, |project, cx| {
25068            project.perform_rename(buffer.clone(), position, new_name, cx)
25069        }))
25070    }
25071}
25072
25073fn consume_contiguous_rows(
25074    contiguous_row_selections: &mut Vec<Selection<Point>>,
25075    selection: &Selection<Point>,
25076    display_map: &DisplaySnapshot,
25077    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25078) -> (MultiBufferRow, MultiBufferRow) {
25079    contiguous_row_selections.push(selection.clone());
25080    let start_row = starting_row(selection, display_map);
25081    let mut end_row = ending_row(selection, display_map);
25082
25083    while let Some(next_selection) = selections.peek() {
25084        if next_selection.start.row <= end_row.0 {
25085            end_row = ending_row(next_selection, display_map);
25086            contiguous_row_selections.push(selections.next().unwrap().clone());
25087        } else {
25088            break;
25089        }
25090    }
25091    (start_row, end_row)
25092}
25093
25094fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25095    if selection.start.column > 0 {
25096        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25097    } else {
25098        MultiBufferRow(selection.start.row)
25099    }
25100}
25101
25102fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25103    if next_selection.end.column > 0 || next_selection.is_empty() {
25104        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25105    } else {
25106        MultiBufferRow(next_selection.end.row)
25107    }
25108}
25109
25110impl EditorSnapshot {
25111    pub fn remote_selections_in_range<'a>(
25112        &'a self,
25113        range: &'a Range<Anchor>,
25114        collaboration_hub: &dyn CollaborationHub,
25115        cx: &'a App,
25116    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25117        let participant_names = collaboration_hub.user_names(cx);
25118        let participant_indices = collaboration_hub.user_participant_indices(cx);
25119        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25120        let collaborators_by_replica_id = collaborators_by_peer_id
25121            .values()
25122            .map(|collaborator| (collaborator.replica_id, collaborator))
25123            .collect::<HashMap<_, _>>();
25124        self.buffer_snapshot()
25125            .selections_in_range(range, false)
25126            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25127                if replica_id == ReplicaId::AGENT {
25128                    Some(RemoteSelection {
25129                        replica_id,
25130                        selection,
25131                        cursor_shape,
25132                        line_mode,
25133                        collaborator_id: CollaboratorId::Agent,
25134                        user_name: Some("Agent".into()),
25135                        color: cx.theme().players().agent(),
25136                    })
25137                } else {
25138                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25139                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25140                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25141                    Some(RemoteSelection {
25142                        replica_id,
25143                        selection,
25144                        cursor_shape,
25145                        line_mode,
25146                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25147                        user_name,
25148                        color: if let Some(index) = participant_index {
25149                            cx.theme().players().color_for_participant(index.0)
25150                        } else {
25151                            cx.theme().players().absent()
25152                        },
25153                    })
25154                }
25155            })
25156    }
25157
25158    pub fn hunks_for_ranges(
25159        &self,
25160        ranges: impl IntoIterator<Item = Range<Point>>,
25161    ) -> Vec<MultiBufferDiffHunk> {
25162        let mut hunks = Vec::new();
25163        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25164            HashMap::default();
25165        for query_range in ranges {
25166            let query_rows =
25167                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25168            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25169                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25170            ) {
25171                // Include deleted hunks that are adjacent to the query range, because
25172                // otherwise they would be missed.
25173                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25174                if hunk.status().is_deleted() {
25175                    intersects_range |= hunk.row_range.start == query_rows.end;
25176                    intersects_range |= hunk.row_range.end == query_rows.start;
25177                }
25178                if intersects_range {
25179                    if !processed_buffer_rows
25180                        .entry(hunk.buffer_id)
25181                        .or_default()
25182                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25183                    {
25184                        continue;
25185                    }
25186                    hunks.push(hunk);
25187                }
25188            }
25189        }
25190
25191        hunks
25192    }
25193
25194    fn display_diff_hunks_for_rows<'a>(
25195        &'a self,
25196        display_rows: Range<DisplayRow>,
25197        folded_buffers: &'a HashSet<BufferId>,
25198    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25199        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25200        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25201
25202        self.buffer_snapshot()
25203            .diff_hunks_in_range(buffer_start..buffer_end)
25204            .filter_map(|hunk| {
25205                if folded_buffers.contains(&hunk.buffer_id) {
25206                    return None;
25207                }
25208
25209                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25210                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25211
25212                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25213                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25214
25215                let display_hunk = if hunk_display_start.column() != 0 {
25216                    DisplayDiffHunk::Folded {
25217                        display_row: hunk_display_start.row(),
25218                    }
25219                } else {
25220                    let mut end_row = hunk_display_end.row();
25221                    if hunk_display_end.column() > 0 {
25222                        end_row.0 += 1;
25223                    }
25224                    let is_created_file = hunk.is_created_file();
25225
25226                    DisplayDiffHunk::Unfolded {
25227                        status: hunk.status(),
25228                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25229                            ..hunk.diff_base_byte_range.end.0,
25230                        word_diffs: hunk.word_diffs,
25231                        display_row_range: hunk_display_start.row()..end_row,
25232                        multi_buffer_range: Anchor::range_in_buffer(
25233                            hunk.excerpt_id,
25234                            hunk.buffer_range,
25235                        ),
25236                        is_created_file,
25237                    }
25238                };
25239
25240                Some(display_hunk)
25241            })
25242    }
25243
25244    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25245        self.display_snapshot
25246            .buffer_snapshot()
25247            .language_at(position)
25248    }
25249
25250    pub fn is_focused(&self) -> bool {
25251        self.is_focused
25252    }
25253
25254    pub fn placeholder_text(&self) -> Option<String> {
25255        self.placeholder_display_snapshot
25256            .as_ref()
25257            .map(|display_map| display_map.text())
25258    }
25259
25260    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25261        self.scroll_anchor.scroll_position(&self.display_snapshot)
25262    }
25263
25264    pub fn gutter_dimensions(
25265        &self,
25266        font_id: FontId,
25267        font_size: Pixels,
25268        style: &EditorStyle,
25269        window: &mut Window,
25270        cx: &App,
25271    ) -> GutterDimensions {
25272        if self.show_gutter
25273            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25274            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25275        {
25276            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25277                matches!(
25278                    ProjectSettings::get_global(cx).git.git_gutter,
25279                    GitGutterSetting::TrackedFiles
25280                )
25281            });
25282            let gutter_settings = EditorSettings::get_global(cx).gutter;
25283            let show_line_numbers = self
25284                .show_line_numbers
25285                .unwrap_or(gutter_settings.line_numbers);
25286            let line_gutter_width = if show_line_numbers {
25287                // Avoid flicker-like gutter resizes when the line number gains another digit by
25288                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25289                let min_width_for_number_on_gutter =
25290                    ch_advance * gutter_settings.min_line_number_digits as f32;
25291                self.max_line_number_width(style, window)
25292                    .max(min_width_for_number_on_gutter)
25293            } else {
25294                0.0.into()
25295            };
25296
25297            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25298            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25299
25300            let git_blame_entries_width =
25301                self.git_blame_gutter_max_author_length
25302                    .map(|max_author_length| {
25303                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25304                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25305
25306                        /// The number of characters to dedicate to gaps and margins.
25307                        const SPACING_WIDTH: usize = 4;
25308
25309                        let max_char_count = max_author_length.min(renderer.max_author_length())
25310                            + ::git::SHORT_SHA_LENGTH
25311                            + MAX_RELATIVE_TIMESTAMP.len()
25312                            + SPACING_WIDTH;
25313
25314                        ch_advance * max_char_count
25315                    });
25316
25317            let is_singleton = self.buffer_snapshot().is_singleton();
25318
25319            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25320            left_padding += if !is_singleton {
25321                ch_width * 4.0
25322            } else if show_runnables || show_breakpoints {
25323                ch_width * 3.0
25324            } else if show_git_gutter && show_line_numbers {
25325                ch_width * 2.0
25326            } else if show_git_gutter || show_line_numbers {
25327                ch_width
25328            } else {
25329                px(0.)
25330            };
25331
25332            let shows_folds = is_singleton && gutter_settings.folds;
25333
25334            let right_padding = if shows_folds && show_line_numbers {
25335                ch_width * 4.0
25336            } else if shows_folds || (!is_singleton && show_line_numbers) {
25337                ch_width * 3.0
25338            } else if show_line_numbers {
25339                ch_width
25340            } else {
25341                px(0.)
25342            };
25343
25344            GutterDimensions {
25345                left_padding,
25346                right_padding,
25347                width: line_gutter_width + left_padding + right_padding,
25348                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25349                git_blame_entries_width,
25350            }
25351        } else if self.offset_content {
25352            GutterDimensions::default_with_margin(font_id, font_size, cx)
25353        } else {
25354            GutterDimensions::default()
25355        }
25356    }
25357
25358    pub fn render_crease_toggle(
25359        &self,
25360        buffer_row: MultiBufferRow,
25361        row_contains_cursor: bool,
25362        editor: Entity<Editor>,
25363        window: &mut Window,
25364        cx: &mut App,
25365    ) -> Option<AnyElement> {
25366        let folded = self.is_line_folded(buffer_row);
25367        let mut is_foldable = false;
25368
25369        if let Some(crease) = self
25370            .crease_snapshot
25371            .query_row(buffer_row, self.buffer_snapshot())
25372        {
25373            is_foldable = true;
25374            match crease {
25375                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25376                    if let Some(render_toggle) = render_toggle {
25377                        let toggle_callback =
25378                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25379                                if folded {
25380                                    editor.update(cx, |editor, cx| {
25381                                        editor.fold_at(buffer_row, window, cx)
25382                                    });
25383                                } else {
25384                                    editor.update(cx, |editor, cx| {
25385                                        editor.unfold_at(buffer_row, window, cx)
25386                                    });
25387                                }
25388                            });
25389                        return Some((render_toggle)(
25390                            buffer_row,
25391                            folded,
25392                            toggle_callback,
25393                            window,
25394                            cx,
25395                        ));
25396                    }
25397                }
25398            }
25399        }
25400
25401        is_foldable |= self.starts_indent(buffer_row);
25402
25403        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25404            Some(
25405                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25406                    .toggle_state(folded)
25407                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25408                        if folded {
25409                            this.unfold_at(buffer_row, window, cx);
25410                        } else {
25411                            this.fold_at(buffer_row, window, cx);
25412                        }
25413                    }))
25414                    .into_any_element(),
25415            )
25416        } else {
25417            None
25418        }
25419    }
25420
25421    pub fn render_crease_trailer(
25422        &self,
25423        buffer_row: MultiBufferRow,
25424        window: &mut Window,
25425        cx: &mut App,
25426    ) -> Option<AnyElement> {
25427        let folded = self.is_line_folded(buffer_row);
25428        if let Crease::Inline { render_trailer, .. } = self
25429            .crease_snapshot
25430            .query_row(buffer_row, self.buffer_snapshot())?
25431        {
25432            let render_trailer = render_trailer.as_ref()?;
25433            Some(render_trailer(buffer_row, folded, window, cx))
25434        } else {
25435            None
25436        }
25437    }
25438
25439    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25440        let digit_count = self.widest_line_number().ilog10() + 1;
25441        column_pixels(style, digit_count as usize, window)
25442    }
25443
25444    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25445    ///
25446    /// This is positive if `base` is before `line`.
25447    fn relative_line_delta(
25448        &self,
25449        base: DisplayRow,
25450        line: DisplayRow,
25451        consider_wrapped_lines: bool,
25452    ) -> i64 {
25453        let point = DisplayPoint::new(line, 0).to_point(self);
25454        self.relative_line_delta_to_point(base, point, consider_wrapped_lines)
25455    }
25456
25457    /// Returns the line delta from `base` to `point` in the multibuffer.
25458    ///
25459    /// This is positive if `base` is before `point`.
25460    pub fn relative_line_delta_to_point(
25461        &self,
25462        base: DisplayRow,
25463        point: Point,
25464        consider_wrapped_lines: bool,
25465    ) -> i64 {
25466        let base_point = DisplayPoint::new(base, 0).to_point(self);
25467        if consider_wrapped_lines {
25468            let wrap_snapshot = self.wrap_snapshot();
25469            let base_wrap_row = wrap_snapshot.make_wrap_point(base_point, Bias::Left).row();
25470            let wrap_row = wrap_snapshot.make_wrap_point(point, Bias::Left).row();
25471            wrap_row.0 as i64 - base_wrap_row.0 as i64
25472        } else {
25473            point.row as i64 - base_point.row as i64
25474        }
25475    }
25476
25477    /// Returns the unsigned relative line number to display for each row in `rows`.
25478    ///
25479    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25480    pub fn calculate_relative_line_numbers(
25481        &self,
25482        rows: &Range<DisplayRow>,
25483        relative_to: DisplayRow,
25484        count_wrapped_lines: bool,
25485    ) -> HashMap<DisplayRow, u32> {
25486        let initial_offset = self.relative_line_delta(relative_to, rows.start, count_wrapped_lines);
25487
25488        self.row_infos(rows.start)
25489            .take(rows.len())
25490            .enumerate()
25491            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25492            .filter(|(_row, row_info)| {
25493                row_info.buffer_row.is_some()
25494                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25495            })
25496            .enumerate()
25497            .flat_map(|(i, (row, _row_info))| {
25498                (row != relative_to)
25499                    .then_some((row, (initial_offset + i as i64).unsigned_abs() as u32))
25500            })
25501            .collect()
25502    }
25503}
25504
25505pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25506    let font_size = style.text.font_size.to_pixels(window.rem_size());
25507    let layout = window.text_system().shape_line(
25508        SharedString::from(" ".repeat(column)),
25509        font_size,
25510        &[TextRun {
25511            len: column,
25512            font: style.text.font(),
25513            color: Hsla::default(),
25514            ..Default::default()
25515        }],
25516        None,
25517    );
25518
25519    layout.width
25520}
25521
25522impl Deref for EditorSnapshot {
25523    type Target = DisplaySnapshot;
25524
25525    fn deref(&self) -> &Self::Target {
25526        &self.display_snapshot
25527    }
25528}
25529
25530#[derive(Clone, Debug, PartialEq, Eq)]
25531pub enum EditorEvent {
25532    InputIgnored {
25533        text: Arc<str>,
25534    },
25535    InputHandled {
25536        utf16_range_to_replace: Option<Range<isize>>,
25537        text: Arc<str>,
25538    },
25539    ExcerptsAdded {
25540        buffer: Entity<Buffer>,
25541        predecessor: ExcerptId,
25542        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25543    },
25544    ExcerptsRemoved {
25545        ids: Vec<ExcerptId>,
25546        removed_buffer_ids: Vec<BufferId>,
25547    },
25548    BufferFoldToggled {
25549        ids: Vec<ExcerptId>,
25550        folded: bool,
25551    },
25552    ExcerptsEdited {
25553        ids: Vec<ExcerptId>,
25554    },
25555    ExcerptsExpanded {
25556        ids: Vec<ExcerptId>,
25557    },
25558    ExpandExcerptsRequested {
25559        excerpt_ids: Vec<ExcerptId>,
25560        lines: u32,
25561        direction: ExpandExcerptDirection,
25562    },
25563    BufferEdited,
25564    Edited {
25565        transaction_id: clock::Lamport,
25566    },
25567    Reparsed(BufferId),
25568    Focused,
25569    FocusedIn,
25570    Blurred,
25571    DirtyChanged,
25572    Saved,
25573    TitleChanged,
25574    SelectionsChanged {
25575        local: bool,
25576    },
25577    ScrollPositionChanged {
25578        local: bool,
25579        autoscroll: bool,
25580    },
25581    TransactionUndone {
25582        transaction_id: clock::Lamport,
25583    },
25584    TransactionBegun {
25585        transaction_id: clock::Lamport,
25586    },
25587    CursorShapeChanged,
25588    BreadcrumbsChanged,
25589    PushedToNavHistory {
25590        anchor: Anchor,
25591        is_deactivate: bool,
25592    },
25593}
25594
25595impl EventEmitter<EditorEvent> for Editor {}
25596
25597impl Focusable for Editor {
25598    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25599        self.focus_handle.clone()
25600    }
25601}
25602
25603impl Render for Editor {
25604    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25605        EditorElement::new(&cx.entity(), self.create_style(cx))
25606    }
25607}
25608
25609impl EntityInputHandler for Editor {
25610    fn text_for_range(
25611        &mut self,
25612        range_utf16: Range<usize>,
25613        adjusted_range: &mut Option<Range<usize>>,
25614        _: &mut Window,
25615        cx: &mut Context<Self>,
25616    ) -> Option<String> {
25617        let snapshot = self.buffer.read(cx).read(cx);
25618        let start = snapshot.clip_offset_utf16(
25619            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25620            Bias::Left,
25621        );
25622        let end = snapshot.clip_offset_utf16(
25623            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25624            Bias::Right,
25625        );
25626        if (start.0.0..end.0.0) != range_utf16 {
25627            adjusted_range.replace(start.0.0..end.0.0);
25628        }
25629        Some(snapshot.text_for_range(start..end).collect())
25630    }
25631
25632    fn selected_text_range(
25633        &mut self,
25634        ignore_disabled_input: bool,
25635        _: &mut Window,
25636        cx: &mut Context<Self>,
25637    ) -> Option<UTF16Selection> {
25638        // Prevent the IME menu from appearing when holding down an alphabetic key
25639        // while input is disabled.
25640        if !ignore_disabled_input && !self.input_enabled {
25641            return None;
25642        }
25643
25644        let selection = self
25645            .selections
25646            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25647        let range = selection.range();
25648
25649        Some(UTF16Selection {
25650            range: range.start.0.0..range.end.0.0,
25651            reversed: selection.reversed,
25652        })
25653    }
25654
25655    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25656        let snapshot = self.buffer.read(cx).read(cx);
25657        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25658        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25659    }
25660
25661    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25662        self.clear_highlights::<InputComposition>(cx);
25663        self.ime_transaction.take();
25664    }
25665
25666    fn replace_text_in_range(
25667        &mut self,
25668        range_utf16: Option<Range<usize>>,
25669        text: &str,
25670        window: &mut Window,
25671        cx: &mut Context<Self>,
25672    ) {
25673        if !self.input_enabled {
25674            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25675            return;
25676        }
25677
25678        self.transact(window, cx, |this, window, cx| {
25679            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25680                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25681                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25682                Some(this.selection_replacement_ranges(range_utf16, cx))
25683            } else {
25684                this.marked_text_ranges(cx)
25685            };
25686
25687            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25688                let newest_selection_id = this.selections.newest_anchor().id;
25689                this.selections
25690                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25691                    .iter()
25692                    .zip(ranges_to_replace.iter())
25693                    .find_map(|(selection, range)| {
25694                        if selection.id == newest_selection_id {
25695                            Some(
25696                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25697                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25698                            )
25699                        } else {
25700                            None
25701                        }
25702                    })
25703            });
25704
25705            cx.emit(EditorEvent::InputHandled {
25706                utf16_range_to_replace: range_to_replace,
25707                text: text.into(),
25708            });
25709
25710            if let Some(new_selected_ranges) = new_selected_ranges {
25711                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25712                    selections.select_ranges(new_selected_ranges)
25713                });
25714                this.backspace(&Default::default(), window, cx);
25715            }
25716
25717            this.handle_input(text, window, cx);
25718        });
25719
25720        if let Some(transaction) = self.ime_transaction {
25721            self.buffer.update(cx, |buffer, cx| {
25722                buffer.group_until_transaction(transaction, cx);
25723            });
25724        }
25725
25726        self.unmark_text(window, cx);
25727    }
25728
25729    fn replace_and_mark_text_in_range(
25730        &mut self,
25731        range_utf16: Option<Range<usize>>,
25732        text: &str,
25733        new_selected_range_utf16: Option<Range<usize>>,
25734        window: &mut Window,
25735        cx: &mut Context<Self>,
25736    ) {
25737        if !self.input_enabled {
25738            return;
25739        }
25740
25741        let transaction = self.transact(window, cx, |this, window, cx| {
25742            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25743                let snapshot = this.buffer.read(cx).read(cx);
25744                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25745                    for marked_range in &mut marked_ranges {
25746                        marked_range.end = marked_range.start + relative_range_utf16.end;
25747                        marked_range.start += relative_range_utf16.start;
25748                        marked_range.start =
25749                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25750                        marked_range.end =
25751                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25752                    }
25753                }
25754                Some(marked_ranges)
25755            } else if let Some(range_utf16) = range_utf16 {
25756                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25757                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25758                Some(this.selection_replacement_ranges(range_utf16, cx))
25759            } else {
25760                None
25761            };
25762
25763            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25764                let newest_selection_id = this.selections.newest_anchor().id;
25765                this.selections
25766                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25767                    .iter()
25768                    .zip(ranges_to_replace.iter())
25769                    .find_map(|(selection, range)| {
25770                        if selection.id == newest_selection_id {
25771                            Some(
25772                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25773                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25774                            )
25775                        } else {
25776                            None
25777                        }
25778                    })
25779            });
25780
25781            cx.emit(EditorEvent::InputHandled {
25782                utf16_range_to_replace: range_to_replace,
25783                text: text.into(),
25784            });
25785
25786            if let Some(ranges) = ranges_to_replace {
25787                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25788                    s.select_ranges(ranges)
25789                });
25790            }
25791
25792            let marked_ranges = {
25793                let snapshot = this.buffer.read(cx).read(cx);
25794                this.selections
25795                    .disjoint_anchors_arc()
25796                    .iter()
25797                    .map(|selection| {
25798                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25799                    })
25800                    .collect::<Vec<_>>()
25801            };
25802
25803            if text.is_empty() {
25804                this.unmark_text(window, cx);
25805            } else {
25806                this.highlight_text::<InputComposition>(
25807                    marked_ranges.clone(),
25808                    HighlightStyle {
25809                        underline: Some(UnderlineStyle {
25810                            thickness: px(1.),
25811                            color: None,
25812                            wavy: false,
25813                        }),
25814                        ..Default::default()
25815                    },
25816                    cx,
25817                );
25818            }
25819
25820            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25821            let use_autoclose = this.use_autoclose;
25822            let use_auto_surround = this.use_auto_surround;
25823            this.set_use_autoclose(false);
25824            this.set_use_auto_surround(false);
25825            this.handle_input(text, window, cx);
25826            this.set_use_autoclose(use_autoclose);
25827            this.set_use_auto_surround(use_auto_surround);
25828
25829            if let Some(new_selected_range) = new_selected_range_utf16 {
25830                let snapshot = this.buffer.read(cx).read(cx);
25831                let new_selected_ranges = marked_ranges
25832                    .into_iter()
25833                    .map(|marked_range| {
25834                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25835                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25836                            insertion_start.0 + new_selected_range.start,
25837                        ));
25838                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25839                            insertion_start.0 + new_selected_range.end,
25840                        ));
25841                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25842                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25843                    })
25844                    .collect::<Vec<_>>();
25845
25846                drop(snapshot);
25847                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25848                    selections.select_ranges(new_selected_ranges)
25849                });
25850            }
25851        });
25852
25853        self.ime_transaction = self.ime_transaction.or(transaction);
25854        if let Some(transaction) = self.ime_transaction {
25855            self.buffer.update(cx, |buffer, cx| {
25856                buffer.group_until_transaction(transaction, cx);
25857            });
25858        }
25859
25860        if self.text_highlights::<InputComposition>(cx).is_none() {
25861            self.ime_transaction.take();
25862        }
25863    }
25864
25865    fn bounds_for_range(
25866        &mut self,
25867        range_utf16: Range<usize>,
25868        element_bounds: gpui::Bounds<Pixels>,
25869        window: &mut Window,
25870        cx: &mut Context<Self>,
25871    ) -> Option<gpui::Bounds<Pixels>> {
25872        let text_layout_details = self.text_layout_details(window);
25873        let CharacterDimensions {
25874            em_width,
25875            em_advance,
25876            line_height,
25877        } = self.character_dimensions(window);
25878
25879        let snapshot = self.snapshot(window, cx);
25880        let scroll_position = snapshot.scroll_position();
25881        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25882
25883        let start =
25884            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25885        let x = Pixels::from(
25886            ScrollOffset::from(
25887                snapshot.x_for_display_point(start, &text_layout_details)
25888                    + self.gutter_dimensions.full_width(),
25889            ) - scroll_left,
25890        );
25891        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25892
25893        Some(Bounds {
25894            origin: element_bounds.origin + point(x, y),
25895            size: size(em_width, line_height),
25896        })
25897    }
25898
25899    fn character_index_for_point(
25900        &mut self,
25901        point: gpui::Point<Pixels>,
25902        _window: &mut Window,
25903        _cx: &mut Context<Self>,
25904    ) -> Option<usize> {
25905        let position_map = self.last_position_map.as_ref()?;
25906        if !position_map.text_hitbox.contains(&point) {
25907            return None;
25908        }
25909        let display_point = position_map.point_for_position(point).previous_valid;
25910        let anchor = position_map
25911            .snapshot
25912            .display_point_to_anchor(display_point, Bias::Left);
25913        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25914        Some(utf16_offset.0.0)
25915    }
25916
25917    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25918        self.input_enabled
25919    }
25920}
25921
25922trait SelectionExt {
25923    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25924    fn spanned_rows(
25925        &self,
25926        include_end_if_at_line_start: bool,
25927        map: &DisplaySnapshot,
25928    ) -> Range<MultiBufferRow>;
25929}
25930
25931impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25932    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25933        let start = self
25934            .start
25935            .to_point(map.buffer_snapshot())
25936            .to_display_point(map);
25937        let end = self
25938            .end
25939            .to_point(map.buffer_snapshot())
25940            .to_display_point(map);
25941        if self.reversed {
25942            end..start
25943        } else {
25944            start..end
25945        }
25946    }
25947
25948    fn spanned_rows(
25949        &self,
25950        include_end_if_at_line_start: bool,
25951        map: &DisplaySnapshot,
25952    ) -> Range<MultiBufferRow> {
25953        let start = self.start.to_point(map.buffer_snapshot());
25954        let mut end = self.end.to_point(map.buffer_snapshot());
25955        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25956            end.row -= 1;
25957        }
25958
25959        let buffer_start = map.prev_line_boundary(start).0;
25960        let buffer_end = map.next_line_boundary(end).0;
25961        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25962    }
25963}
25964
25965impl<T: InvalidationRegion> InvalidationStack<T> {
25966    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25967    where
25968        S: Clone + ToOffset,
25969    {
25970        while let Some(region) = self.last() {
25971            let all_selections_inside_invalidation_ranges =
25972                if selections.len() == region.ranges().len() {
25973                    selections
25974                        .iter()
25975                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25976                        .all(|(selection, invalidation_range)| {
25977                            let head = selection.head().to_offset(buffer);
25978                            invalidation_range.start <= head && invalidation_range.end >= head
25979                        })
25980                } else {
25981                    false
25982                };
25983
25984            if all_selections_inside_invalidation_ranges {
25985                break;
25986            } else {
25987                self.pop();
25988            }
25989        }
25990    }
25991}
25992
25993impl<T> Default for InvalidationStack<T> {
25994    fn default() -> Self {
25995        Self(Default::default())
25996    }
25997}
25998
25999impl<T> Deref for InvalidationStack<T> {
26000    type Target = Vec<T>;
26001
26002    fn deref(&self) -> &Self::Target {
26003        &self.0
26004    }
26005}
26006
26007impl<T> DerefMut for InvalidationStack<T> {
26008    fn deref_mut(&mut self) -> &mut Self::Target {
26009        &mut self.0
26010    }
26011}
26012
26013impl InvalidationRegion for SnippetState {
26014    fn ranges(&self) -> &[Range<Anchor>] {
26015        &self.ranges[self.active_index]
26016    }
26017}
26018
26019fn edit_prediction_edit_text(
26020    current_snapshot: &BufferSnapshot,
26021    edits: &[(Range<Anchor>, impl AsRef<str>)],
26022    edit_preview: &EditPreview,
26023    include_deletions: bool,
26024    cx: &App,
26025) -> HighlightedText {
26026    let edits = edits
26027        .iter()
26028        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26029        .collect::<Vec<_>>();
26030
26031    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26032}
26033
26034fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26035    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26036    // Just show the raw edit text with basic styling
26037    let mut text = String::new();
26038    let mut highlights = Vec::new();
26039
26040    let insertion_highlight_style = HighlightStyle {
26041        color: Some(cx.theme().colors().text),
26042        ..Default::default()
26043    };
26044
26045    for (_, edit_text) in edits {
26046        let start_offset = text.len();
26047        text.push_str(edit_text);
26048        let end_offset = text.len();
26049
26050        if start_offset < end_offset {
26051            highlights.push((start_offset..end_offset, insertion_highlight_style));
26052        }
26053    }
26054
26055    HighlightedText {
26056        text: text.into(),
26057        highlights,
26058    }
26059}
26060
26061pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26062    match severity {
26063        lsp::DiagnosticSeverity::ERROR => colors.error,
26064        lsp::DiagnosticSeverity::WARNING => colors.warning,
26065        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26066        lsp::DiagnosticSeverity::HINT => colors.info,
26067        _ => colors.ignored,
26068    }
26069}
26070
26071pub fn styled_runs_for_code_label<'a>(
26072    label: &'a CodeLabel,
26073    syntax_theme: &'a theme::SyntaxTheme,
26074    local_player: &'a theme::PlayerColor,
26075) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26076    let fade_out = HighlightStyle {
26077        fade_out: Some(0.35),
26078        ..Default::default()
26079    };
26080
26081    let mut prev_end = label.filter_range.end;
26082    label
26083        .runs
26084        .iter()
26085        .enumerate()
26086        .flat_map(move |(ix, (range, highlight_id))| {
26087            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26088                HighlightStyle {
26089                    color: Some(local_player.cursor),
26090                    ..Default::default()
26091                }
26092            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26093                HighlightStyle {
26094                    background_color: Some(local_player.selection),
26095                    ..Default::default()
26096                }
26097            } else if let Some(style) = highlight_id.style(syntax_theme) {
26098                style
26099            } else {
26100                return Default::default();
26101            };
26102            let muted_style = style.highlight(fade_out);
26103
26104            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26105            if range.start >= label.filter_range.end {
26106                if range.start > prev_end {
26107                    runs.push((prev_end..range.start, fade_out));
26108                }
26109                runs.push((range.clone(), muted_style));
26110            } else if range.end <= label.filter_range.end {
26111                runs.push((range.clone(), style));
26112            } else {
26113                runs.push((range.start..label.filter_range.end, style));
26114                runs.push((label.filter_range.end..range.end, muted_style));
26115            }
26116            prev_end = cmp::max(prev_end, range.end);
26117
26118            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26119                runs.push((prev_end..label.text.len(), fade_out));
26120            }
26121
26122            runs
26123        })
26124}
26125
26126pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26127    let mut prev_index = 0;
26128    let mut prev_codepoint: Option<char> = None;
26129    text.char_indices()
26130        .chain([(text.len(), '\0')])
26131        .filter_map(move |(index, codepoint)| {
26132            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26133            let is_boundary = index == text.len()
26134                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26135                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26136            if is_boundary {
26137                let chunk = &text[prev_index..index];
26138                prev_index = index;
26139                Some(chunk)
26140            } else {
26141                None
26142            }
26143        })
26144}
26145
26146/// Given a string of text immediately before the cursor, iterates over possible
26147/// strings a snippet could match to. More precisely: returns an iterator over
26148/// suffixes of `text` created by splitting at word boundaries (before & after
26149/// every non-word character).
26150///
26151/// Shorter suffixes are returned first.
26152pub(crate) fn snippet_candidate_suffixes(
26153    text: &str,
26154    is_word_char: impl Fn(char) -> bool,
26155) -> impl std::iter::Iterator<Item = &str> {
26156    let mut prev_index = text.len();
26157    let mut prev_codepoint = None;
26158    text.char_indices()
26159        .rev()
26160        .chain([(0, '\0')])
26161        .filter_map(move |(index, codepoint)| {
26162            let prev_index = std::mem::replace(&mut prev_index, index);
26163            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26164            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26165                None
26166            } else {
26167                let chunk = &text[prev_index..]; // go to end of string
26168                Some(chunk)
26169            }
26170        })
26171}
26172
26173pub trait RangeToAnchorExt: Sized {
26174    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26175
26176    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26177        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26178        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26179    }
26180}
26181
26182impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26183    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26184        let start_offset = self.start.to_offset(snapshot);
26185        let end_offset = self.end.to_offset(snapshot);
26186        if start_offset == end_offset {
26187            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26188        } else {
26189            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26190        }
26191    }
26192}
26193
26194pub trait RowExt {
26195    fn as_f64(&self) -> f64;
26196
26197    fn next_row(&self) -> Self;
26198
26199    fn previous_row(&self) -> Self;
26200
26201    fn minus(&self, other: Self) -> u32;
26202}
26203
26204impl RowExt for DisplayRow {
26205    fn as_f64(&self) -> f64 {
26206        self.0 as _
26207    }
26208
26209    fn next_row(&self) -> Self {
26210        Self(self.0 + 1)
26211    }
26212
26213    fn previous_row(&self) -> Self {
26214        Self(self.0.saturating_sub(1))
26215    }
26216
26217    fn minus(&self, other: Self) -> u32 {
26218        self.0 - other.0
26219    }
26220}
26221
26222impl RowExt for MultiBufferRow {
26223    fn as_f64(&self) -> f64 {
26224        self.0 as _
26225    }
26226
26227    fn next_row(&self) -> Self {
26228        Self(self.0 + 1)
26229    }
26230
26231    fn previous_row(&self) -> Self {
26232        Self(self.0.saturating_sub(1))
26233    }
26234
26235    fn minus(&self, other: Self) -> u32 {
26236        self.0 - other.0
26237    }
26238}
26239
26240trait RowRangeExt {
26241    type Row;
26242
26243    fn len(&self) -> usize;
26244
26245    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26246}
26247
26248impl RowRangeExt for Range<MultiBufferRow> {
26249    type Row = MultiBufferRow;
26250
26251    fn len(&self) -> usize {
26252        (self.end.0 - self.start.0) as usize
26253    }
26254
26255    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26256        (self.start.0..self.end.0).map(MultiBufferRow)
26257    }
26258}
26259
26260impl RowRangeExt for Range<DisplayRow> {
26261    type Row = DisplayRow;
26262
26263    fn len(&self) -> usize {
26264        (self.end.0 - self.start.0) as usize
26265    }
26266
26267    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26268        (self.start.0..self.end.0).map(DisplayRow)
26269    }
26270}
26271
26272/// If select range has more than one line, we
26273/// just point the cursor to range.start.
26274fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26275    if range.start.row == range.end.row {
26276        range
26277    } else {
26278        range.start..range.start
26279    }
26280}
26281pub struct KillRing(ClipboardItem);
26282impl Global for KillRing {}
26283
26284const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26285
26286enum BreakpointPromptEditAction {
26287    Log,
26288    Condition,
26289    HitCondition,
26290}
26291
26292struct BreakpointPromptEditor {
26293    pub(crate) prompt: Entity<Editor>,
26294    editor: WeakEntity<Editor>,
26295    breakpoint_anchor: Anchor,
26296    breakpoint: Breakpoint,
26297    edit_action: BreakpointPromptEditAction,
26298    block_ids: HashSet<CustomBlockId>,
26299    editor_margins: Arc<Mutex<EditorMargins>>,
26300    _subscriptions: Vec<Subscription>,
26301}
26302
26303impl BreakpointPromptEditor {
26304    const MAX_LINES: u8 = 4;
26305
26306    fn new(
26307        editor: WeakEntity<Editor>,
26308        breakpoint_anchor: Anchor,
26309        breakpoint: Breakpoint,
26310        edit_action: BreakpointPromptEditAction,
26311        window: &mut Window,
26312        cx: &mut Context<Self>,
26313    ) -> Self {
26314        let base_text = match edit_action {
26315            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26316            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26317            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26318        }
26319        .map(|msg| msg.to_string())
26320        .unwrap_or_default();
26321
26322        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26323        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26324
26325        let prompt = cx.new(|cx| {
26326            let mut prompt = Editor::new(
26327                EditorMode::AutoHeight {
26328                    min_lines: 1,
26329                    max_lines: Some(Self::MAX_LINES as usize),
26330                },
26331                buffer,
26332                None,
26333                window,
26334                cx,
26335            );
26336            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26337            prompt.set_show_cursor_when_unfocused(false, cx);
26338            prompt.set_placeholder_text(
26339                match edit_action {
26340                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26341                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26342                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26343                },
26344                window,
26345                cx,
26346            );
26347
26348            prompt
26349        });
26350
26351        Self {
26352            prompt,
26353            editor,
26354            breakpoint_anchor,
26355            breakpoint,
26356            edit_action,
26357            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26358            block_ids: Default::default(),
26359            _subscriptions: vec![],
26360        }
26361    }
26362
26363    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26364        self.block_ids.extend(block_ids)
26365    }
26366
26367    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26368        if let Some(editor) = self.editor.upgrade() {
26369            let message = self
26370                .prompt
26371                .read(cx)
26372                .buffer
26373                .read(cx)
26374                .as_singleton()
26375                .expect("A multi buffer in breakpoint prompt isn't possible")
26376                .read(cx)
26377                .as_rope()
26378                .to_string();
26379
26380            editor.update(cx, |editor, cx| {
26381                editor.edit_breakpoint_at_anchor(
26382                    self.breakpoint_anchor,
26383                    self.breakpoint.clone(),
26384                    match self.edit_action {
26385                        BreakpointPromptEditAction::Log => {
26386                            BreakpointEditAction::EditLogMessage(message.into())
26387                        }
26388                        BreakpointPromptEditAction::Condition => {
26389                            BreakpointEditAction::EditCondition(message.into())
26390                        }
26391                        BreakpointPromptEditAction::HitCondition => {
26392                            BreakpointEditAction::EditHitCondition(message.into())
26393                        }
26394                    },
26395                    cx,
26396                );
26397
26398                editor.remove_blocks(self.block_ids.clone(), None, cx);
26399                cx.focus_self(window);
26400            });
26401        }
26402    }
26403
26404    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26405        self.editor
26406            .update(cx, |editor, cx| {
26407                editor.remove_blocks(self.block_ids.clone(), None, cx);
26408                window.focus(&editor.focus_handle, cx);
26409            })
26410            .log_err();
26411    }
26412
26413    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26414        let settings = ThemeSettings::get_global(cx);
26415        let text_style = TextStyle {
26416            color: if self.prompt.read(cx).read_only(cx) {
26417                cx.theme().colors().text_disabled
26418            } else {
26419                cx.theme().colors().text
26420            },
26421            font_family: settings.buffer_font.family.clone(),
26422            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26423            font_size: settings.buffer_font_size(cx).into(),
26424            font_weight: settings.buffer_font.weight,
26425            line_height: relative(settings.buffer_line_height.value()),
26426            ..Default::default()
26427        };
26428        EditorElement::new(
26429            &self.prompt,
26430            EditorStyle {
26431                background: cx.theme().colors().editor_background,
26432                local_player: cx.theme().players().local(),
26433                text: text_style,
26434                ..Default::default()
26435            },
26436        )
26437    }
26438}
26439
26440impl Render for BreakpointPromptEditor {
26441    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26442        let editor_margins = *self.editor_margins.lock();
26443        let gutter_dimensions = editor_margins.gutter;
26444        h_flex()
26445            .key_context("Editor")
26446            .bg(cx.theme().colors().editor_background)
26447            .border_y_1()
26448            .border_color(cx.theme().status().info_border)
26449            .size_full()
26450            .py(window.line_height() / 2.5)
26451            .on_action(cx.listener(Self::confirm))
26452            .on_action(cx.listener(Self::cancel))
26453            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26454            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26455    }
26456}
26457
26458impl Focusable for BreakpointPromptEditor {
26459    fn focus_handle(&self, cx: &App) -> FocusHandle {
26460        self.prompt.focus_handle(cx)
26461    }
26462}
26463
26464fn all_edits_insertions_or_deletions(
26465    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26466    snapshot: &MultiBufferSnapshot,
26467) -> bool {
26468    let mut all_insertions = true;
26469    let mut all_deletions = true;
26470
26471    for (range, new_text) in edits.iter() {
26472        let range_is_empty = range.to_offset(snapshot).is_empty();
26473        let text_is_empty = new_text.is_empty();
26474
26475        if range_is_empty != text_is_empty {
26476            if range_is_empty {
26477                all_deletions = false;
26478            } else {
26479                all_insertions = false;
26480            }
26481        } else {
26482            return false;
26483        }
26484
26485        if !all_insertions && !all_deletions {
26486            return false;
26487        }
26488    }
26489    all_insertions || all_deletions
26490}
26491
26492struct MissingEditPredictionKeybindingTooltip;
26493
26494impl Render for MissingEditPredictionKeybindingTooltip {
26495    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26496        ui::tooltip_container(cx, |container, cx| {
26497            container
26498                .flex_shrink_0()
26499                .max_w_80()
26500                .min_h(rems_from_px(124.))
26501                .justify_between()
26502                .child(
26503                    v_flex()
26504                        .flex_1()
26505                        .text_ui_sm(cx)
26506                        .child(Label::new("Conflict with Accept Keybinding"))
26507                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26508                )
26509                .child(
26510                    h_flex()
26511                        .pb_1()
26512                        .gap_1()
26513                        .items_end()
26514                        .w_full()
26515                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26516                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26517                        }))
26518                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26519                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26520                        })),
26521                )
26522        })
26523    }
26524}
26525
26526#[derive(Debug, Clone, Copy, PartialEq)]
26527pub struct LineHighlight {
26528    pub background: Background,
26529    pub border: Option<gpui::Hsla>,
26530    pub include_gutter: bool,
26531    pub type_id: Option<TypeId>,
26532}
26533
26534struct LineManipulationResult {
26535    pub new_text: String,
26536    pub line_count_before: usize,
26537    pub line_count_after: usize,
26538}
26539
26540fn render_diff_hunk_controls(
26541    row: u32,
26542    status: &DiffHunkStatus,
26543    hunk_range: Range<Anchor>,
26544    is_created_file: bool,
26545    line_height: Pixels,
26546    editor: &Entity<Editor>,
26547    _window: &mut Window,
26548    cx: &mut App,
26549) -> AnyElement {
26550    h_flex()
26551        .h(line_height)
26552        .mr_1()
26553        .gap_1()
26554        .px_0p5()
26555        .pb_1()
26556        .border_x_1()
26557        .border_b_1()
26558        .border_color(cx.theme().colors().border_variant)
26559        .rounded_b_lg()
26560        .bg(cx.theme().colors().editor_background)
26561        .gap_1()
26562        .block_mouse_except_scroll()
26563        .shadow_md()
26564        .child(if status.has_secondary_hunk() {
26565            Button::new(("stage", row as u64), "Stage")
26566                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26567                .tooltip({
26568                    let focus_handle = editor.focus_handle(cx);
26569                    move |_window, cx| {
26570                        Tooltip::for_action_in(
26571                            "Stage Hunk",
26572                            &::git::ToggleStaged,
26573                            &focus_handle,
26574                            cx,
26575                        )
26576                    }
26577                })
26578                .on_click({
26579                    let editor = editor.clone();
26580                    move |_event, _window, cx| {
26581                        editor.update(cx, |editor, cx| {
26582                            editor.stage_or_unstage_diff_hunks(
26583                                true,
26584                                vec![hunk_range.start..hunk_range.start],
26585                                cx,
26586                            );
26587                        });
26588                    }
26589                })
26590        } else {
26591            Button::new(("unstage", row as u64), "Unstage")
26592                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26593                .tooltip({
26594                    let focus_handle = editor.focus_handle(cx);
26595                    move |_window, cx| {
26596                        Tooltip::for_action_in(
26597                            "Unstage Hunk",
26598                            &::git::ToggleStaged,
26599                            &focus_handle,
26600                            cx,
26601                        )
26602                    }
26603                })
26604                .on_click({
26605                    let editor = editor.clone();
26606                    move |_event, _window, cx| {
26607                        editor.update(cx, |editor, cx| {
26608                            editor.stage_or_unstage_diff_hunks(
26609                                false,
26610                                vec![hunk_range.start..hunk_range.start],
26611                                cx,
26612                            );
26613                        });
26614                    }
26615                })
26616        })
26617        .child(
26618            Button::new(("restore", row as u64), "Restore")
26619                .tooltip({
26620                    let focus_handle = editor.focus_handle(cx);
26621                    move |_window, cx| {
26622                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26623                    }
26624                })
26625                .on_click({
26626                    let editor = editor.clone();
26627                    move |_event, window, cx| {
26628                        editor.update(cx, |editor, cx| {
26629                            let snapshot = editor.snapshot(window, cx);
26630                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26631                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26632                        });
26633                    }
26634                })
26635                .disabled(is_created_file),
26636        )
26637        .when(
26638            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26639            |el| {
26640                el.child(
26641                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26642                        .shape(IconButtonShape::Square)
26643                        .icon_size(IconSize::Small)
26644                        // .disabled(!has_multiple_hunks)
26645                        .tooltip({
26646                            let focus_handle = editor.focus_handle(cx);
26647                            move |_window, cx| {
26648                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26649                            }
26650                        })
26651                        .on_click({
26652                            let editor = editor.clone();
26653                            move |_event, window, cx| {
26654                                editor.update(cx, |editor, cx| {
26655                                    let snapshot = editor.snapshot(window, cx);
26656                                    let position =
26657                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26658                                    editor.go_to_hunk_before_or_after_position(
26659                                        &snapshot,
26660                                        position,
26661                                        Direction::Next,
26662                                        window,
26663                                        cx,
26664                                    );
26665                                    editor.expand_selected_diff_hunks(cx);
26666                                });
26667                            }
26668                        }),
26669                )
26670                .child(
26671                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26672                        .shape(IconButtonShape::Square)
26673                        .icon_size(IconSize::Small)
26674                        // .disabled(!has_multiple_hunks)
26675                        .tooltip({
26676                            let focus_handle = editor.focus_handle(cx);
26677                            move |_window, cx| {
26678                                Tooltip::for_action_in(
26679                                    "Previous Hunk",
26680                                    &GoToPreviousHunk,
26681                                    &focus_handle,
26682                                    cx,
26683                                )
26684                            }
26685                        })
26686                        .on_click({
26687                            let editor = editor.clone();
26688                            move |_event, window, cx| {
26689                                editor.update(cx, |editor, cx| {
26690                                    let snapshot = editor.snapshot(window, cx);
26691                                    let point =
26692                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26693                                    editor.go_to_hunk_before_or_after_position(
26694                                        &snapshot,
26695                                        point,
26696                                        Direction::Prev,
26697                                        window,
26698                                        cx,
26699                                    );
26700                                    editor.expand_selected_diff_hunks(cx);
26701                                });
26702                            }
26703                        }),
26704                )
26705            },
26706        )
26707        .into_any_element()
26708}
26709
26710pub fn multibuffer_context_lines(cx: &App) -> u32 {
26711    EditorSettings::try_get(cx)
26712        .map(|settings| settings.excerpt_context_lines)
26713        .unwrap_or(2)
26714        .min(32)
26715}