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;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   69    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   70    ToPoint,
   71};
   72pub use text::Bias;
   73
   74use ::git::{
   75    Restore,
   76    blame::{BlameEntry, ParsedCommitMessage},
   77    status::FileStatus,
   78};
   79use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   80use anyhow::{Context as _, Result, anyhow};
   81use blink_manager::BlinkManager;
   82use buffer_diff::DiffHunkStatus;
   83use client::{Collaborator, ParticipantIndex, parse_zed_link};
   84use clock::ReplicaId;
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   90use convert_case::{Case, Casing};
   91use dap::TelemetrySpawnLocation;
   92use display_map::*;
   93use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  109    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle,
  110    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  111    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  112};
  113use hover_links::{HoverLink, HoveredLinkState, find_file};
  114use hover_popover::{HoverState, hide_hover};
  115use indent_guides::ActiveIndentGuidesState;
  116use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  117use itertools::{Either, Itertools};
  118use language::{
  119    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  120    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  121    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  122    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  123    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  124    language_settings::{
  125        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  126        all_language_settings, language_settings,
  127    },
  128    point_from_lsp, point_to_lsp, text_diff_with_options,
  129};
  130use linked_editing_ranges::refresh_linked_ranges;
  131use lsp::{
  132    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  133    LanguageServerId,
  134};
  135use lsp_colors::LspColorData;
  136use markdown::Markdown;
  137use mouse_context_menu::MouseContextMenu;
  138use movement::TextLayoutDetails;
  139use multi_buffer::{
  140    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  141};
  142use parking_lot::Mutex;
  143use persistence::DB;
  144use project::{
  145    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  146    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  147    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  148    ProjectPath, ProjectTransaction, TaskSourceKind,
  149    debugger::{
  150        breakpoint_store::{
  151            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  152            BreakpointStore, BreakpointStoreEvent,
  153        },
  154        session::{Session, SessionEvent},
  155    },
  156    git_store::GitStoreEvent,
  157    lsp_store::{
  158        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  159        OpenLspBufferHandle,
  160    },
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  167use serde::{Deserialize, Serialize};
  168use settings::{
  169    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  170    update_settings_file,
  171};
  172use smallvec::{SmallVec, smallvec};
  173use snippet::Snippet;
  174use std::{
  175    any::{Any, TypeId},
  176    borrow::Cow,
  177    cell::{OnceCell, RefCell},
  178    cmp::{self, Ordering, Reverse},
  179    collections::hash_map,
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    inlays::{
  214        InlineValueCache,
  215        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  216    },
  217    scroll::{ScrollOffset, ScrollPixelOffset},
  218    selections_collection::resolve_selections_wrapping_blocks,
  219    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  220};
  221
  222pub const FILE_HEADER_HEIGHT: u32 = 2;
  223pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  224const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  225const MAX_LINE_LEN: usize = 1024;
  226const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  227const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  228pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  229#[doc(hidden)]
  230pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  231pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  232
  233pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  236pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  237
  238pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  239pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  240pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  241
  242pub type RenderDiffHunkControlsFn = Arc<
  243    dyn Fn(
  244        u32,
  245        &DiffHunkStatus,
  246        Range<Anchor>,
  247        bool,
  248        Pixels,
  249        &Entity<Editor>,
  250        &mut Window,
  251        &mut App,
  252    ) -> AnyElement,
  253>;
  254
  255enum ReportEditorEvent {
  256    Saved { auto_saved: bool },
  257    EditorOpened,
  258    Closed,
  259}
  260
  261impl ReportEditorEvent {
  262    pub fn event_type(&self) -> &'static str {
  263        match self {
  264            Self::Saved { .. } => "Editor Saved",
  265            Self::EditorOpened => "Editor Opened",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271pub enum ActiveDebugLine {}
  272pub enum DebugStackFrameLine {}
  273enum DocumentHighlightRead {}
  274enum DocumentHighlightWrite {}
  275enum InputComposition {}
  276pub enum PendingInput {}
  277enum SelectedTextHighlight {}
  278
  279pub enum ConflictsOuter {}
  280pub enum ConflictsOurs {}
  281pub enum ConflictsTheirs {}
  282pub enum ConflictsOursMarker {}
  283pub enum ConflictsTheirsMarker {}
  284
  285#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  286pub enum Navigated {
  287    Yes,
  288    No,
  289}
  290
  291impl Navigated {
  292    pub fn from_bool(yes: bool) -> Navigated {
  293        if yes { Navigated::Yes } else { Navigated::No }
  294    }
  295}
  296
  297#[derive(Debug, Clone, PartialEq, Eq)]
  298enum DisplayDiffHunk {
  299    Folded {
  300        display_row: DisplayRow,
  301    },
  302    Unfolded {
  303        is_created_file: bool,
  304        diff_base_byte_range: Range<usize>,
  305        display_row_range: Range<DisplayRow>,
  306        multi_buffer_range: Range<Anchor>,
  307        status: DiffHunkStatus,
  308    },
  309}
  310
  311pub enum HideMouseCursorOrigin {
  312    TypingAction,
  313    MovementAction,
  314}
  315
  316pub fn init(cx: &mut App) {
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        language_registry: Option<Arc<LanguageRegistry>>,
  378        cx: &mut App,
  379    ) -> Vec<BlockProperties<Anchor>>;
  380
  381    fn render_hover(
  382        &self,
  383        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  384        range: Range<Point>,
  385        buffer_id: BufferId,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Option<Entity<markdown::Markdown>>;
  389
  390    fn open_link(
  391        &self,
  392        editor: &mut Editor,
  393        link: SharedString,
  394        window: &mut Window,
  395        cx: &mut Context<Editor>,
  396    );
  397}
  398
  399pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  400
  401impl GlobalDiagnosticRenderer {
  402    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  403        cx.try_global::<Self>().map(|g| g.0.clone())
  404    }
  405}
  406
  407impl gpui::Global for GlobalDiagnosticRenderer {}
  408pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  409    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  410}
  411
  412pub struct SearchWithinRange;
  413
  414trait InvalidationRegion {
  415    fn ranges(&self) -> &[Range<Anchor>];
  416}
  417
  418#[derive(Clone, Debug, PartialEq)]
  419pub enum SelectPhase {
  420    Begin {
  421        position: DisplayPoint,
  422        add: bool,
  423        click_count: usize,
  424    },
  425    BeginColumnar {
  426        position: DisplayPoint,
  427        reset: bool,
  428        mode: ColumnarMode,
  429        goal_column: u32,
  430    },
  431    Extend {
  432        position: DisplayPoint,
  433        click_count: usize,
  434    },
  435    Update {
  436        position: DisplayPoint,
  437        goal_column: u32,
  438        scroll_delta: gpui::Point<f32>,
  439    },
  440    End,
  441}
  442
  443#[derive(Clone, Debug, PartialEq)]
  444pub enum ColumnarMode {
  445    FromMouse,
  446    FromSelection,
  447}
  448
  449#[derive(Clone, Debug)]
  450pub enum SelectMode {
  451    Character,
  452    Word(Range<Anchor>),
  453    Line(Range<Anchor>),
  454    All,
  455}
  456
  457#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  458pub enum SizingBehavior {
  459    /// The editor will layout itself using `size_full` and will include the vertical
  460    /// scroll margin as requested by user settings.
  461    #[default]
  462    Default,
  463    /// The editor will layout itself using `size_full`, but will not have any
  464    /// vertical overscroll.
  465    ExcludeOverscrollMargin,
  466    /// The editor will request a vertical size according to its content and will be
  467    /// layouted without a vertical scroll margin.
  468    SizeByContent,
  469}
  470
  471#[derive(Clone, PartialEq, Eq, Debug)]
  472pub enum EditorMode {
  473    SingleLine,
  474    AutoHeight {
  475        min_lines: usize,
  476        max_lines: Option<usize>,
  477    },
  478    Full {
  479        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  480        scale_ui_elements_with_buffer_font_size: bool,
  481        /// When set to `true`, the editor will render a background for the active line.
  482        show_active_line_background: bool,
  483        /// Determines the sizing behavior for this editor
  484        sizing_behavior: SizingBehavior,
  485    },
  486    Minimap {
  487        parent: WeakEntity<Editor>,
  488    },
  489}
  490
  491impl EditorMode {
  492    pub fn full() -> Self {
  493        Self::Full {
  494            scale_ui_elements_with_buffer_font_size: true,
  495            show_active_line_background: true,
  496            sizing_behavior: SizingBehavior::Default,
  497        }
  498    }
  499
  500    #[inline]
  501    pub fn is_full(&self) -> bool {
  502        matches!(self, Self::Full { .. })
  503    }
  504
  505    #[inline]
  506    pub fn is_single_line(&self) -> bool {
  507        matches!(self, Self::SingleLine { .. })
  508    }
  509
  510    #[inline]
  511    fn is_minimap(&self) -> bool {
  512        matches!(self, Self::Minimap { .. })
  513    }
  514}
  515
  516#[derive(Copy, Clone, Debug)]
  517pub enum SoftWrap {
  518    /// Prefer not to wrap at all.
  519    ///
  520    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  521    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  522    GitDiff,
  523    /// Prefer a single line generally, unless an overly long line is encountered.
  524    None,
  525    /// Soft wrap lines that exceed the editor width.
  526    EditorWidth,
  527    /// Soft wrap lines at the preferred line length.
  528    Column(u32),
  529    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  530    Bounded(u32),
  531}
  532
  533#[derive(Clone)]
  534pub struct EditorStyle {
  535    pub background: Hsla,
  536    pub border: Hsla,
  537    pub local_player: PlayerColor,
  538    pub text: TextStyle,
  539    pub scrollbar_width: Pixels,
  540    pub syntax: Arc<SyntaxTheme>,
  541    pub status: StatusColors,
  542    pub inlay_hints_style: HighlightStyle,
  543    pub edit_prediction_styles: EditPredictionStyles,
  544    pub unnecessary_code_fade: f32,
  545    pub show_underlines: bool,
  546}
  547
  548impl Default for EditorStyle {
  549    fn default() -> Self {
  550        Self {
  551            background: Hsla::default(),
  552            border: Hsla::default(),
  553            local_player: PlayerColor::default(),
  554            text: TextStyle::default(),
  555            scrollbar_width: Pixels::default(),
  556            syntax: Default::default(),
  557            // HACK: Status colors don't have a real default.
  558            // We should look into removing the status colors from the editor
  559            // style and retrieve them directly from the theme.
  560            status: StatusColors::dark(),
  561            inlay_hints_style: HighlightStyle::default(),
  562            edit_prediction_styles: EditPredictionStyles {
  563                insertion: HighlightStyle::default(),
  564                whitespace: HighlightStyle::default(),
  565            },
  566            unnecessary_code_fade: Default::default(),
  567            show_underlines: true,
  568        }
  569    }
  570}
  571
  572pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  573    let show_background = language_settings::language_settings(None, None, cx)
  574        .inlay_hints
  575        .show_background;
  576
  577    let mut style = cx.theme().syntax().get("hint");
  578
  579    if style.color.is_none() {
  580        style.color = Some(cx.theme().status().hint);
  581    }
  582
  583    if !show_background {
  584        style.background_color = None;
  585        return style;
  586    }
  587
  588    if style.background_color.is_none() {
  589        style.background_color = Some(cx.theme().status().hint_background);
  590    }
  591
  592    style
  593}
  594
  595pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  596    EditPredictionStyles {
  597        insertion: HighlightStyle {
  598            color: Some(cx.theme().status().predictive),
  599            ..HighlightStyle::default()
  600        },
  601        whitespace: HighlightStyle {
  602            background_color: Some(cx.theme().status().created_background),
  603            ..HighlightStyle::default()
  604        },
  605    }
  606}
  607
  608type CompletionId = usize;
  609
  610pub(crate) enum EditDisplayMode {
  611    TabAccept,
  612    DiffPopover,
  613    Inline,
  614}
  615
  616enum EditPrediction {
  617    Edit {
  618        edits: Vec<(Range<Anchor>, Arc<str>)>,
  619        edit_preview: Option<EditPreview>,
  620        display_mode: EditDisplayMode,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in the active editor
  624    MoveWithin {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628    /// Move to a specific location in a different editor (not the active one)
  629    MoveOutside {
  630        target: language::Anchor,
  631        snapshot: BufferSnapshot,
  632    },
  633}
  634
  635struct EditPredictionState {
  636    inlay_ids: Vec<InlayId>,
  637    completion: EditPrediction,
  638    completion_id: Option<SharedString>,
  639    invalidation_range: Option<Range<Anchor>>,
  640}
  641
  642enum EditPredictionSettings {
  643    Disabled,
  644    Enabled {
  645        show_in_menu: bool,
  646        preview_requires_modifier: bool,
  647    },
  648}
  649
  650enum EditPredictionHighlight {}
  651
  652#[derive(Debug, Clone)]
  653struct InlineDiagnostic {
  654    message: SharedString,
  655    group_id: usize,
  656    is_primary: bool,
  657    start: Point,
  658    severity: lsp::DiagnosticSeverity,
  659}
  660
  661pub enum MenuEditPredictionsPolicy {
  662    Never,
  663    ByProvider,
  664}
  665
  666pub enum EditPredictionPreview {
  667    /// Modifier is not pressed
  668    Inactive { released_too_fast: bool },
  669    /// Modifier pressed
  670    Active {
  671        since: Instant,
  672        previous_scroll_position: Option<ScrollAnchor>,
  673    },
  674}
  675
  676impl EditPredictionPreview {
  677    pub fn released_too_fast(&self) -> bool {
  678        match self {
  679            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  680            EditPredictionPreview::Active { .. } => false,
  681        }
  682    }
  683
  684    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  685        if let EditPredictionPreview::Active {
  686            previous_scroll_position,
  687            ..
  688        } = self
  689        {
  690            *previous_scroll_position = scroll_position;
  691        }
  692    }
  693}
  694
  695pub struct ContextMenuOptions {
  696    pub min_entries_visible: usize,
  697    pub max_entries_visible: usize,
  698    pub placement: Option<ContextMenuPlacement>,
  699}
  700
  701#[derive(Debug, Clone, PartialEq, Eq)]
  702pub enum ContextMenuPlacement {
  703    Above,
  704    Below,
  705}
  706
  707#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  708struct EditorActionId(usize);
  709
  710impl EditorActionId {
  711    pub fn post_inc(&mut self) -> Self {
  712        let answer = self.0;
  713
  714        *self = Self(answer + 1);
  715
  716        Self(answer)
  717    }
  718}
  719
  720// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  721// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  722
  723type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  724type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  725
  726#[derive(Default)]
  727struct ScrollbarMarkerState {
  728    scrollbar_size: Size<Pixels>,
  729    dirty: bool,
  730    markers: Arc<[PaintQuad]>,
  731    pending_refresh: Option<Task<Result<()>>>,
  732}
  733
  734impl ScrollbarMarkerState {
  735    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  736        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  737    }
  738}
  739
  740#[derive(Clone, Copy, PartialEq, Eq)]
  741pub enum MinimapVisibility {
  742    Disabled,
  743    Enabled {
  744        /// The configuration currently present in the users settings.
  745        setting_configuration: bool,
  746        /// Whether to override the currently set visibility from the users setting.
  747        toggle_override: bool,
  748    },
  749}
  750
  751impl MinimapVisibility {
  752    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  753        if mode.is_full() {
  754            Self::Enabled {
  755                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  756                toggle_override: false,
  757            }
  758        } else {
  759            Self::Disabled
  760        }
  761    }
  762
  763    fn hidden(&self) -> Self {
  764        match *self {
  765            Self::Enabled {
  766                setting_configuration,
  767                ..
  768            } => Self::Enabled {
  769                setting_configuration,
  770                toggle_override: setting_configuration,
  771            },
  772            Self::Disabled => Self::Disabled,
  773        }
  774    }
  775
  776    fn disabled(&self) -> bool {
  777        matches!(*self, Self::Disabled)
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  815pub enum BufferSerialization {
  816    All,
  817    NonDirtyBuffers,
  818}
  819
  820impl BufferSerialization {
  821    fn new(restore_unsaved_buffers: bool) -> Self {
  822        if restore_unsaved_buffers {
  823            Self::All
  824        } else {
  825            Self::NonDirtyBuffers
  826        }
  827    }
  828}
  829
  830#[derive(Clone, Debug)]
  831struct RunnableTasks {
  832    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  833    offset: multi_buffer::Anchor,
  834    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  835    column: u32,
  836    // Values of all named captures, including those starting with '_'
  837    extra_variables: HashMap<String, String>,
  838    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  839    context_range: Range<BufferOffset>,
  840}
  841
  842impl RunnableTasks {
  843    fn resolve<'a>(
  844        &'a self,
  845        cx: &'a task::TaskContext,
  846    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  847        self.templates.iter().filter_map(|(kind, template)| {
  848            template
  849                .resolve_task(&kind.to_id_base(), cx)
  850                .map(|task| (kind.clone(), task))
  851        })
  852    }
  853}
  854
  855#[derive(Clone)]
  856pub struct ResolvedTasks {
  857    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  858    position: Anchor,
  859}
  860
  861/// Addons allow storing per-editor state in other crates (e.g. Vim)
  862pub trait Addon: 'static {
  863    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  864
  865    fn render_buffer_header_controls(
  866        &self,
  867        _: &ExcerptInfo,
  868        _: &Window,
  869        _: &App,
  870    ) -> Option<AnyElement> {
  871        None
  872    }
  873
  874    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    pub collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    next_inlay_id: usize,
 1126    next_color_inlay_id: usize,
 1127    _subscriptions: Vec<Subscription>,
 1128    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1129    gutter_dimensions: GutterDimensions,
 1130    style: Option<EditorStyle>,
 1131    text_style_refinement: Option<TextStyleRefinement>,
 1132    next_editor_action_id: EditorActionId,
 1133    editor_actions: Rc<
 1134        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1135    >,
 1136    use_autoclose: bool,
 1137    use_auto_surround: bool,
 1138    auto_replace_emoji_shortcode: bool,
 1139    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1140    show_git_blame_gutter: bool,
 1141    show_git_blame_inline: bool,
 1142    show_git_blame_inline_delay_task: Option<Task<()>>,
 1143    git_blame_inline_enabled: bool,
 1144    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1145    buffer_serialization: Option<BufferSerialization>,
 1146    show_selection_menu: Option<bool>,
 1147    blame: Option<Entity<GitBlame>>,
 1148    blame_subscription: Option<Subscription>,
 1149    custom_context_menu: Option<
 1150        Box<
 1151            dyn 'static
 1152                + Fn(
 1153                    &mut Self,
 1154                    DisplayPoint,
 1155                    &mut Window,
 1156                    &mut Context<Self>,
 1157                ) -> Option<Entity<ui::ContextMenu>>,
 1158        >,
 1159    >,
 1160    last_bounds: Option<Bounds<Pixels>>,
 1161    last_position_map: Option<Rc<PositionMap>>,
 1162    expect_bounds_change: Option<Bounds<Pixels>>,
 1163    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1164    tasks_update_task: Option<Task<()>>,
 1165    breakpoint_store: Option<Entity<BreakpointStore>>,
 1166    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1167    hovered_diff_hunk_row: Option<DisplayRow>,
 1168    pull_diagnostics_task: Task<()>,
 1169    in_project_search: bool,
 1170    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1171    breadcrumb_header: Option<String>,
 1172    focused_block: Option<FocusedBlock>,
 1173    next_scroll_position: NextScrollCursorCenterTopBottom,
 1174    addons: HashMap<TypeId, Box<dyn Addon>>,
 1175    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1176    load_diff_task: Option<Shared<Task<()>>>,
 1177    /// Whether we are temporarily displaying a diff other than git's
 1178    temporary_diff_override: bool,
 1179    selection_mark_mode: bool,
 1180    toggle_fold_multiple_buffers: Task<()>,
 1181    _scroll_cursor_center_top_bottom_task: Task<()>,
 1182    serialize_selections: Task<()>,
 1183    serialize_folds: Task<()>,
 1184    mouse_cursor_hidden: bool,
 1185    minimap: Option<Entity<Self>>,
 1186    hide_mouse_mode: HideMouseMode,
 1187    pub change_list: ChangeList,
 1188    inline_value_cache: InlineValueCache,
 1189
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    inlay_hints: Option<LspInlayHintData>,
 1195    folding_newlines: Task<()>,
 1196    select_next_is_case_sensitive: Option<bool>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1199    accent_overrides: Vec<SharedString>,
 1200    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1201}
 1202
 1203fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1204    if debounce_ms > 0 {
 1205        Some(Duration::from_millis(debounce_ms))
 1206    } else {
 1207        None
 1208    }
 1209}
 1210
 1211#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1212enum NextScrollCursorCenterTopBottom {
 1213    #[default]
 1214    Center,
 1215    Top,
 1216    Bottom,
 1217}
 1218
 1219impl NextScrollCursorCenterTopBottom {
 1220    fn next(&self) -> Self {
 1221        match self {
 1222            Self::Center => Self::Top,
 1223            Self::Top => Self::Bottom,
 1224            Self::Bottom => Self::Center,
 1225        }
 1226    }
 1227}
 1228
 1229#[derive(Clone)]
 1230pub struct EditorSnapshot {
 1231    pub mode: EditorMode,
 1232    show_gutter: bool,
 1233    show_line_numbers: Option<bool>,
 1234    show_git_diff_gutter: Option<bool>,
 1235    show_code_actions: Option<bool>,
 1236    show_runnables: Option<bool>,
 1237    show_breakpoints: Option<bool>,
 1238    git_blame_gutter_max_author_length: Option<usize>,
 1239    pub display_snapshot: DisplaySnapshot,
 1240    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1241    is_focused: bool,
 1242    scroll_anchor: ScrollAnchor,
 1243    ongoing_scroll: OngoingScroll,
 1244    current_line_highlight: CurrentLineHighlight,
 1245    gutter_hovered: bool,
 1246}
 1247
 1248#[derive(Default, Debug, Clone, Copy)]
 1249pub struct GutterDimensions {
 1250    pub left_padding: Pixels,
 1251    pub right_padding: Pixels,
 1252    pub width: Pixels,
 1253    pub margin: Pixels,
 1254    pub git_blame_entries_width: Option<Pixels>,
 1255}
 1256
 1257impl GutterDimensions {
 1258    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1259        Self {
 1260            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1261            ..Default::default()
 1262        }
 1263    }
 1264
 1265    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1266        -cx.text_system().descent(font_id, font_size)
 1267    }
 1268    /// The full width of the space taken up by the gutter.
 1269    pub fn full_width(&self) -> Pixels {
 1270        self.margin + self.width
 1271    }
 1272
 1273    /// The width of the space reserved for the fold indicators,
 1274    /// use alongside 'justify_end' and `gutter_width` to
 1275    /// right align content with the line numbers
 1276    pub fn fold_area_width(&self) -> Pixels {
 1277        self.margin + self.right_padding
 1278    }
 1279}
 1280
 1281struct CharacterDimensions {
 1282    em_width: Pixels,
 1283    em_advance: Pixels,
 1284    line_height: Pixels,
 1285}
 1286
 1287#[derive(Debug)]
 1288pub struct RemoteSelection {
 1289    pub replica_id: ReplicaId,
 1290    pub selection: Selection<Anchor>,
 1291    pub cursor_shape: CursorShape,
 1292    pub collaborator_id: CollaboratorId,
 1293    pub line_mode: bool,
 1294    pub user_name: Option<SharedString>,
 1295    pub color: PlayerColor,
 1296}
 1297
 1298#[derive(Clone, Debug)]
 1299struct SelectionHistoryEntry {
 1300    selections: Arc<[Selection<Anchor>]>,
 1301    select_next_state: Option<SelectNextState>,
 1302    select_prev_state: Option<SelectNextState>,
 1303    add_selections_state: Option<AddSelectionsState>,
 1304}
 1305
 1306#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1307enum SelectionHistoryMode {
 1308    #[default]
 1309    Normal,
 1310    Undoing,
 1311    Redoing,
 1312    Skipping,
 1313}
 1314
 1315#[derive(Clone, PartialEq, Eq, Hash)]
 1316struct HoveredCursor {
 1317    replica_id: ReplicaId,
 1318    selection_id: usize,
 1319}
 1320
 1321#[derive(Debug)]
 1322/// SelectionEffects controls the side-effects of updating the selection.
 1323///
 1324/// The default behaviour does "what you mostly want":
 1325/// - it pushes to the nav history if the cursor moved by >10 lines
 1326/// - it re-triggers completion requests
 1327/// - it scrolls to fit
 1328///
 1329/// You might want to modify these behaviours. For example when doing a "jump"
 1330/// like go to definition, we always want to add to nav history; but when scrolling
 1331/// in vim mode we never do.
 1332///
 1333/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1334/// move.
 1335#[derive(Clone)]
 1336pub struct SelectionEffects {
 1337    nav_history: Option<bool>,
 1338    completions: bool,
 1339    scroll: Option<Autoscroll>,
 1340}
 1341
 1342impl Default for SelectionEffects {
 1343    fn default() -> Self {
 1344        Self {
 1345            nav_history: None,
 1346            completions: true,
 1347            scroll: Some(Autoscroll::fit()),
 1348        }
 1349    }
 1350}
 1351impl SelectionEffects {
 1352    pub fn scroll(scroll: Autoscroll) -> Self {
 1353        Self {
 1354            scroll: Some(scroll),
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn no_scroll() -> Self {
 1360        Self {
 1361            scroll: None,
 1362            ..Default::default()
 1363        }
 1364    }
 1365
 1366    pub fn completions(self, completions: bool) -> Self {
 1367        Self {
 1368            completions,
 1369            ..self
 1370        }
 1371    }
 1372
 1373    pub fn nav_history(self, nav_history: bool) -> Self {
 1374        Self {
 1375            nav_history: Some(nav_history),
 1376            ..self
 1377        }
 1378    }
 1379}
 1380
 1381struct DeferredSelectionEffectsState {
 1382    changed: bool,
 1383    effects: SelectionEffects,
 1384    old_cursor_position: Anchor,
 1385    history_entry: SelectionHistoryEntry,
 1386}
 1387
 1388#[derive(Default)]
 1389struct SelectionHistory {
 1390    #[allow(clippy::type_complexity)]
 1391    selections_by_transaction:
 1392        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1393    mode: SelectionHistoryMode,
 1394    undo_stack: VecDeque<SelectionHistoryEntry>,
 1395    redo_stack: VecDeque<SelectionHistoryEntry>,
 1396}
 1397
 1398impl SelectionHistory {
 1399    #[track_caller]
 1400    fn insert_transaction(
 1401        &mut self,
 1402        transaction_id: TransactionId,
 1403        selections: Arc<[Selection<Anchor>]>,
 1404    ) {
 1405        if selections.is_empty() {
 1406            log::error!(
 1407                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1408                std::panic::Location::caller()
 1409            );
 1410            return;
 1411        }
 1412        self.selections_by_transaction
 1413            .insert(transaction_id, (selections, None));
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction(
 1418        &self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get(&transaction_id)
 1422    }
 1423
 1424    #[allow(clippy::type_complexity)]
 1425    fn transaction_mut(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1429        self.selections_by_transaction.get_mut(&transaction_id)
 1430    }
 1431
 1432    fn push(&mut self, entry: SelectionHistoryEntry) {
 1433        if !entry.selections.is_empty() {
 1434            match self.mode {
 1435                SelectionHistoryMode::Normal => {
 1436                    self.push_undo(entry);
 1437                    self.redo_stack.clear();
 1438                }
 1439                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1440                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1441                SelectionHistoryMode::Skipping => {}
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .undo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.undo_stack.push_back(entry);
 1453            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.undo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458
 1459    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1460        if self
 1461            .redo_stack
 1462            .back()
 1463            .is_none_or(|e| e.selections != entry.selections)
 1464        {
 1465            self.redo_stack.push_back(entry);
 1466            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1467                self.redo_stack.pop_front();
 1468            }
 1469        }
 1470    }
 1471}
 1472
 1473#[derive(Clone, Copy)]
 1474pub struct RowHighlightOptions {
 1475    pub autoscroll: bool,
 1476    pub include_gutter: bool,
 1477}
 1478
 1479impl Default for RowHighlightOptions {
 1480    fn default() -> Self {
 1481        Self {
 1482            autoscroll: Default::default(),
 1483            include_gutter: true,
 1484        }
 1485    }
 1486}
 1487
 1488struct RowHighlight {
 1489    index: usize,
 1490    range: Range<Anchor>,
 1491    color: Hsla,
 1492    options: RowHighlightOptions,
 1493    type_id: TypeId,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsState {
 1498    groups: Vec<AddSelectionsGroup>,
 1499}
 1500
 1501#[derive(Clone, Debug)]
 1502struct AddSelectionsGroup {
 1503    above: bool,
 1504    stack: Vec<usize>,
 1505}
 1506
 1507#[derive(Clone)]
 1508struct SelectNextState {
 1509    query: AhoCorasick,
 1510    wordwise: bool,
 1511    done: bool,
 1512}
 1513
 1514impl std::fmt::Debug for SelectNextState {
 1515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1516        f.debug_struct(std::any::type_name::<Self>())
 1517            .field("wordwise", &self.wordwise)
 1518            .field("done", &self.done)
 1519            .finish()
 1520    }
 1521}
 1522
 1523#[derive(Debug)]
 1524struct AutocloseRegion {
 1525    selection_id: usize,
 1526    range: Range<Anchor>,
 1527    pair: BracketPair,
 1528}
 1529
 1530#[derive(Debug)]
 1531struct SnippetState {
 1532    ranges: Vec<Vec<Range<Anchor>>>,
 1533    active_index: usize,
 1534    choices: Vec<Option<Vec<String>>>,
 1535}
 1536
 1537#[doc(hidden)]
 1538pub struct RenameState {
 1539    pub range: Range<Anchor>,
 1540    pub old_name: Arc<str>,
 1541    pub editor: Entity<Editor>,
 1542    block_id: CustomBlockId,
 1543}
 1544
 1545struct InvalidationStack<T>(Vec<T>);
 1546
 1547struct RegisteredEditPredictionProvider {
 1548    provider: Arc<dyn EditPredictionProviderHandle>,
 1549    _subscription: Subscription,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553pub struct ActiveDiagnosticGroup {
 1554    pub active_range: Range<Anchor>,
 1555    pub active_message: String,
 1556    pub group_id: usize,
 1557    pub blocks: HashSet<CustomBlockId>,
 1558}
 1559
 1560#[derive(Debug, PartialEq, Eq)]
 1561
 1562pub(crate) enum ActiveDiagnostic {
 1563    None,
 1564    All,
 1565    Group(ActiveDiagnosticGroup),
 1566}
 1567
 1568#[derive(Serialize, Deserialize, Clone, Debug)]
 1569pub struct ClipboardSelection {
 1570    /// The number of bytes in this selection.
 1571    pub len: usize,
 1572    /// Whether this was a full-line selection.
 1573    pub is_entire_line: bool,
 1574    /// The indentation of the first line when this content was originally copied.
 1575    pub first_line_indent: u32,
 1576}
 1577
 1578// selections, scroll behavior, was newest selection reversed
 1579type SelectSyntaxNodeHistoryState = (
 1580    Box<[Selection<MultiBufferOffset>]>,
 1581    SelectSyntaxNodeScrollBehavior,
 1582    bool,
 1583);
 1584
 1585#[derive(Default)]
 1586struct SelectSyntaxNodeHistory {
 1587    stack: Vec<SelectSyntaxNodeHistoryState>,
 1588    // disable temporarily to allow changing selections without losing the stack
 1589    pub disable_clearing: bool,
 1590}
 1591
 1592impl SelectSyntaxNodeHistory {
 1593    pub fn try_clear(&mut self) {
 1594        if !self.disable_clearing {
 1595            self.stack.clear();
 1596        }
 1597    }
 1598
 1599    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1600        self.stack.push(selection);
 1601    }
 1602
 1603    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1604        self.stack.pop()
 1605    }
 1606}
 1607
 1608enum SelectSyntaxNodeScrollBehavior {
 1609    CursorTop,
 1610    FitSelection,
 1611    CursorBottom,
 1612}
 1613
 1614#[derive(Debug)]
 1615pub(crate) struct NavigationData {
 1616    cursor_anchor: Anchor,
 1617    cursor_position: Point,
 1618    scroll_anchor: ScrollAnchor,
 1619    scroll_top_row: u32,
 1620}
 1621
 1622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1623pub enum GotoDefinitionKind {
 1624    Symbol,
 1625    Declaration,
 1626    Type,
 1627    Implementation,
 1628}
 1629
 1630pub enum FormatTarget {
 1631    Buffers(HashSet<Entity<Buffer>>),
 1632    Ranges(Vec<Range<MultiBufferPoint>>),
 1633}
 1634
 1635pub(crate) struct FocusedBlock {
 1636    id: BlockId,
 1637    focus_handle: WeakFocusHandle,
 1638}
 1639
 1640#[derive(Clone)]
 1641enum JumpData {
 1642    MultiBufferRow {
 1643        row: MultiBufferRow,
 1644        line_offset_from_top: u32,
 1645    },
 1646    MultiBufferPoint {
 1647        excerpt_id: ExcerptId,
 1648        position: Point,
 1649        anchor: text::Anchor,
 1650        line_offset_from_top: u32,
 1651    },
 1652}
 1653
 1654pub enum MultibufferSelectionMode {
 1655    First,
 1656    All,
 1657}
 1658
 1659#[derive(Clone, Copy, Debug, Default)]
 1660pub struct RewrapOptions {
 1661    pub override_language_settings: bool,
 1662    pub preserve_existing_whitespace: bool,
 1663}
 1664
 1665impl Editor {
 1666    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1667        let buffer = cx.new(|cx| Buffer::local("", cx));
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1670    }
 1671
 1672    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1673        let buffer = cx.new(|cx| Buffer::local("", cx));
 1674        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1675        Self::new(EditorMode::full(), buffer, None, window, cx)
 1676    }
 1677
 1678    pub fn auto_height(
 1679        min_lines: usize,
 1680        max_lines: usize,
 1681        window: &mut Window,
 1682        cx: &mut Context<Self>,
 1683    ) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(
 1687            EditorMode::AutoHeight {
 1688                min_lines,
 1689                max_lines: Some(max_lines),
 1690            },
 1691            buffer,
 1692            None,
 1693            window,
 1694            cx,
 1695        )
 1696    }
 1697
 1698    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1699    /// The editor grows as tall as needed to fit its content.
 1700    pub fn auto_height_unbounded(
 1701        min_lines: usize,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        let buffer = cx.new(|cx| Buffer::local("", cx));
 1706        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1707        Self::new(
 1708            EditorMode::AutoHeight {
 1709                min_lines,
 1710                max_lines: None,
 1711            },
 1712            buffer,
 1713            None,
 1714            window,
 1715            cx,
 1716        )
 1717    }
 1718
 1719    pub fn for_buffer(
 1720        buffer: Entity<Buffer>,
 1721        project: Option<Entity<Project>>,
 1722        window: &mut Window,
 1723        cx: &mut Context<Self>,
 1724    ) -> Self {
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn for_multibuffer(
 1730        buffer: Entity<MultiBuffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        Self::new(EditorMode::full(), buffer, project, window, cx)
 1736    }
 1737
 1738    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let mut clone = Self::new(
 1740            self.mode.clone(),
 1741            self.buffer.clone(),
 1742            self.project.clone(),
 1743            window,
 1744            cx,
 1745        );
 1746        self.display_map.update(cx, |display_map, cx| {
 1747            let snapshot = display_map.snapshot(cx);
 1748            clone.display_map.update(cx, |display_map, cx| {
 1749                display_map.set_state(&snapshot, cx);
 1750            });
 1751        });
 1752        clone.folds_did_change(cx);
 1753        clone.selections.clone_state(&self.selections);
 1754        clone.scroll_manager.clone_state(&self.scroll_manager);
 1755        clone.searchable = self.searchable;
 1756        clone.read_only = self.read_only;
 1757        clone
 1758    }
 1759
 1760    pub fn new(
 1761        mode: EditorMode,
 1762        buffer: Entity<MultiBuffer>,
 1763        project: Option<Entity<Project>>,
 1764        window: &mut Window,
 1765        cx: &mut Context<Self>,
 1766    ) -> Self {
 1767        Editor::new_internal(mode, buffer, project, None, window, cx)
 1768    }
 1769
 1770    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1771        let multi_buffer = self.buffer().read(cx);
 1772        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1773        let multi_buffer_visible_start = self
 1774            .scroll_manager
 1775            .anchor()
 1776            .anchor
 1777            .to_point(&multi_buffer_snapshot);
 1778        let max_row = multi_buffer_snapshot.max_point().row;
 1779
 1780        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1781        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1782
 1783        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1784            let outline_items = buffer
 1785                .outline_items_containing(
 1786                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1787                    true,
 1788                    self.style().map(|style| style.syntax.as_ref()),
 1789                )
 1790                .into_iter()
 1791                .map(|outline_item| OutlineItem {
 1792                    depth: outline_item.depth,
 1793                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1794                    source_range_for_text: Anchor::range_in_buffer(
 1795                        *excerpt_id,
 1796                        outline_item.source_range_for_text,
 1797                    ),
 1798                    text: outline_item.text,
 1799                    highlight_ranges: outline_item.highlight_ranges,
 1800                    name_ranges: outline_item.name_ranges,
 1801                    body_range: outline_item
 1802                        .body_range
 1803                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1804                    annotation_range: outline_item
 1805                        .annotation_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1807                });
 1808            return Some(outline_items.collect());
 1809        }
 1810
 1811        None
 1812    }
 1813
 1814    fn new_internal(
 1815        mode: EditorMode,
 1816        multi_buffer: Entity<MultiBuffer>,
 1817        project: Option<Entity<Project>>,
 1818        display_map: Option<Entity<DisplayMap>>,
 1819        window: &mut Window,
 1820        cx: &mut Context<Self>,
 1821    ) -> Self {
 1822        debug_assert!(
 1823            display_map.is_none() || mode.is_minimap(),
 1824            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1825        );
 1826
 1827        let full_mode = mode.is_full();
 1828        let is_minimap = mode.is_minimap();
 1829        let diagnostics_max_severity = if full_mode {
 1830            EditorSettings::get_global(cx)
 1831                .diagnostics_max_severity
 1832                .unwrap_or(DiagnosticSeverity::Hint)
 1833        } else {
 1834            DiagnosticSeverity::Off
 1835        };
 1836        let style = window.text_style();
 1837        let font_size = style.font_size.to_pixels(window.rem_size());
 1838        let editor = cx.entity().downgrade();
 1839        let fold_placeholder = FoldPlaceholder {
 1840            constrain_width: false,
 1841            render: Arc::new(move |fold_id, fold_range, cx| {
 1842                let editor = editor.clone();
 1843                div()
 1844                    .id(fold_id)
 1845                    .bg(cx.theme().colors().ghost_element_background)
 1846                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1847                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1848                    .rounded_xs()
 1849                    .size_full()
 1850                    .cursor_pointer()
 1851                    .child("")
 1852                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1853                    .on_click(move |_, _window, cx| {
 1854                        editor
 1855                            .update(cx, |editor, cx| {
 1856                                editor.unfold_ranges(
 1857                                    &[fold_range.start..fold_range.end],
 1858                                    true,
 1859                                    false,
 1860                                    cx,
 1861                                );
 1862                                cx.stop_propagation();
 1863                            })
 1864                            .ok();
 1865                    })
 1866                    .into_any()
 1867            }),
 1868            merge_adjacent: true,
 1869            ..FoldPlaceholder::default()
 1870        };
 1871        let display_map = display_map.unwrap_or_else(|| {
 1872            cx.new(|cx| {
 1873                DisplayMap::new(
 1874                    multi_buffer.clone(),
 1875                    style.font(),
 1876                    font_size,
 1877                    None,
 1878                    FILE_HEADER_HEIGHT,
 1879                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1880                    fold_placeholder,
 1881                    diagnostics_max_severity,
 1882                    cx,
 1883                )
 1884            })
 1885        });
 1886
 1887        let selections = SelectionsCollection::new();
 1888
 1889        let blink_manager = cx.new(|cx| {
 1890            let mut blink_manager = BlinkManager::new(
 1891                CURSOR_BLINK_INTERVAL,
 1892                |cx| EditorSettings::get_global(cx).cursor_blink,
 1893                cx,
 1894            );
 1895            if is_minimap {
 1896                blink_manager.disable(cx);
 1897            }
 1898            blink_manager
 1899        });
 1900
 1901        let soft_wrap_mode_override =
 1902            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1903
 1904        let mut project_subscriptions = Vec::new();
 1905        if full_mode && let Some(project) = project.as_ref() {
 1906            project_subscriptions.push(cx.subscribe_in(
 1907                project,
 1908                window,
 1909                |editor, _, event, window, cx| match event {
 1910                    project::Event::RefreshCodeLens => {
 1911                        // we always query lens with actions, without storing them, always refreshing them
 1912                    }
 1913                    project::Event::RefreshInlayHints {
 1914                        server_id,
 1915                        request_id,
 1916                    } => {
 1917                        editor.refresh_inlay_hints(
 1918                            InlayHintRefreshReason::RefreshRequested {
 1919                                server_id: *server_id,
 1920                                request_id: *request_id,
 1921                            },
 1922                            cx,
 1923                        );
 1924                    }
 1925                    project::Event::LanguageServerRemoved(..) => {
 1926                        if editor.tasks_update_task.is_none() {
 1927                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1928                        }
 1929                        editor.registered_buffers.clear();
 1930                        editor.register_visible_buffers(cx);
 1931                    }
 1932                    project::Event::LanguageServerAdded(..) => {
 1933                        if editor.tasks_update_task.is_none() {
 1934                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1935                        }
 1936                    }
 1937                    project::Event::SnippetEdit(id, snippet_edits) => {
 1938                        // todo(lw): Non singletons
 1939                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1940                            let snapshot = buffer.read(cx).snapshot();
 1941                            let focus_handle = editor.focus_handle(cx);
 1942                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1943                                for (range, snippet) in snippet_edits {
 1944                                    let buffer_range =
 1945                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1946                                    editor
 1947                                        .insert_snippet(
 1948                                            &[MultiBufferOffset(buffer_range.start)
 1949                                                ..MultiBufferOffset(buffer_range.end)],
 1950                                            snippet.clone(),
 1951                                            window,
 1952                                            cx,
 1953                                        )
 1954                                        .ok();
 1955                                }
 1956                            }
 1957                        }
 1958                    }
 1959                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1960                        let buffer_id = *buffer_id;
 1961                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1962                            editor.register_buffer(buffer_id, cx);
 1963                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1964                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1965                            refresh_linked_ranges(editor, window, cx);
 1966                            editor.refresh_code_actions(window, cx);
 1967                            editor.refresh_document_highlights(cx);
 1968                        }
 1969                    }
 1970
 1971                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1972                        let Some(workspace) = editor.workspace() else {
 1973                            return;
 1974                        };
 1975                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1976                        else {
 1977                            return;
 1978                        };
 1979
 1980                        if active_editor.entity_id() == cx.entity_id() {
 1981                            let entity_id = cx.entity_id();
 1982                            workspace.update(cx, |this, cx| {
 1983                                this.panes_mut()
 1984                                    .iter_mut()
 1985                                    .filter(|pane| pane.entity_id() != entity_id)
 1986                                    .for_each(|p| {
 1987                                        p.update(cx, |pane, _| {
 1988                                            pane.nav_history_mut().rename_item(
 1989                                                entity_id,
 1990                                                project_path.clone(),
 1991                                                abs_path.clone().into(),
 1992                                            );
 1993                                        })
 1994                                    });
 1995                            });
 1996                            let edited_buffers_already_open = {
 1997                                let other_editors: Vec<Entity<Editor>> = workspace
 1998                                    .read(cx)
 1999                                    .panes()
 2000                                    .iter()
 2001                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2002                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2003                                    .collect();
 2004
 2005                                transaction.0.keys().all(|buffer| {
 2006                                    other_editors.iter().any(|editor| {
 2007                                        let multi_buffer = editor.read(cx).buffer();
 2008                                        multi_buffer.read(cx).is_singleton()
 2009                                            && multi_buffer.read(cx).as_singleton().map_or(
 2010                                                false,
 2011                                                |singleton| {
 2012                                                    singleton.entity_id() == buffer.entity_id()
 2013                                                },
 2014                                            )
 2015                                    })
 2016                                })
 2017                            };
 2018                            if !edited_buffers_already_open {
 2019                                let workspace = workspace.downgrade();
 2020                                let transaction = transaction.clone();
 2021                                cx.defer_in(window, move |_, window, cx| {
 2022                                    cx.spawn_in(window, async move |editor, cx| {
 2023                                        Self::open_project_transaction(
 2024                                            &editor,
 2025                                            workspace,
 2026                                            transaction,
 2027                                            "Rename".to_string(),
 2028                                            cx,
 2029                                        )
 2030                                        .await
 2031                                        .ok()
 2032                                    })
 2033                                    .detach();
 2034                                });
 2035                            }
 2036                        }
 2037                    }
 2038
 2039                    _ => {}
 2040                },
 2041            ));
 2042            if let Some(task_inventory) = project
 2043                .read(cx)
 2044                .task_store()
 2045                .read(cx)
 2046                .task_inventory()
 2047                .cloned()
 2048            {
 2049                project_subscriptions.push(cx.observe_in(
 2050                    &task_inventory,
 2051                    window,
 2052                    |editor, _, window, cx| {
 2053                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2054                    },
 2055                ));
 2056            };
 2057
 2058            project_subscriptions.push(cx.subscribe_in(
 2059                &project.read(cx).breakpoint_store(),
 2060                window,
 2061                |editor, _, event, window, cx| match event {
 2062                    BreakpointStoreEvent::ClearDebugLines => {
 2063                        editor.clear_row_highlights::<ActiveDebugLine>();
 2064                        editor.refresh_inline_values(cx);
 2065                    }
 2066                    BreakpointStoreEvent::SetDebugLine => {
 2067                        if editor.go_to_active_debug_line(window, cx) {
 2068                            cx.stop_propagation();
 2069                        }
 2070
 2071                        editor.refresh_inline_values(cx);
 2072                    }
 2073                    _ => {}
 2074                },
 2075            ));
 2076            let git_store = project.read(cx).git_store().clone();
 2077            let project = project.clone();
 2078            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2079                if let GitStoreEvent::RepositoryAdded = event {
 2080                    this.load_diff_task = Some(
 2081                        update_uncommitted_diff_for_buffer(
 2082                            cx.entity(),
 2083                            &project,
 2084                            this.buffer.read(cx).all_buffers(),
 2085                            this.buffer.clone(),
 2086                            cx,
 2087                        )
 2088                        .shared(),
 2089                    );
 2090                }
 2091            }));
 2092        }
 2093
 2094        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2095
 2096        let inlay_hint_settings =
 2097            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2098        let focus_handle = cx.focus_handle();
 2099        if !is_minimap {
 2100            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2101                .detach();
 2102            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2103                .detach();
 2104            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2105                .detach();
 2106            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2107                .detach();
 2108            cx.observe_pending_input(window, Self::observe_pending_input)
 2109                .detach();
 2110        }
 2111
 2112        let show_indent_guides =
 2113            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2114                Some(false)
 2115            } else {
 2116                None
 2117            };
 2118
 2119        let breakpoint_store = match (&mode, project.as_ref()) {
 2120            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2121            _ => None,
 2122        };
 2123
 2124        let mut code_action_providers = Vec::new();
 2125        let mut load_uncommitted_diff = None;
 2126        if let Some(project) = project.clone() {
 2127            load_uncommitted_diff = Some(
 2128                update_uncommitted_diff_for_buffer(
 2129                    cx.entity(),
 2130                    &project,
 2131                    multi_buffer.read(cx).all_buffers(),
 2132                    multi_buffer.clone(),
 2133                    cx,
 2134                )
 2135                .shared(),
 2136            );
 2137            code_action_providers.push(Rc::new(project) as Rc<_>);
 2138        }
 2139
 2140        let mut editor = Self {
 2141            focus_handle,
 2142            show_cursor_when_unfocused: false,
 2143            last_focused_descendant: None,
 2144            buffer: multi_buffer.clone(),
 2145            display_map: display_map.clone(),
 2146            placeholder_display_map: None,
 2147            selections,
 2148            scroll_manager: ScrollManager::new(cx),
 2149            columnar_selection_state: None,
 2150            add_selections_state: None,
 2151            select_next_state: None,
 2152            select_prev_state: None,
 2153            selection_history: SelectionHistory::default(),
 2154            defer_selection_effects: false,
 2155            deferred_selection_effects_state: None,
 2156            autoclose_regions: Vec::new(),
 2157            snippet_stack: InvalidationStack::default(),
 2158            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2159            ime_transaction: None,
 2160            active_diagnostics: ActiveDiagnostic::None,
 2161            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2162            inline_diagnostics_update: Task::ready(()),
 2163            inline_diagnostics: Vec::new(),
 2164            soft_wrap_mode_override,
 2165            diagnostics_max_severity,
 2166            hard_wrap: None,
 2167            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2168            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2169            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2170            project,
 2171            blink_manager: blink_manager.clone(),
 2172            show_local_selections: true,
 2173            show_scrollbars: ScrollbarAxes {
 2174                horizontal: full_mode,
 2175                vertical: full_mode,
 2176            },
 2177            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2178            offset_content: !matches!(mode, EditorMode::SingleLine),
 2179            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2180            show_gutter: full_mode,
 2181            show_line_numbers: (!full_mode).then_some(false),
 2182            use_relative_line_numbers: None,
 2183            disable_expand_excerpt_buttons: !full_mode,
 2184            show_git_diff_gutter: None,
 2185            show_code_actions: None,
 2186            show_runnables: None,
 2187            show_breakpoints: None,
 2188            show_wrap_guides: None,
 2189            show_indent_guides,
 2190            highlight_order: 0,
 2191            highlighted_rows: HashMap::default(),
 2192            background_highlights: HashMap::default(),
 2193            gutter_highlights: HashMap::default(),
 2194            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2195            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2196            nav_history: None,
 2197            context_menu: RefCell::new(None),
 2198            context_menu_options: None,
 2199            mouse_context_menu: None,
 2200            completion_tasks: Vec::new(),
 2201            inline_blame_popover: None,
 2202            inline_blame_popover_show_task: None,
 2203            signature_help_state: SignatureHelpState::default(),
 2204            auto_signature_help: None,
 2205            find_all_references_task_sources: Vec::new(),
 2206            next_completion_id: 0,
 2207            next_inlay_id: 0,
 2208            code_action_providers,
 2209            available_code_actions: None,
 2210            code_actions_task: None,
 2211            quick_selection_highlight_task: None,
 2212            debounced_selection_highlight_task: None,
 2213            document_highlights_task: None,
 2214            linked_editing_range_task: None,
 2215            pending_rename: None,
 2216            searchable: !is_minimap,
 2217            cursor_shape: EditorSettings::get_global(cx)
 2218                .cursor_shape
 2219                .unwrap_or_default(),
 2220            current_line_highlight: None,
 2221            autoindent_mode: Some(AutoindentMode::EachLine),
 2222            collapse_matches: false,
 2223            workspace: None,
 2224            input_enabled: !is_minimap,
 2225            use_modal_editing: full_mode,
 2226            read_only: is_minimap,
 2227            use_autoclose: true,
 2228            use_auto_surround: true,
 2229            auto_replace_emoji_shortcode: false,
 2230            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2231            leader_id: None,
 2232            remote_id: None,
 2233            hover_state: HoverState::default(),
 2234            pending_mouse_down: None,
 2235            hovered_link_state: None,
 2236            edit_prediction_provider: None,
 2237            active_edit_prediction: None,
 2238            stale_edit_prediction_in_menu: None,
 2239            edit_prediction_preview: EditPredictionPreview::Inactive {
 2240                released_too_fast: false,
 2241            },
 2242            inline_diagnostics_enabled: full_mode,
 2243            diagnostics_enabled: full_mode,
 2244            word_completions_enabled: full_mode,
 2245            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2246            gutter_hovered: false,
 2247            pixel_position_of_newest_cursor: None,
 2248            last_bounds: None,
 2249            last_position_map: None,
 2250            expect_bounds_change: None,
 2251            gutter_dimensions: GutterDimensions::default(),
 2252            style: None,
 2253            show_cursor_names: false,
 2254            hovered_cursors: HashMap::default(),
 2255            next_editor_action_id: EditorActionId::default(),
 2256            editor_actions: Rc::default(),
 2257            edit_predictions_hidden_for_vim_mode: false,
 2258            show_edit_predictions_override: None,
 2259            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2260            edit_prediction_settings: EditPredictionSettings::Disabled,
 2261            edit_prediction_indent_conflict: false,
 2262            edit_prediction_requires_modifier_in_indent_conflict: true,
 2263            custom_context_menu: None,
 2264            show_git_blame_gutter: false,
 2265            show_git_blame_inline: false,
 2266            show_selection_menu: None,
 2267            show_git_blame_inline_delay_task: None,
 2268            git_blame_inline_enabled: full_mode
 2269                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2270            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2271            buffer_serialization: is_minimap.not().then(|| {
 2272                BufferSerialization::new(
 2273                    ProjectSettings::get_global(cx)
 2274                        .session
 2275                        .restore_unsaved_buffers,
 2276                )
 2277            }),
 2278            blame: None,
 2279            blame_subscription: None,
 2280            tasks: BTreeMap::default(),
 2281
 2282            breakpoint_store,
 2283            gutter_breakpoint_indicator: (None, None),
 2284            hovered_diff_hunk_row: None,
 2285            _subscriptions: (!is_minimap)
 2286                .then(|| {
 2287                    vec![
 2288                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2289                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2290                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2291                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2292                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2293                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2294                        cx.observe_window_activation(window, |editor, window, cx| {
 2295                            let active = window.is_window_active();
 2296                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2297                                if active {
 2298                                    blink_manager.enable(cx);
 2299                                } else {
 2300                                    blink_manager.disable(cx);
 2301                                }
 2302                            });
 2303                            if active {
 2304                                editor.show_mouse_cursor(cx);
 2305                            }
 2306                        }),
 2307                    ]
 2308                })
 2309                .unwrap_or_default(),
 2310            tasks_update_task: None,
 2311            pull_diagnostics_task: Task::ready(()),
 2312            colors: None,
 2313            refresh_colors_task: Task::ready(()),
 2314            inlay_hints: None,
 2315            next_color_inlay_id: 0,
 2316            post_scroll_update: Task::ready(()),
 2317            linked_edit_ranges: Default::default(),
 2318            in_project_search: false,
 2319            previous_search_ranges: None,
 2320            breadcrumb_header: None,
 2321            focused_block: None,
 2322            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2323            addons: HashMap::default(),
 2324            registered_buffers: HashMap::default(),
 2325            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2326            selection_mark_mode: false,
 2327            toggle_fold_multiple_buffers: Task::ready(()),
 2328            serialize_selections: Task::ready(()),
 2329            serialize_folds: Task::ready(()),
 2330            text_style_refinement: None,
 2331            load_diff_task: load_uncommitted_diff,
 2332            temporary_diff_override: false,
 2333            mouse_cursor_hidden: false,
 2334            minimap: None,
 2335            hide_mouse_mode: EditorSettings::get_global(cx)
 2336                .hide_mouse
 2337                .unwrap_or_default(),
 2338            change_list: ChangeList::new(),
 2339            mode,
 2340            selection_drag_state: SelectionDragState::None,
 2341            folding_newlines: Task::ready(()),
 2342            lookup_key: None,
 2343            select_next_is_case_sensitive: None,
 2344            applicable_language_settings: HashMap::default(),
 2345            accent_overrides: Vec::new(),
 2346            fetched_tree_sitter_chunks: HashMap::default(),
 2347        };
 2348
 2349        if is_minimap {
 2350            return editor;
 2351        }
 2352
 2353        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2354        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2355
 2356        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2357            editor
 2358                ._subscriptions
 2359                .push(cx.observe(breakpoints, |_, _, cx| {
 2360                    cx.notify();
 2361                }));
 2362        }
 2363        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2364        editor._subscriptions.extend(project_subscriptions);
 2365
 2366        editor._subscriptions.push(cx.subscribe_in(
 2367            &cx.entity(),
 2368            window,
 2369            |editor, _, e: &EditorEvent, window, cx| match e {
 2370                EditorEvent::ScrollPositionChanged { local, .. } => {
 2371                    if *local {
 2372                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2373                        editor.inline_blame_popover.take();
 2374                        let new_anchor = editor.scroll_manager.anchor();
 2375                        let snapshot = editor.snapshot(window, cx);
 2376                        editor.update_restoration_data(cx, move |data| {
 2377                            data.scroll_position = (
 2378                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2379                                new_anchor.offset,
 2380                            );
 2381                        });
 2382
 2383                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2384                            cx.background_executor()
 2385                                .timer(Duration::from_millis(50))
 2386                                .await;
 2387                            editor
 2388                                .update_in(cx, |editor, window, cx| {
 2389                                    editor.register_visible_buffers(cx);
 2390                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2391                                    editor.refresh_inlay_hints(
 2392                                        InlayHintRefreshReason::NewLinesShown,
 2393                                        cx,
 2394                                    );
 2395                                    editor.colorize_brackets(false, cx);
 2396                                })
 2397                                .ok();
 2398                        });
 2399                    }
 2400                }
 2401                EditorEvent::Edited { .. } => {
 2402                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2403                        .map(|vim_mode| vim_mode.0)
 2404                        .unwrap_or(false);
 2405                    if !vim_mode {
 2406                        let display_map = editor.display_snapshot(cx);
 2407                        let selections = editor.selections.all_adjusted_display(&display_map);
 2408                        let pop_state = editor
 2409                            .change_list
 2410                            .last()
 2411                            .map(|previous| {
 2412                                previous.len() == selections.len()
 2413                                    && previous.iter().enumerate().all(|(ix, p)| {
 2414                                        p.to_display_point(&display_map).row()
 2415                                            == selections[ix].head().row()
 2416                                    })
 2417                            })
 2418                            .unwrap_or(false);
 2419                        let new_positions = selections
 2420                            .into_iter()
 2421                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2422                            .collect();
 2423                        editor
 2424                            .change_list
 2425                            .push_to_change_list(pop_state, new_positions);
 2426                    }
 2427                }
 2428                _ => (),
 2429            },
 2430        ));
 2431
 2432        if let Some(dap_store) = editor
 2433            .project
 2434            .as_ref()
 2435            .map(|project| project.read(cx).dap_store())
 2436        {
 2437            let weak_editor = cx.weak_entity();
 2438
 2439            editor
 2440                ._subscriptions
 2441                .push(
 2442                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2443                        let session_entity = cx.entity();
 2444                        weak_editor
 2445                            .update(cx, |editor, cx| {
 2446                                editor._subscriptions.push(
 2447                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2448                                );
 2449                            })
 2450                            .ok();
 2451                    }),
 2452                );
 2453
 2454            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2455                editor
 2456                    ._subscriptions
 2457                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2458            }
 2459        }
 2460
 2461        // skip adding the initial selection to selection history
 2462        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2463        editor.end_selection(window, cx);
 2464        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2465
 2466        editor.scroll_manager.show_scrollbars(window, cx);
 2467        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2468
 2469        if full_mode {
 2470            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2471            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2472
 2473            if editor.git_blame_inline_enabled {
 2474                editor.start_git_blame_inline(false, window, cx);
 2475            }
 2476
 2477            editor.go_to_active_debug_line(window, cx);
 2478
 2479            editor.minimap =
 2480                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2481            editor.colors = Some(LspColorData::new(cx));
 2482            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2483
 2484            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2485                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2486            }
 2487            editor.update_lsp_data(None, window, cx);
 2488            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2489        }
 2490
 2491        editor
 2492    }
 2493
 2494    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2495        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2496    }
 2497
 2498    pub fn deploy_mouse_context_menu(
 2499        &mut self,
 2500        position: gpui::Point<Pixels>,
 2501        context_menu: Entity<ContextMenu>,
 2502        window: &mut Window,
 2503        cx: &mut Context<Self>,
 2504    ) {
 2505        self.mouse_context_menu = Some(MouseContextMenu::new(
 2506            self,
 2507            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2508            context_menu,
 2509            window,
 2510            cx,
 2511        ));
 2512    }
 2513
 2514    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2515        self.mouse_context_menu
 2516            .as_ref()
 2517            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2518    }
 2519
 2520    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2521        if self
 2522            .selections
 2523            .pending_anchor()
 2524            .is_some_and(|pending_selection| {
 2525                let snapshot = self.buffer().read(cx).snapshot(cx);
 2526                pending_selection.range().includes(range, &snapshot)
 2527            })
 2528        {
 2529            return true;
 2530        }
 2531
 2532        self.selections
 2533            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2534            .into_iter()
 2535            .any(|selection| {
 2536                // This is needed to cover a corner case, if we just check for an existing
 2537                // selection in the fold range, having a cursor at the start of the fold
 2538                // marks it as selected. Non-empty selections don't cause this.
 2539                let length = selection.end - selection.start;
 2540                length > 0
 2541            })
 2542    }
 2543
 2544    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2545        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2546    }
 2547
 2548    fn key_context_internal(
 2549        &self,
 2550        has_active_edit_prediction: bool,
 2551        window: &mut Window,
 2552        cx: &mut App,
 2553    ) -> KeyContext {
 2554        let mut key_context = KeyContext::new_with_defaults();
 2555        key_context.add("Editor");
 2556        let mode = match self.mode {
 2557            EditorMode::SingleLine => "single_line",
 2558            EditorMode::AutoHeight { .. } => "auto_height",
 2559            EditorMode::Minimap { .. } => "minimap",
 2560            EditorMode::Full { .. } => "full",
 2561        };
 2562
 2563        if EditorSettings::jupyter_enabled(cx) {
 2564            key_context.add("jupyter");
 2565        }
 2566
 2567        key_context.set("mode", mode);
 2568        if self.pending_rename.is_some() {
 2569            key_context.add("renaming");
 2570        }
 2571
 2572        if let Some(snippet_stack) = self.snippet_stack.last() {
 2573            key_context.add("in_snippet");
 2574
 2575            if snippet_stack.active_index > 0 {
 2576                key_context.add("has_previous_tabstop");
 2577            }
 2578
 2579            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2580                key_context.add("has_next_tabstop");
 2581            }
 2582        }
 2583
 2584        match self.context_menu.borrow().as_ref() {
 2585            Some(CodeContextMenu::Completions(menu)) => {
 2586                if menu.visible() {
 2587                    key_context.add("menu");
 2588                    key_context.add("showing_completions");
 2589                }
 2590            }
 2591            Some(CodeContextMenu::CodeActions(menu)) => {
 2592                if menu.visible() {
 2593                    key_context.add("menu");
 2594                    key_context.add("showing_code_actions")
 2595                }
 2596            }
 2597            None => {}
 2598        }
 2599
 2600        if self.signature_help_state.has_multiple_signatures() {
 2601            key_context.add("showing_signature_help");
 2602        }
 2603
 2604        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2605        if !self.focus_handle(cx).contains_focused(window, cx)
 2606            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2607        {
 2608            for addon in self.addons.values() {
 2609                addon.extend_key_context(&mut key_context, cx)
 2610            }
 2611        }
 2612
 2613        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2614            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2615                Some(
 2616                    file.full_path(cx)
 2617                        .extension()?
 2618                        .to_string_lossy()
 2619                        .into_owned(),
 2620                )
 2621            }) {
 2622                key_context.set("extension", extension);
 2623            }
 2624        } else {
 2625            key_context.add("multibuffer");
 2626        }
 2627
 2628        if has_active_edit_prediction {
 2629            if self.edit_prediction_in_conflict() {
 2630                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2631            } else {
 2632                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2633                key_context.add("copilot_suggestion");
 2634            }
 2635        }
 2636
 2637        if self.selection_mark_mode {
 2638            key_context.add("selection_mode");
 2639        }
 2640
 2641        let disjoint = self.selections.disjoint_anchors();
 2642        let snapshot = self.snapshot(window, cx);
 2643        let snapshot = snapshot.buffer_snapshot();
 2644        if self.mode == EditorMode::SingleLine
 2645            && let [selection] = disjoint
 2646            && selection.start == selection.end
 2647            && selection.end.to_offset(snapshot) == snapshot.len()
 2648        {
 2649            key_context.add("end_of_input");
 2650        }
 2651
 2652        if self.has_any_expanded_diff_hunks(cx) {
 2653            key_context.add("diffs_expanded");
 2654        }
 2655
 2656        key_context
 2657    }
 2658
 2659    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2660        self.last_bounds.as_ref()
 2661    }
 2662
 2663    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2664        if self.mouse_cursor_hidden {
 2665            self.mouse_cursor_hidden = false;
 2666            cx.notify();
 2667        }
 2668    }
 2669
 2670    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2671        let hide_mouse_cursor = match origin {
 2672            HideMouseCursorOrigin::TypingAction => {
 2673                matches!(
 2674                    self.hide_mouse_mode,
 2675                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2676                )
 2677            }
 2678            HideMouseCursorOrigin::MovementAction => {
 2679                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2680            }
 2681        };
 2682        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2683            self.mouse_cursor_hidden = hide_mouse_cursor;
 2684            cx.notify();
 2685        }
 2686    }
 2687
 2688    pub fn edit_prediction_in_conflict(&self) -> bool {
 2689        if !self.show_edit_predictions_in_menu() {
 2690            return false;
 2691        }
 2692
 2693        let showing_completions = self
 2694            .context_menu
 2695            .borrow()
 2696            .as_ref()
 2697            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2698
 2699        showing_completions
 2700            || self.edit_prediction_requires_modifier()
 2701            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2702            // bindings to insert tab characters.
 2703            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2704    }
 2705
 2706    pub fn accept_edit_prediction_keybind(
 2707        &self,
 2708        accept_partial: bool,
 2709        window: &mut Window,
 2710        cx: &mut App,
 2711    ) -> AcceptEditPredictionBinding {
 2712        let key_context = self.key_context_internal(true, window, cx);
 2713        let in_conflict = self.edit_prediction_in_conflict();
 2714
 2715        let bindings = if accept_partial {
 2716            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2717        } else {
 2718            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2719        };
 2720
 2721        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2722        // just the first one.
 2723        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2724            !in_conflict
 2725                || binding
 2726                    .keystrokes()
 2727                    .first()
 2728                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2729        }))
 2730    }
 2731
 2732    pub fn new_file(
 2733        workspace: &mut Workspace,
 2734        _: &workspace::NewFile,
 2735        window: &mut Window,
 2736        cx: &mut Context<Workspace>,
 2737    ) {
 2738        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2739            "Failed to create buffer",
 2740            window,
 2741            cx,
 2742            |e, _, _| match e.error_code() {
 2743                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2744                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2745                e.error_tag("required").unwrap_or("the latest version")
 2746            )),
 2747                _ => None,
 2748            },
 2749        );
 2750    }
 2751
 2752    pub fn new_in_workspace(
 2753        workspace: &mut Workspace,
 2754        window: &mut Window,
 2755        cx: &mut Context<Workspace>,
 2756    ) -> Task<Result<Entity<Editor>>> {
 2757        let project = workspace.project().clone();
 2758        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2759
 2760        cx.spawn_in(window, async move |workspace, cx| {
 2761            let buffer = create.await?;
 2762            workspace.update_in(cx, |workspace, window, cx| {
 2763                let editor =
 2764                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2765                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2766                editor
 2767            })
 2768        })
 2769    }
 2770
 2771    fn new_file_vertical(
 2772        workspace: &mut Workspace,
 2773        _: &workspace::NewFileSplitVertical,
 2774        window: &mut Window,
 2775        cx: &mut Context<Workspace>,
 2776    ) {
 2777        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2778    }
 2779
 2780    fn new_file_horizontal(
 2781        workspace: &mut Workspace,
 2782        _: &workspace::NewFileSplitHorizontal,
 2783        window: &mut Window,
 2784        cx: &mut Context<Workspace>,
 2785    ) {
 2786        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2787    }
 2788
 2789    fn new_file_split(
 2790        workspace: &mut Workspace,
 2791        action: &workspace::NewFileSplit,
 2792        window: &mut Window,
 2793        cx: &mut Context<Workspace>,
 2794    ) {
 2795        Self::new_file_in_direction(workspace, action.0, window, cx)
 2796    }
 2797
 2798    fn new_file_in_direction(
 2799        workspace: &mut Workspace,
 2800        direction: SplitDirection,
 2801        window: &mut Window,
 2802        cx: &mut Context<Workspace>,
 2803    ) {
 2804        let project = workspace.project().clone();
 2805        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2806
 2807        cx.spawn_in(window, async move |workspace, cx| {
 2808            let buffer = create.await?;
 2809            workspace.update_in(cx, move |workspace, window, cx| {
 2810                workspace.split_item(
 2811                    direction,
 2812                    Box::new(
 2813                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2814                    ),
 2815                    window,
 2816                    cx,
 2817                )
 2818            })?;
 2819            anyhow::Ok(())
 2820        })
 2821        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2822            match e.error_code() {
 2823                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2824                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2825                e.error_tag("required").unwrap_or("the latest version")
 2826            )),
 2827                _ => None,
 2828            }
 2829        });
 2830    }
 2831
 2832    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2833        self.leader_id
 2834    }
 2835
 2836    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2837        &self.buffer
 2838    }
 2839
 2840    pub fn project(&self) -> Option<&Entity<Project>> {
 2841        self.project.as_ref()
 2842    }
 2843
 2844    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2845        self.workspace.as_ref()?.0.upgrade()
 2846    }
 2847
 2848    /// Returns the workspace serialization ID if this editor should be serialized.
 2849    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2850        self.workspace
 2851            .as_ref()
 2852            .filter(|_| self.should_serialize_buffer())
 2853            .and_then(|workspace| workspace.1)
 2854    }
 2855
 2856    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2857        self.buffer().read(cx).title(cx)
 2858    }
 2859
 2860    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2861        let git_blame_gutter_max_author_length = self
 2862            .render_git_blame_gutter(cx)
 2863            .then(|| {
 2864                if let Some(blame) = self.blame.as_ref() {
 2865                    let max_author_length =
 2866                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2867                    Some(max_author_length)
 2868                } else {
 2869                    None
 2870                }
 2871            })
 2872            .flatten();
 2873
 2874        EditorSnapshot {
 2875            mode: self.mode.clone(),
 2876            show_gutter: self.show_gutter,
 2877            show_line_numbers: self.show_line_numbers,
 2878            show_git_diff_gutter: self.show_git_diff_gutter,
 2879            show_code_actions: self.show_code_actions,
 2880            show_runnables: self.show_runnables,
 2881            show_breakpoints: self.show_breakpoints,
 2882            git_blame_gutter_max_author_length,
 2883            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2884            placeholder_display_snapshot: self
 2885                .placeholder_display_map
 2886                .as_ref()
 2887                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2888            scroll_anchor: self.scroll_manager.anchor(),
 2889            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2890            is_focused: self.focus_handle.is_focused(window),
 2891            current_line_highlight: self
 2892                .current_line_highlight
 2893                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2894            gutter_hovered: self.gutter_hovered,
 2895        }
 2896    }
 2897
 2898    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2899        self.buffer.read(cx).language_at(point, cx)
 2900    }
 2901
 2902    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2903        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2904    }
 2905
 2906    pub fn active_excerpt(
 2907        &self,
 2908        cx: &App,
 2909    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2910        self.buffer
 2911            .read(cx)
 2912            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2913    }
 2914
 2915    pub fn mode(&self) -> &EditorMode {
 2916        &self.mode
 2917    }
 2918
 2919    pub fn set_mode(&mut self, mode: EditorMode) {
 2920        self.mode = mode;
 2921    }
 2922
 2923    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2924        self.collaboration_hub.as_deref()
 2925    }
 2926
 2927    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2928        self.collaboration_hub = Some(hub);
 2929    }
 2930
 2931    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2932        self.in_project_search = in_project_search;
 2933    }
 2934
 2935    pub fn set_custom_context_menu(
 2936        &mut self,
 2937        f: impl 'static
 2938        + Fn(
 2939            &mut Self,
 2940            DisplayPoint,
 2941            &mut Window,
 2942            &mut Context<Self>,
 2943        ) -> Option<Entity<ui::ContextMenu>>,
 2944    ) {
 2945        self.custom_context_menu = Some(Box::new(f))
 2946    }
 2947
 2948    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2949        self.completion_provider = provider;
 2950    }
 2951
 2952    #[cfg(any(test, feature = "test-support"))]
 2953    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2954        self.completion_provider.clone()
 2955    }
 2956
 2957    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2958        self.semantics_provider.clone()
 2959    }
 2960
 2961    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2962        self.semantics_provider = provider;
 2963    }
 2964
 2965    pub fn set_edit_prediction_provider<T>(
 2966        &mut self,
 2967        provider: Option<Entity<T>>,
 2968        window: &mut Window,
 2969        cx: &mut Context<Self>,
 2970    ) where
 2971        T: EditPredictionProvider,
 2972    {
 2973        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2974            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2975                if this.focus_handle.is_focused(window) {
 2976                    this.update_visible_edit_prediction(window, cx);
 2977                }
 2978            }),
 2979            provider: Arc::new(provider),
 2980        });
 2981        self.update_edit_prediction_settings(cx);
 2982        self.refresh_edit_prediction(false, false, window, cx);
 2983    }
 2984
 2985    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2986        self.placeholder_display_map
 2987            .as_ref()
 2988            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2989    }
 2990
 2991    pub fn set_placeholder_text(
 2992        &mut self,
 2993        placeholder_text: &str,
 2994        window: &mut Window,
 2995        cx: &mut Context<Self>,
 2996    ) {
 2997        let multibuffer = cx
 2998            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2999
 3000        let style = window.text_style();
 3001
 3002        self.placeholder_display_map = Some(cx.new(|cx| {
 3003            DisplayMap::new(
 3004                multibuffer,
 3005                style.font(),
 3006                style.font_size.to_pixels(window.rem_size()),
 3007                None,
 3008                FILE_HEADER_HEIGHT,
 3009                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3010                Default::default(),
 3011                DiagnosticSeverity::Off,
 3012                cx,
 3013            )
 3014        }));
 3015        cx.notify();
 3016    }
 3017
 3018    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3019        self.cursor_shape = cursor_shape;
 3020
 3021        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3022        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3023
 3024        cx.notify();
 3025    }
 3026
 3027    pub fn cursor_shape(&self) -> CursorShape {
 3028        self.cursor_shape
 3029    }
 3030
 3031    pub fn set_current_line_highlight(
 3032        &mut self,
 3033        current_line_highlight: Option<CurrentLineHighlight>,
 3034    ) {
 3035        self.current_line_highlight = current_line_highlight;
 3036    }
 3037
 3038    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3039        self.collapse_matches = collapse_matches;
 3040    }
 3041
 3042    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3043        if self.collapse_matches {
 3044            return range.start..range.start;
 3045        }
 3046        range.clone()
 3047    }
 3048
 3049    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3050        self.display_map.read(cx).clip_at_line_ends
 3051    }
 3052
 3053    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3054        if self.display_map.read(cx).clip_at_line_ends != clip {
 3055            self.display_map
 3056                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3057        }
 3058    }
 3059
 3060    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3061        self.input_enabled = input_enabled;
 3062    }
 3063
 3064    pub fn set_edit_predictions_hidden_for_vim_mode(
 3065        &mut self,
 3066        hidden: bool,
 3067        window: &mut Window,
 3068        cx: &mut Context<Self>,
 3069    ) {
 3070        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3071            self.edit_predictions_hidden_for_vim_mode = hidden;
 3072            if hidden {
 3073                self.update_visible_edit_prediction(window, cx);
 3074            } else {
 3075                self.refresh_edit_prediction(true, false, window, cx);
 3076            }
 3077        }
 3078    }
 3079
 3080    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3081        self.menu_edit_predictions_policy = value;
 3082    }
 3083
 3084    pub fn set_autoindent(&mut self, autoindent: bool) {
 3085        if autoindent {
 3086            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3087        } else {
 3088            self.autoindent_mode = None;
 3089        }
 3090    }
 3091
 3092    pub fn read_only(&self, cx: &App) -> bool {
 3093        self.read_only || self.buffer.read(cx).read_only()
 3094    }
 3095
 3096    pub fn set_read_only(&mut self, read_only: bool) {
 3097        self.read_only = read_only;
 3098    }
 3099
 3100    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3101        self.use_autoclose = autoclose;
 3102    }
 3103
 3104    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3105        self.use_auto_surround = auto_surround;
 3106    }
 3107
 3108    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3109        self.auto_replace_emoji_shortcode = auto_replace;
 3110    }
 3111
 3112    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3113        self.buffer_serialization = should_serialize.then(|| {
 3114            BufferSerialization::new(
 3115                ProjectSettings::get_global(cx)
 3116                    .session
 3117                    .restore_unsaved_buffers,
 3118            )
 3119        })
 3120    }
 3121
 3122    fn should_serialize_buffer(&self) -> bool {
 3123        self.buffer_serialization.is_some()
 3124    }
 3125
 3126    pub fn toggle_edit_predictions(
 3127        &mut self,
 3128        _: &ToggleEditPrediction,
 3129        window: &mut Window,
 3130        cx: &mut Context<Self>,
 3131    ) {
 3132        if self.show_edit_predictions_override.is_some() {
 3133            self.set_show_edit_predictions(None, window, cx);
 3134        } else {
 3135            let show_edit_predictions = !self.edit_predictions_enabled();
 3136            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3137        }
 3138    }
 3139
 3140    pub fn set_show_edit_predictions(
 3141        &mut self,
 3142        show_edit_predictions: Option<bool>,
 3143        window: &mut Window,
 3144        cx: &mut Context<Self>,
 3145    ) {
 3146        self.show_edit_predictions_override = show_edit_predictions;
 3147        self.update_edit_prediction_settings(cx);
 3148
 3149        if let Some(false) = show_edit_predictions {
 3150            self.discard_edit_prediction(false, cx);
 3151        } else {
 3152            self.refresh_edit_prediction(false, true, window, cx);
 3153        }
 3154    }
 3155
 3156    fn edit_predictions_disabled_in_scope(
 3157        &self,
 3158        buffer: &Entity<Buffer>,
 3159        buffer_position: language::Anchor,
 3160        cx: &App,
 3161    ) -> bool {
 3162        let snapshot = buffer.read(cx).snapshot();
 3163        let settings = snapshot.settings_at(buffer_position, cx);
 3164
 3165        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3166            return false;
 3167        };
 3168
 3169        scope.override_name().is_some_and(|scope_name| {
 3170            settings
 3171                .edit_predictions_disabled_in
 3172                .iter()
 3173                .any(|s| s == scope_name)
 3174        })
 3175    }
 3176
 3177    pub fn set_use_modal_editing(&mut self, to: bool) {
 3178        self.use_modal_editing = to;
 3179    }
 3180
 3181    pub fn use_modal_editing(&self) -> bool {
 3182        self.use_modal_editing
 3183    }
 3184
 3185    fn selections_did_change(
 3186        &mut self,
 3187        local: bool,
 3188        old_cursor_position: &Anchor,
 3189        effects: SelectionEffects,
 3190        window: &mut Window,
 3191        cx: &mut Context<Self>,
 3192    ) {
 3193        window.invalidate_character_coordinates();
 3194
 3195        // Copy selections to primary selection buffer
 3196        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3197        if local {
 3198            let selections = self
 3199                .selections
 3200                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3201            let buffer_handle = self.buffer.read(cx).read(cx);
 3202
 3203            let mut text = String::new();
 3204            for (index, selection) in selections.iter().enumerate() {
 3205                let text_for_selection = buffer_handle
 3206                    .text_for_range(selection.start..selection.end)
 3207                    .collect::<String>();
 3208
 3209                text.push_str(&text_for_selection);
 3210                if index != selections.len() - 1 {
 3211                    text.push('\n');
 3212                }
 3213            }
 3214
 3215            if !text.is_empty() {
 3216                cx.write_to_primary(ClipboardItem::new_string(text));
 3217            }
 3218        }
 3219
 3220        let selection_anchors = self.selections.disjoint_anchors_arc();
 3221
 3222        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3223            self.buffer.update(cx, |buffer, cx| {
 3224                buffer.set_active_selections(
 3225                    &selection_anchors,
 3226                    self.selections.line_mode(),
 3227                    self.cursor_shape,
 3228                    cx,
 3229                )
 3230            });
 3231        }
 3232        let display_map = self
 3233            .display_map
 3234            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3235        let buffer = display_map.buffer_snapshot();
 3236        if self.selections.count() == 1 {
 3237            self.add_selections_state = None;
 3238        }
 3239        self.select_next_state = None;
 3240        self.select_prev_state = None;
 3241        self.select_syntax_node_history.try_clear();
 3242        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3243        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3244        self.take_rename(false, window, cx);
 3245
 3246        let newest_selection = self.selections.newest_anchor();
 3247        let new_cursor_position = newest_selection.head();
 3248        let selection_start = newest_selection.start;
 3249
 3250        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3251            self.push_to_nav_history(
 3252                *old_cursor_position,
 3253                Some(new_cursor_position.to_point(buffer)),
 3254                false,
 3255                effects.nav_history == Some(true),
 3256                cx,
 3257            );
 3258        }
 3259
 3260        if local {
 3261            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3262                self.register_buffer(buffer_id, cx);
 3263            }
 3264
 3265            let mut context_menu = self.context_menu.borrow_mut();
 3266            let completion_menu = match context_menu.as_ref() {
 3267                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3268                Some(CodeContextMenu::CodeActions(_)) => {
 3269                    *context_menu = None;
 3270                    None
 3271                }
 3272                None => None,
 3273            };
 3274            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3275            drop(context_menu);
 3276
 3277            if effects.completions
 3278                && let Some(completion_position) = completion_position
 3279            {
 3280                let start_offset = selection_start.to_offset(buffer);
 3281                let position_matches = start_offset == completion_position.to_offset(buffer);
 3282                let continue_showing = if position_matches {
 3283                    if self.snippet_stack.is_empty() {
 3284                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3285                            == Some(CharKind::Word)
 3286                    } else {
 3287                        // Snippet choices can be shown even when the cursor is in whitespace.
 3288                        // Dismissing the menu with actions like backspace is handled by
 3289                        // invalidation regions.
 3290                        true
 3291                    }
 3292                } else {
 3293                    false
 3294                };
 3295
 3296                if continue_showing {
 3297                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3298                } else {
 3299                    self.hide_context_menu(window, cx);
 3300                }
 3301            }
 3302
 3303            hide_hover(self, cx);
 3304
 3305            if old_cursor_position.to_display_point(&display_map).row()
 3306                != new_cursor_position.to_display_point(&display_map).row()
 3307            {
 3308                self.available_code_actions.take();
 3309            }
 3310            self.refresh_code_actions(window, cx);
 3311            self.refresh_document_highlights(cx);
 3312            refresh_linked_ranges(self, window, cx);
 3313
 3314            self.refresh_selected_text_highlights(false, window, cx);
 3315            self.refresh_matching_bracket_highlights(window, cx);
 3316            self.update_visible_edit_prediction(window, cx);
 3317            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3318            self.inline_blame_popover.take();
 3319            if self.git_blame_inline_enabled {
 3320                self.start_inline_blame_timer(window, cx);
 3321            }
 3322        }
 3323
 3324        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3325        cx.emit(EditorEvent::SelectionsChanged { local });
 3326
 3327        let selections = &self.selections.disjoint_anchors_arc();
 3328        if selections.len() == 1 {
 3329            cx.emit(SearchEvent::ActiveMatchChanged)
 3330        }
 3331        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3332            let inmemory_selections = selections
 3333                .iter()
 3334                .map(|s| {
 3335                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3336                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3337                })
 3338                .collect();
 3339            self.update_restoration_data(cx, |data| {
 3340                data.selections = inmemory_selections;
 3341            });
 3342
 3343            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3344                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3345            {
 3346                let snapshot = self.buffer().read(cx).snapshot(cx);
 3347                let selections = selections.clone();
 3348                let background_executor = cx.background_executor().clone();
 3349                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3350                self.serialize_selections = cx.background_spawn(async move {
 3351                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3352                    let db_selections = selections
 3353                        .iter()
 3354                        .map(|selection| {
 3355                            (
 3356                                selection.start.to_offset(&snapshot).0,
 3357                                selection.end.to_offset(&snapshot).0,
 3358                            )
 3359                        })
 3360                        .collect();
 3361
 3362                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3363                        .await
 3364                        .with_context(|| {
 3365                            format!(
 3366                                "persisting editor selections for editor {editor_id}, \
 3367                                workspace {workspace_id:?}"
 3368                            )
 3369                        })
 3370                        .log_err();
 3371                });
 3372            }
 3373        }
 3374
 3375        cx.notify();
 3376    }
 3377
 3378    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3379        use text::ToOffset as _;
 3380        use text::ToPoint as _;
 3381
 3382        if self.mode.is_minimap()
 3383            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3384        {
 3385            return;
 3386        }
 3387
 3388        if !self.buffer().read(cx).is_singleton() {
 3389            return;
 3390        }
 3391
 3392        let display_snapshot = self
 3393            .display_map
 3394            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3395        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3396            return;
 3397        };
 3398        let inmemory_folds = display_snapshot
 3399            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3400            .map(|fold| {
 3401                fold.range.start.text_anchor.to_point(&snapshot)
 3402                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3403            })
 3404            .collect();
 3405        self.update_restoration_data(cx, |data| {
 3406            data.folds = inmemory_folds;
 3407        });
 3408
 3409        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3410            return;
 3411        };
 3412        let background_executor = cx.background_executor().clone();
 3413        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3414        let db_folds = display_snapshot
 3415            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3416            .map(|fold| {
 3417                (
 3418                    fold.range.start.text_anchor.to_offset(&snapshot),
 3419                    fold.range.end.text_anchor.to_offset(&snapshot),
 3420                )
 3421            })
 3422            .collect();
 3423        self.serialize_folds = cx.background_spawn(async move {
 3424            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3425            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3426                .await
 3427                .with_context(|| {
 3428                    format!(
 3429                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3430                    )
 3431                })
 3432                .log_err();
 3433        });
 3434    }
 3435
 3436    pub fn sync_selections(
 3437        &mut self,
 3438        other: Entity<Editor>,
 3439        cx: &mut Context<Self>,
 3440    ) -> gpui::Subscription {
 3441        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3442        if !other_selections.is_empty() {
 3443            self.selections
 3444                .change_with(&self.display_snapshot(cx), |selections| {
 3445                    selections.select_anchors(other_selections);
 3446                });
 3447        }
 3448
 3449        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3450            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3451                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3452                if other_selections.is_empty() {
 3453                    return;
 3454                }
 3455                let snapshot = this.display_snapshot(cx);
 3456                this.selections.change_with(&snapshot, |selections| {
 3457                    selections.select_anchors(other_selections);
 3458                });
 3459            }
 3460        });
 3461
 3462        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3463            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3464                let these_selections = this.selections.disjoint_anchors().to_vec();
 3465                if these_selections.is_empty() {
 3466                    return;
 3467                }
 3468                other.update(cx, |other_editor, cx| {
 3469                    let snapshot = other_editor.display_snapshot(cx);
 3470                    other_editor
 3471                        .selections
 3472                        .change_with(&snapshot, |selections| {
 3473                            selections.select_anchors(these_selections);
 3474                        })
 3475                });
 3476            }
 3477        });
 3478
 3479        Subscription::join(other_subscription, this_subscription)
 3480    }
 3481
 3482    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3483        if self.buffer().read(cx).is_singleton() {
 3484            return;
 3485        }
 3486        let snapshot = self.buffer.read(cx).snapshot(cx);
 3487        let buffer_ids: HashSet<BufferId> = self
 3488            .selections
 3489            .disjoint_anchor_ranges()
 3490            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3491            .collect();
 3492        for buffer_id in buffer_ids {
 3493            self.unfold_buffer(buffer_id, cx);
 3494        }
 3495    }
 3496
 3497    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3498    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3499    /// effects of selection change occur at the end of the transaction.
 3500    pub fn change_selections<R>(
 3501        &mut self,
 3502        effects: SelectionEffects,
 3503        window: &mut Window,
 3504        cx: &mut Context<Self>,
 3505        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3506    ) -> R {
 3507        let snapshot = self.display_snapshot(cx);
 3508        if let Some(state) = &mut self.deferred_selection_effects_state {
 3509            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3510            state.effects.completions = effects.completions;
 3511            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3512            let (changed, result) = self.selections.change_with(&snapshot, change);
 3513            state.changed |= changed;
 3514            return result;
 3515        }
 3516        let mut state = DeferredSelectionEffectsState {
 3517            changed: false,
 3518            effects,
 3519            old_cursor_position: self.selections.newest_anchor().head(),
 3520            history_entry: SelectionHistoryEntry {
 3521                selections: self.selections.disjoint_anchors_arc(),
 3522                select_next_state: self.select_next_state.clone(),
 3523                select_prev_state: self.select_prev_state.clone(),
 3524                add_selections_state: self.add_selections_state.clone(),
 3525            },
 3526        };
 3527        let (changed, result) = self.selections.change_with(&snapshot, change);
 3528        state.changed = state.changed || changed;
 3529        if self.defer_selection_effects {
 3530            self.deferred_selection_effects_state = Some(state);
 3531        } else {
 3532            self.apply_selection_effects(state, window, cx);
 3533        }
 3534        result
 3535    }
 3536
 3537    /// Defers the effects of selection change, so that the effects of multiple calls to
 3538    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3539    /// to selection history and the state of popovers based on selection position aren't
 3540    /// erroneously updated.
 3541    pub fn with_selection_effects_deferred<R>(
 3542        &mut self,
 3543        window: &mut Window,
 3544        cx: &mut Context<Self>,
 3545        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3546    ) -> R {
 3547        let already_deferred = self.defer_selection_effects;
 3548        self.defer_selection_effects = true;
 3549        let result = update(self, window, cx);
 3550        if !already_deferred {
 3551            self.defer_selection_effects = false;
 3552            if let Some(state) = self.deferred_selection_effects_state.take() {
 3553                self.apply_selection_effects(state, window, cx);
 3554            }
 3555        }
 3556        result
 3557    }
 3558
 3559    fn apply_selection_effects(
 3560        &mut self,
 3561        state: DeferredSelectionEffectsState,
 3562        window: &mut Window,
 3563        cx: &mut Context<Self>,
 3564    ) {
 3565        if state.changed {
 3566            self.selection_history.push(state.history_entry);
 3567
 3568            if let Some(autoscroll) = state.effects.scroll {
 3569                self.request_autoscroll(autoscroll, cx);
 3570            }
 3571
 3572            let old_cursor_position = &state.old_cursor_position;
 3573
 3574            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3575
 3576            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3577                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3578            }
 3579        }
 3580    }
 3581
 3582    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3583    where
 3584        I: IntoIterator<Item = (Range<S>, T)>,
 3585        S: ToOffset,
 3586        T: Into<Arc<str>>,
 3587    {
 3588        if self.read_only(cx) {
 3589            return;
 3590        }
 3591
 3592        self.buffer
 3593            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3594    }
 3595
 3596    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3597    where
 3598        I: IntoIterator<Item = (Range<S>, T)>,
 3599        S: ToOffset,
 3600        T: Into<Arc<str>>,
 3601    {
 3602        if self.read_only(cx) {
 3603            return;
 3604        }
 3605
 3606        self.buffer.update(cx, |buffer, cx| {
 3607            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3608        });
 3609    }
 3610
 3611    pub fn edit_with_block_indent<I, S, T>(
 3612        &mut self,
 3613        edits: I,
 3614        original_indent_columns: Vec<Option<u32>>,
 3615        cx: &mut Context<Self>,
 3616    ) where
 3617        I: IntoIterator<Item = (Range<S>, T)>,
 3618        S: ToOffset,
 3619        T: Into<Arc<str>>,
 3620    {
 3621        if self.read_only(cx) {
 3622            return;
 3623        }
 3624
 3625        self.buffer.update(cx, |buffer, cx| {
 3626            buffer.edit(
 3627                edits,
 3628                Some(AutoindentMode::Block {
 3629                    original_indent_columns,
 3630                }),
 3631                cx,
 3632            )
 3633        });
 3634    }
 3635
 3636    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3637        self.hide_context_menu(window, cx);
 3638
 3639        match phase {
 3640            SelectPhase::Begin {
 3641                position,
 3642                add,
 3643                click_count,
 3644            } => self.begin_selection(position, add, click_count, window, cx),
 3645            SelectPhase::BeginColumnar {
 3646                position,
 3647                goal_column,
 3648                reset,
 3649                mode,
 3650            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3651            SelectPhase::Extend {
 3652                position,
 3653                click_count,
 3654            } => self.extend_selection(position, click_count, window, cx),
 3655            SelectPhase::Update {
 3656                position,
 3657                goal_column,
 3658                scroll_delta,
 3659            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3660            SelectPhase::End => self.end_selection(window, cx),
 3661        }
 3662    }
 3663
 3664    fn extend_selection(
 3665        &mut self,
 3666        position: DisplayPoint,
 3667        click_count: usize,
 3668        window: &mut Window,
 3669        cx: &mut Context<Self>,
 3670    ) {
 3671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3672        let tail = self
 3673            .selections
 3674            .newest::<MultiBufferOffset>(&display_map)
 3675            .tail();
 3676        let click_count = click_count.max(match self.selections.select_mode() {
 3677            SelectMode::Character => 1,
 3678            SelectMode::Word(_) => 2,
 3679            SelectMode::Line(_) => 3,
 3680            SelectMode::All => 4,
 3681        });
 3682        self.begin_selection(position, false, click_count, window, cx);
 3683
 3684        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3685
 3686        let current_selection = match self.selections.select_mode() {
 3687            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3688            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3689        };
 3690
 3691        let mut pending_selection = self
 3692            .selections
 3693            .pending_anchor()
 3694            .cloned()
 3695            .expect("extend_selection not called with pending selection");
 3696
 3697        if pending_selection
 3698            .start
 3699            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3700            == Ordering::Greater
 3701        {
 3702            pending_selection.start = current_selection.start;
 3703        }
 3704        if pending_selection
 3705            .end
 3706            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3707            == Ordering::Less
 3708        {
 3709            pending_selection.end = current_selection.end;
 3710            pending_selection.reversed = true;
 3711        }
 3712
 3713        let mut pending_mode = self.selections.pending_mode().unwrap();
 3714        match &mut pending_mode {
 3715            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3716            _ => {}
 3717        }
 3718
 3719        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3720            SelectionEffects::scroll(Autoscroll::fit())
 3721        } else {
 3722            SelectionEffects::no_scroll()
 3723        };
 3724
 3725        self.change_selections(effects, window, cx, |s| {
 3726            s.set_pending(pending_selection.clone(), pending_mode);
 3727            s.set_is_extending(true);
 3728        });
 3729    }
 3730
 3731    fn begin_selection(
 3732        &mut self,
 3733        position: DisplayPoint,
 3734        add: bool,
 3735        click_count: usize,
 3736        window: &mut Window,
 3737        cx: &mut Context<Self>,
 3738    ) {
 3739        if !self.focus_handle.is_focused(window) {
 3740            self.last_focused_descendant = None;
 3741            window.focus(&self.focus_handle);
 3742        }
 3743
 3744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3745        let buffer = display_map.buffer_snapshot();
 3746        let position = display_map.clip_point(position, Bias::Left);
 3747
 3748        let start;
 3749        let end;
 3750        let mode;
 3751        let mut auto_scroll;
 3752        match click_count {
 3753            1 => {
 3754                start = buffer.anchor_before(position.to_point(&display_map));
 3755                end = start;
 3756                mode = SelectMode::Character;
 3757                auto_scroll = true;
 3758            }
 3759            2 => {
 3760                let position = display_map
 3761                    .clip_point(position, Bias::Left)
 3762                    .to_offset(&display_map, Bias::Left);
 3763                let (range, _) = buffer.surrounding_word(position, None);
 3764                start = buffer.anchor_before(range.start);
 3765                end = buffer.anchor_before(range.end);
 3766                mode = SelectMode::Word(start..end);
 3767                auto_scroll = true;
 3768            }
 3769            3 => {
 3770                let position = display_map
 3771                    .clip_point(position, Bias::Left)
 3772                    .to_point(&display_map);
 3773                let line_start = display_map.prev_line_boundary(position).0;
 3774                let next_line_start = buffer.clip_point(
 3775                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3776                    Bias::Left,
 3777                );
 3778                start = buffer.anchor_before(line_start);
 3779                end = buffer.anchor_before(next_line_start);
 3780                mode = SelectMode::Line(start..end);
 3781                auto_scroll = true;
 3782            }
 3783            _ => {
 3784                start = buffer.anchor_before(MultiBufferOffset(0));
 3785                end = buffer.anchor_before(buffer.len());
 3786                mode = SelectMode::All;
 3787                auto_scroll = false;
 3788            }
 3789        }
 3790        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3791
 3792        let point_to_delete: Option<usize> = {
 3793            let selected_points: Vec<Selection<Point>> =
 3794                self.selections.disjoint_in_range(start..end, &display_map);
 3795
 3796            if !add || click_count > 1 {
 3797                None
 3798            } else if !selected_points.is_empty() {
 3799                Some(selected_points[0].id)
 3800            } else {
 3801                let clicked_point_already_selected =
 3802                    self.selections.disjoint_anchors().iter().find(|selection| {
 3803                        selection.start.to_point(buffer) == start.to_point(buffer)
 3804                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3805                    });
 3806
 3807                clicked_point_already_selected.map(|selection| selection.id)
 3808            }
 3809        };
 3810
 3811        let selections_count = self.selections.count();
 3812        let effects = if auto_scroll {
 3813            SelectionEffects::default()
 3814        } else {
 3815            SelectionEffects::no_scroll()
 3816        };
 3817
 3818        self.change_selections(effects, window, cx, |s| {
 3819            if let Some(point_to_delete) = point_to_delete {
 3820                s.delete(point_to_delete);
 3821
 3822                if selections_count == 1 {
 3823                    s.set_pending_anchor_range(start..end, mode);
 3824                }
 3825            } else {
 3826                if !add {
 3827                    s.clear_disjoint();
 3828                }
 3829
 3830                s.set_pending_anchor_range(start..end, mode);
 3831            }
 3832        });
 3833    }
 3834
 3835    fn begin_columnar_selection(
 3836        &mut self,
 3837        position: DisplayPoint,
 3838        goal_column: u32,
 3839        reset: bool,
 3840        mode: ColumnarMode,
 3841        window: &mut Window,
 3842        cx: &mut Context<Self>,
 3843    ) {
 3844        if !self.focus_handle.is_focused(window) {
 3845            self.last_focused_descendant = None;
 3846            window.focus(&self.focus_handle);
 3847        }
 3848
 3849        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3850
 3851        if reset {
 3852            let pointer_position = display_map
 3853                .buffer_snapshot()
 3854                .anchor_before(position.to_point(&display_map));
 3855
 3856            self.change_selections(
 3857                SelectionEffects::scroll(Autoscroll::newest()),
 3858                window,
 3859                cx,
 3860                |s| {
 3861                    s.clear_disjoint();
 3862                    s.set_pending_anchor_range(
 3863                        pointer_position..pointer_position,
 3864                        SelectMode::Character,
 3865                    );
 3866                },
 3867            );
 3868        };
 3869
 3870        let tail = self.selections.newest::<Point>(&display_map).tail();
 3871        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3872        self.columnar_selection_state = match mode {
 3873            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3874                selection_tail: selection_anchor,
 3875                display_point: if reset {
 3876                    if position.column() != goal_column {
 3877                        Some(DisplayPoint::new(position.row(), goal_column))
 3878                    } else {
 3879                        None
 3880                    }
 3881                } else {
 3882                    None
 3883                },
 3884            }),
 3885            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3886                selection_tail: selection_anchor,
 3887            }),
 3888        };
 3889
 3890        if !reset {
 3891            self.select_columns(position, goal_column, &display_map, window, cx);
 3892        }
 3893    }
 3894
 3895    fn update_selection(
 3896        &mut self,
 3897        position: DisplayPoint,
 3898        goal_column: u32,
 3899        scroll_delta: gpui::Point<f32>,
 3900        window: &mut Window,
 3901        cx: &mut Context<Self>,
 3902    ) {
 3903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3904
 3905        if self.columnar_selection_state.is_some() {
 3906            self.select_columns(position, goal_column, &display_map, window, cx);
 3907        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3908            let buffer = display_map.buffer_snapshot();
 3909            let head;
 3910            let tail;
 3911            let mode = self.selections.pending_mode().unwrap();
 3912            match &mode {
 3913                SelectMode::Character => {
 3914                    head = position.to_point(&display_map);
 3915                    tail = pending.tail().to_point(buffer);
 3916                }
 3917                SelectMode::Word(original_range) => {
 3918                    let offset = display_map
 3919                        .clip_point(position, Bias::Left)
 3920                        .to_offset(&display_map, Bias::Left);
 3921                    let original_range = original_range.to_offset(buffer);
 3922
 3923                    let head_offset = if buffer.is_inside_word(offset, None)
 3924                        || original_range.contains(&offset)
 3925                    {
 3926                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3927                        if word_range.start < original_range.start {
 3928                            word_range.start
 3929                        } else {
 3930                            word_range.end
 3931                        }
 3932                    } else {
 3933                        offset
 3934                    };
 3935
 3936                    head = head_offset.to_point(buffer);
 3937                    if head_offset <= original_range.start {
 3938                        tail = original_range.end.to_point(buffer);
 3939                    } else {
 3940                        tail = original_range.start.to_point(buffer);
 3941                    }
 3942                }
 3943                SelectMode::Line(original_range) => {
 3944                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3945
 3946                    let position = display_map
 3947                        .clip_point(position, Bias::Left)
 3948                        .to_point(&display_map);
 3949                    let line_start = display_map.prev_line_boundary(position).0;
 3950                    let next_line_start = buffer.clip_point(
 3951                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3952                        Bias::Left,
 3953                    );
 3954
 3955                    if line_start < original_range.start {
 3956                        head = line_start
 3957                    } else {
 3958                        head = next_line_start
 3959                    }
 3960
 3961                    if head <= original_range.start {
 3962                        tail = original_range.end;
 3963                    } else {
 3964                        tail = original_range.start;
 3965                    }
 3966                }
 3967                SelectMode::All => {
 3968                    return;
 3969                }
 3970            };
 3971
 3972            if head < tail {
 3973                pending.start = buffer.anchor_before(head);
 3974                pending.end = buffer.anchor_before(tail);
 3975                pending.reversed = true;
 3976            } else {
 3977                pending.start = buffer.anchor_before(tail);
 3978                pending.end = buffer.anchor_before(head);
 3979                pending.reversed = false;
 3980            }
 3981
 3982            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3983                s.set_pending(pending.clone(), mode);
 3984            });
 3985        } else {
 3986            log::error!("update_selection dispatched with no pending selection");
 3987            return;
 3988        }
 3989
 3990        self.apply_scroll_delta(scroll_delta, window, cx);
 3991        cx.notify();
 3992    }
 3993
 3994    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3995        self.columnar_selection_state.take();
 3996        if let Some(pending_mode) = self.selections.pending_mode() {
 3997            let selections = self
 3998                .selections
 3999                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4000            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4001                s.select(selections);
 4002                s.clear_pending();
 4003                if s.is_extending() {
 4004                    s.set_is_extending(false);
 4005                } else {
 4006                    s.set_select_mode(pending_mode);
 4007                }
 4008            });
 4009        }
 4010    }
 4011
 4012    fn select_columns(
 4013        &mut self,
 4014        head: DisplayPoint,
 4015        goal_column: u32,
 4016        display_map: &DisplaySnapshot,
 4017        window: &mut Window,
 4018        cx: &mut Context<Self>,
 4019    ) {
 4020        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4021            return;
 4022        };
 4023
 4024        let tail = match columnar_state {
 4025            ColumnarSelectionState::FromMouse {
 4026                selection_tail,
 4027                display_point,
 4028            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4029            ColumnarSelectionState::FromSelection { selection_tail } => {
 4030                selection_tail.to_display_point(display_map)
 4031            }
 4032        };
 4033
 4034        let start_row = cmp::min(tail.row(), head.row());
 4035        let end_row = cmp::max(tail.row(), head.row());
 4036        let start_column = cmp::min(tail.column(), goal_column);
 4037        let end_column = cmp::max(tail.column(), goal_column);
 4038        let reversed = start_column < tail.column();
 4039
 4040        let selection_ranges = (start_row.0..=end_row.0)
 4041            .map(DisplayRow)
 4042            .filter_map(|row| {
 4043                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4044                    || start_column <= display_map.line_len(row))
 4045                    && !display_map.is_block_line(row)
 4046                {
 4047                    let start = display_map
 4048                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4049                        .to_point(display_map);
 4050                    let end = display_map
 4051                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4052                        .to_point(display_map);
 4053                    if reversed {
 4054                        Some(end..start)
 4055                    } else {
 4056                        Some(start..end)
 4057                    }
 4058                } else {
 4059                    None
 4060                }
 4061            })
 4062            .collect::<Vec<_>>();
 4063        if selection_ranges.is_empty() {
 4064            return;
 4065        }
 4066
 4067        let ranges = match columnar_state {
 4068            ColumnarSelectionState::FromMouse { .. } => {
 4069                let mut non_empty_ranges = selection_ranges
 4070                    .iter()
 4071                    .filter(|selection_range| selection_range.start != selection_range.end)
 4072                    .peekable();
 4073                if non_empty_ranges.peek().is_some() {
 4074                    non_empty_ranges.cloned().collect()
 4075                } else {
 4076                    selection_ranges
 4077                }
 4078            }
 4079            _ => selection_ranges,
 4080        };
 4081
 4082        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4083            s.select_ranges(ranges);
 4084        });
 4085        cx.notify();
 4086    }
 4087
 4088    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4089        self.selections
 4090            .all_adjusted(snapshot)
 4091            .iter()
 4092            .any(|selection| !selection.is_empty())
 4093    }
 4094
 4095    pub fn has_pending_nonempty_selection(&self) -> bool {
 4096        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4097            Some(Selection { start, end, .. }) => start != end,
 4098            None => false,
 4099        };
 4100
 4101        pending_nonempty_selection
 4102            || (self.columnar_selection_state.is_some()
 4103                && self.selections.disjoint_anchors().len() > 1)
 4104    }
 4105
 4106    pub fn has_pending_selection(&self) -> bool {
 4107        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4108    }
 4109
 4110    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4111        self.selection_mark_mode = false;
 4112        self.selection_drag_state = SelectionDragState::None;
 4113
 4114        if self.dismiss_menus_and_popups(true, window, cx) {
 4115            cx.notify();
 4116            return;
 4117        }
 4118        if self.clear_expanded_diff_hunks(cx) {
 4119            cx.notify();
 4120            return;
 4121        }
 4122        if self.show_git_blame_gutter {
 4123            self.show_git_blame_gutter = false;
 4124            cx.notify();
 4125            return;
 4126        }
 4127
 4128        if self.mode.is_full()
 4129            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4130        {
 4131            cx.notify();
 4132            return;
 4133        }
 4134
 4135        cx.propagate();
 4136    }
 4137
 4138    pub fn dismiss_menus_and_popups(
 4139        &mut self,
 4140        is_user_requested: bool,
 4141        window: &mut Window,
 4142        cx: &mut Context<Self>,
 4143    ) -> bool {
 4144        let mut dismissed = false;
 4145
 4146        dismissed |= self.take_rename(false, window, cx).is_some();
 4147        dismissed |= self.hide_blame_popover(true, cx);
 4148        dismissed |= hide_hover(self, cx);
 4149        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4150        dismissed |= self.hide_context_menu(window, cx).is_some();
 4151        dismissed |= self.mouse_context_menu.take().is_some();
 4152        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4153        dismissed |= self.snippet_stack.pop().is_some();
 4154
 4155        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4156            self.dismiss_diagnostics(cx);
 4157            dismissed = true;
 4158        }
 4159
 4160        dismissed
 4161    }
 4162
 4163    fn linked_editing_ranges_for(
 4164        &self,
 4165        selection: Range<text::Anchor>,
 4166        cx: &App,
 4167    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4168        if self.linked_edit_ranges.is_empty() {
 4169            return None;
 4170        }
 4171        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4172            selection.end.buffer_id.and_then(|end_buffer_id| {
 4173                if selection.start.buffer_id != Some(end_buffer_id) {
 4174                    return None;
 4175                }
 4176                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4177                let snapshot = buffer.read(cx).snapshot();
 4178                self.linked_edit_ranges
 4179                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4180                    .map(|ranges| (ranges, snapshot, buffer))
 4181            })?;
 4182        use text::ToOffset as TO;
 4183        // find offset from the start of current range to current cursor position
 4184        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4185
 4186        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4187        let start_difference = start_offset - start_byte_offset;
 4188        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4189        let end_difference = end_offset - start_byte_offset;
 4190        // Current range has associated linked ranges.
 4191        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4192        for range in linked_ranges.iter() {
 4193            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4194            let end_offset = start_offset + end_difference;
 4195            let start_offset = start_offset + start_difference;
 4196            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4197                continue;
 4198            }
 4199            if self.selections.disjoint_anchor_ranges().any(|s| {
 4200                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4201                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4202                {
 4203                    return false;
 4204                }
 4205                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4206                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4207            }) {
 4208                continue;
 4209            }
 4210            let start = buffer_snapshot.anchor_after(start_offset);
 4211            let end = buffer_snapshot.anchor_after(end_offset);
 4212            linked_edits
 4213                .entry(buffer.clone())
 4214                .or_default()
 4215                .push(start..end);
 4216        }
 4217        Some(linked_edits)
 4218    }
 4219
 4220    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4221        let text: Arc<str> = text.into();
 4222
 4223        if self.read_only(cx) {
 4224            return;
 4225        }
 4226
 4227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4228
 4229        self.unfold_buffers_with_selections(cx);
 4230
 4231        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4232        let mut bracket_inserted = false;
 4233        let mut edits = Vec::new();
 4234        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4235        let mut new_selections = Vec::with_capacity(selections.len());
 4236        let mut new_autoclose_regions = Vec::new();
 4237        let snapshot = self.buffer.read(cx).read(cx);
 4238        let mut clear_linked_edit_ranges = false;
 4239
 4240        for (selection, autoclose_region) in
 4241            self.selections_with_autoclose_regions(selections, &snapshot)
 4242        {
 4243            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4244                // Determine if the inserted text matches the opening or closing
 4245                // bracket of any of this language's bracket pairs.
 4246                let mut bracket_pair = None;
 4247                let mut is_bracket_pair_start = false;
 4248                let mut is_bracket_pair_end = false;
 4249                if !text.is_empty() {
 4250                    let mut bracket_pair_matching_end = None;
 4251                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4252                    //  and they are removing the character that triggered IME popup.
 4253                    for (pair, enabled) in scope.brackets() {
 4254                        if !pair.close && !pair.surround {
 4255                            continue;
 4256                        }
 4257
 4258                        if enabled && pair.start.ends_with(text.as_ref()) {
 4259                            let prefix_len = pair.start.len() - text.len();
 4260                            let preceding_text_matches_prefix = prefix_len == 0
 4261                                || (selection.start.column >= (prefix_len as u32)
 4262                                    && snapshot.contains_str_at(
 4263                                        Point::new(
 4264                                            selection.start.row,
 4265                                            selection.start.column - (prefix_len as u32),
 4266                                        ),
 4267                                        &pair.start[..prefix_len],
 4268                                    ));
 4269                            if preceding_text_matches_prefix {
 4270                                bracket_pair = Some(pair.clone());
 4271                                is_bracket_pair_start = true;
 4272                                break;
 4273                            }
 4274                        }
 4275                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4276                        {
 4277                            // take first bracket pair matching end, but don't break in case a later bracket
 4278                            // pair matches start
 4279                            bracket_pair_matching_end = Some(pair.clone());
 4280                        }
 4281                    }
 4282                    if let Some(end) = bracket_pair_matching_end
 4283                        && bracket_pair.is_none()
 4284                    {
 4285                        bracket_pair = Some(end);
 4286                        is_bracket_pair_end = true;
 4287                    }
 4288                }
 4289
 4290                if let Some(bracket_pair) = bracket_pair {
 4291                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4292                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4293                    let auto_surround =
 4294                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4295                    if selection.is_empty() {
 4296                        if is_bracket_pair_start {
 4297                            // If the inserted text is a suffix of an opening bracket and the
 4298                            // selection is preceded by the rest of the opening bracket, then
 4299                            // insert the closing bracket.
 4300                            let following_text_allows_autoclose = snapshot
 4301                                .chars_at(selection.start)
 4302                                .next()
 4303                                .is_none_or(|c| scope.should_autoclose_before(c));
 4304
 4305                            let preceding_text_allows_autoclose = selection.start.column == 0
 4306                                || snapshot
 4307                                    .reversed_chars_at(selection.start)
 4308                                    .next()
 4309                                    .is_none_or(|c| {
 4310                                        bracket_pair.start != bracket_pair.end
 4311                                            || !snapshot
 4312                                                .char_classifier_at(selection.start)
 4313                                                .is_word(c)
 4314                                    });
 4315
 4316                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4317                                && bracket_pair.start.len() == 1
 4318                            {
 4319                                let target = bracket_pair.start.chars().next().unwrap();
 4320                                let current_line_count = snapshot
 4321                                    .reversed_chars_at(selection.start)
 4322                                    .take_while(|&c| c != '\n')
 4323                                    .filter(|&c| c == target)
 4324                                    .count();
 4325                                current_line_count % 2 == 1
 4326                            } else {
 4327                                false
 4328                            };
 4329
 4330                            if autoclose
 4331                                && bracket_pair.close
 4332                                && following_text_allows_autoclose
 4333                                && preceding_text_allows_autoclose
 4334                                && !is_closing_quote
 4335                            {
 4336                                let anchor = snapshot.anchor_before(selection.end);
 4337                                new_selections.push((selection.map(|_| anchor), text.len()));
 4338                                new_autoclose_regions.push((
 4339                                    anchor,
 4340                                    text.len(),
 4341                                    selection.id,
 4342                                    bracket_pair.clone(),
 4343                                ));
 4344                                edits.push((
 4345                                    selection.range(),
 4346                                    format!("{}{}", text, bracket_pair.end).into(),
 4347                                ));
 4348                                bracket_inserted = true;
 4349                                continue;
 4350                            }
 4351                        }
 4352
 4353                        if let Some(region) = autoclose_region {
 4354                            // If the selection is followed by an auto-inserted closing bracket,
 4355                            // then don't insert that closing bracket again; just move the selection
 4356                            // past the closing bracket.
 4357                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4358                                && text.as_ref() == region.pair.end.as_str()
 4359                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4360                            if should_skip {
 4361                                let anchor = snapshot.anchor_after(selection.end);
 4362                                new_selections
 4363                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4364                                continue;
 4365                            }
 4366                        }
 4367
 4368                        let always_treat_brackets_as_autoclosed = snapshot
 4369                            .language_settings_at(selection.start, cx)
 4370                            .always_treat_brackets_as_autoclosed;
 4371                        if always_treat_brackets_as_autoclosed
 4372                            && is_bracket_pair_end
 4373                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4374                        {
 4375                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4376                            // and the inserted text is a closing bracket and the selection is followed
 4377                            // by the closing bracket then move the selection past the closing bracket.
 4378                            let anchor = snapshot.anchor_after(selection.end);
 4379                            new_selections.push((selection.map(|_| anchor), text.len()));
 4380                            continue;
 4381                        }
 4382                    }
 4383                    // If an opening bracket is 1 character long and is typed while
 4384                    // text is selected, then surround that text with the bracket pair.
 4385                    else if auto_surround
 4386                        && bracket_pair.surround
 4387                        && is_bracket_pair_start
 4388                        && bracket_pair.start.chars().count() == 1
 4389                    {
 4390                        edits.push((selection.start..selection.start, text.clone()));
 4391                        edits.push((
 4392                            selection.end..selection.end,
 4393                            bracket_pair.end.as_str().into(),
 4394                        ));
 4395                        bracket_inserted = true;
 4396                        new_selections.push((
 4397                            Selection {
 4398                                id: selection.id,
 4399                                start: snapshot.anchor_after(selection.start),
 4400                                end: snapshot.anchor_before(selection.end),
 4401                                reversed: selection.reversed,
 4402                                goal: selection.goal,
 4403                            },
 4404                            0,
 4405                        ));
 4406                        continue;
 4407                    }
 4408                }
 4409            }
 4410
 4411            if self.auto_replace_emoji_shortcode
 4412                && selection.is_empty()
 4413                && text.as_ref().ends_with(':')
 4414                && let Some(possible_emoji_short_code) =
 4415                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4416                && !possible_emoji_short_code.is_empty()
 4417                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4418            {
 4419                let emoji_shortcode_start = Point::new(
 4420                    selection.start.row,
 4421                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4422                );
 4423
 4424                // Remove shortcode from buffer
 4425                edits.push((
 4426                    emoji_shortcode_start..selection.start,
 4427                    "".to_string().into(),
 4428                ));
 4429                new_selections.push((
 4430                    Selection {
 4431                        id: selection.id,
 4432                        start: snapshot.anchor_after(emoji_shortcode_start),
 4433                        end: snapshot.anchor_before(selection.start),
 4434                        reversed: selection.reversed,
 4435                        goal: selection.goal,
 4436                    },
 4437                    0,
 4438                ));
 4439
 4440                // Insert emoji
 4441                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4442                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4443                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4444
 4445                continue;
 4446            }
 4447
 4448            // If not handling any auto-close operation, then just replace the selected
 4449            // text with the given input and move the selection to the end of the
 4450            // newly inserted text.
 4451            let anchor = snapshot.anchor_after(selection.end);
 4452            if !self.linked_edit_ranges.is_empty() {
 4453                let start_anchor = snapshot.anchor_before(selection.start);
 4454
 4455                let is_word_char = text.chars().next().is_none_or(|char| {
 4456                    let classifier = snapshot
 4457                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4458                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4459                    classifier.is_word(char)
 4460                });
 4461
 4462                if is_word_char {
 4463                    if let Some(ranges) = self
 4464                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4465                    {
 4466                        for (buffer, edits) in ranges {
 4467                            linked_edits
 4468                                .entry(buffer.clone())
 4469                                .or_default()
 4470                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4471                        }
 4472                    }
 4473                } else {
 4474                    clear_linked_edit_ranges = true;
 4475                }
 4476            }
 4477
 4478            new_selections.push((selection.map(|_| anchor), 0));
 4479            edits.push((selection.start..selection.end, text.clone()));
 4480        }
 4481
 4482        drop(snapshot);
 4483
 4484        self.transact(window, cx, |this, window, cx| {
 4485            if clear_linked_edit_ranges {
 4486                this.linked_edit_ranges.clear();
 4487            }
 4488            let initial_buffer_versions =
 4489                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4490
 4491            this.buffer.update(cx, |buffer, cx| {
 4492                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4493            });
 4494            for (buffer, edits) in linked_edits {
 4495                buffer.update(cx, |buffer, cx| {
 4496                    let snapshot = buffer.snapshot();
 4497                    let edits = edits
 4498                        .into_iter()
 4499                        .map(|(range, text)| {
 4500                            use text::ToPoint as TP;
 4501                            let end_point = TP::to_point(&range.end, &snapshot);
 4502                            let start_point = TP::to_point(&range.start, &snapshot);
 4503                            (start_point..end_point, text)
 4504                        })
 4505                        .sorted_by_key(|(range, _)| range.start);
 4506                    buffer.edit(edits, None, cx);
 4507                })
 4508            }
 4509            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4510            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4511            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4512            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4513                new_anchor_selections,
 4514                &map,
 4515            )
 4516            .zip(new_selection_deltas)
 4517            .map(|(selection, delta)| Selection {
 4518                id: selection.id,
 4519                start: selection.start + delta,
 4520                end: selection.end + delta,
 4521                reversed: selection.reversed,
 4522                goal: SelectionGoal::None,
 4523            })
 4524            .collect::<Vec<_>>();
 4525
 4526            let mut i = 0;
 4527            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4528                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4529                let start = map.buffer_snapshot().anchor_before(position);
 4530                let end = map.buffer_snapshot().anchor_after(position);
 4531                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4532                    match existing_state
 4533                        .range
 4534                        .start
 4535                        .cmp(&start, map.buffer_snapshot())
 4536                    {
 4537                        Ordering::Less => i += 1,
 4538                        Ordering::Greater => break,
 4539                        Ordering::Equal => {
 4540                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4541                                Ordering::Less => i += 1,
 4542                                Ordering::Equal => break,
 4543                                Ordering::Greater => break,
 4544                            }
 4545                        }
 4546                    }
 4547                }
 4548                this.autoclose_regions.insert(
 4549                    i,
 4550                    AutocloseRegion {
 4551                        selection_id,
 4552                        range: start..end,
 4553                        pair,
 4554                    },
 4555                );
 4556            }
 4557
 4558            let had_active_edit_prediction = this.has_active_edit_prediction();
 4559            this.change_selections(
 4560                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4561                window,
 4562                cx,
 4563                |s| s.select(new_selections),
 4564            );
 4565
 4566            if !bracket_inserted
 4567                && let Some(on_type_format_task) =
 4568                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4569            {
 4570                on_type_format_task.detach_and_log_err(cx);
 4571            }
 4572
 4573            let editor_settings = EditorSettings::get_global(cx);
 4574            if bracket_inserted
 4575                && (editor_settings.auto_signature_help
 4576                    || editor_settings.show_signature_help_after_edits)
 4577            {
 4578                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4579            }
 4580
 4581            let trigger_in_words =
 4582                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4583            if this.hard_wrap.is_some() {
 4584                let latest: Range<Point> = this.selections.newest(&map).range();
 4585                if latest.is_empty()
 4586                    && this
 4587                        .buffer()
 4588                        .read(cx)
 4589                        .snapshot(cx)
 4590                        .line_len(MultiBufferRow(latest.start.row))
 4591                        == latest.start.column
 4592                {
 4593                    this.rewrap_impl(
 4594                        RewrapOptions {
 4595                            override_language_settings: true,
 4596                            preserve_existing_whitespace: true,
 4597                        },
 4598                        cx,
 4599                    )
 4600                }
 4601            }
 4602            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4603            refresh_linked_ranges(this, window, cx);
 4604            this.refresh_edit_prediction(true, false, window, cx);
 4605            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4606        });
 4607    }
 4608
 4609    fn find_possible_emoji_shortcode_at_position(
 4610        snapshot: &MultiBufferSnapshot,
 4611        position: Point,
 4612    ) -> Option<String> {
 4613        let mut chars = Vec::new();
 4614        let mut found_colon = false;
 4615        for char in snapshot.reversed_chars_at(position).take(100) {
 4616            // Found a possible emoji shortcode in the middle of the buffer
 4617            if found_colon {
 4618                if char.is_whitespace() {
 4619                    chars.reverse();
 4620                    return Some(chars.iter().collect());
 4621                }
 4622                // If the previous character is not a whitespace, we are in the middle of a word
 4623                // and we only want to complete the shortcode if the word is made up of other emojis
 4624                let mut containing_word = String::new();
 4625                for ch in snapshot
 4626                    .reversed_chars_at(position)
 4627                    .skip(chars.len() + 1)
 4628                    .take(100)
 4629                {
 4630                    if ch.is_whitespace() {
 4631                        break;
 4632                    }
 4633                    containing_word.push(ch);
 4634                }
 4635                let containing_word = containing_word.chars().rev().collect::<String>();
 4636                if util::word_consists_of_emojis(containing_word.as_str()) {
 4637                    chars.reverse();
 4638                    return Some(chars.iter().collect());
 4639                }
 4640            }
 4641
 4642            if char.is_whitespace() || !char.is_ascii() {
 4643                return None;
 4644            }
 4645            if char == ':' {
 4646                found_colon = true;
 4647            } else {
 4648                chars.push(char);
 4649            }
 4650        }
 4651        // Found a possible emoji shortcode at the beginning of the buffer
 4652        chars.reverse();
 4653        Some(chars.iter().collect())
 4654    }
 4655
 4656    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4658        self.transact(window, cx, |this, window, cx| {
 4659            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4660                let selections = this
 4661                    .selections
 4662                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4663                let multi_buffer = this.buffer.read(cx);
 4664                let buffer = multi_buffer.snapshot(cx);
 4665                selections
 4666                    .iter()
 4667                    .map(|selection| {
 4668                        let start_point = selection.start.to_point(&buffer);
 4669                        let mut existing_indent =
 4670                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4671                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4672                        let start = selection.start;
 4673                        let end = selection.end;
 4674                        let selection_is_empty = start == end;
 4675                        let language_scope = buffer.language_scope_at(start);
 4676                        let (
 4677                            comment_delimiter,
 4678                            doc_delimiter,
 4679                            insert_extra_newline,
 4680                            indent_on_newline,
 4681                            indent_on_extra_newline,
 4682                        ) = if let Some(language) = &language_scope {
 4683                            let mut insert_extra_newline =
 4684                                insert_extra_newline_brackets(&buffer, start..end, language)
 4685                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4686
 4687                            // Comment extension on newline is allowed only for cursor selections
 4688                            let comment_delimiter = maybe!({
 4689                                if !selection_is_empty {
 4690                                    return None;
 4691                                }
 4692
 4693                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4694                                    return None;
 4695                                }
 4696
 4697                                let delimiters = language.line_comment_prefixes();
 4698                                let max_len_of_delimiter =
 4699                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4700                                let (snapshot, range) =
 4701                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4702
 4703                                let num_of_whitespaces = snapshot
 4704                                    .chars_for_range(range.clone())
 4705                                    .take_while(|c| c.is_whitespace())
 4706                                    .count();
 4707                                let comment_candidate = snapshot
 4708                                    .chars_for_range(range.clone())
 4709                                    .skip(num_of_whitespaces)
 4710                                    .take(max_len_of_delimiter)
 4711                                    .collect::<String>();
 4712                                let (delimiter, trimmed_len) = delimiters
 4713                                    .iter()
 4714                                    .filter_map(|delimiter| {
 4715                                        let prefix = delimiter.trim_end();
 4716                                        if comment_candidate.starts_with(prefix) {
 4717                                            Some((delimiter, prefix.len()))
 4718                                        } else {
 4719                                            None
 4720                                        }
 4721                                    })
 4722                                    .max_by_key(|(_, len)| *len)?;
 4723
 4724                                if let Some(BlockCommentConfig {
 4725                                    start: block_start, ..
 4726                                }) = language.block_comment()
 4727                                {
 4728                                    let block_start_trimmed = block_start.trim_end();
 4729                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4730                                        let line_content = snapshot
 4731                                            .chars_for_range(range)
 4732                                            .skip(num_of_whitespaces)
 4733                                            .take(block_start_trimmed.len())
 4734                                            .collect::<String>();
 4735
 4736                                        if line_content.starts_with(block_start_trimmed) {
 4737                                            return None;
 4738                                        }
 4739                                    }
 4740                                }
 4741
 4742                                let cursor_is_placed_after_comment_marker =
 4743                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4744                                if cursor_is_placed_after_comment_marker {
 4745                                    Some(delimiter.clone())
 4746                                } else {
 4747                                    None
 4748                                }
 4749                            });
 4750
 4751                            let mut indent_on_newline = IndentSize::spaces(0);
 4752                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4753
 4754                            let doc_delimiter = maybe!({
 4755                                if !selection_is_empty {
 4756                                    return None;
 4757                                }
 4758
 4759                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4760                                    return None;
 4761                                }
 4762
 4763                                let BlockCommentConfig {
 4764                                    start: start_tag,
 4765                                    end: end_tag,
 4766                                    prefix: delimiter,
 4767                                    tab_size: len,
 4768                                } = language.documentation_comment()?;
 4769                                let is_within_block_comment = buffer
 4770                                    .language_scope_at(start_point)
 4771                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4772                                if !is_within_block_comment {
 4773                                    return None;
 4774                                }
 4775
 4776                                let (snapshot, range) =
 4777                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4778
 4779                                let num_of_whitespaces = snapshot
 4780                                    .chars_for_range(range.clone())
 4781                                    .take_while(|c| c.is_whitespace())
 4782                                    .count();
 4783
 4784                                // 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.
 4785                                let column = start_point.column;
 4786                                let cursor_is_after_start_tag = {
 4787                                    let start_tag_len = start_tag.len();
 4788                                    let start_tag_line = snapshot
 4789                                        .chars_for_range(range.clone())
 4790                                        .skip(num_of_whitespaces)
 4791                                        .take(start_tag_len)
 4792                                        .collect::<String>();
 4793                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4794                                        num_of_whitespaces + start_tag_len <= column as usize
 4795                                    } else {
 4796                                        false
 4797                                    }
 4798                                };
 4799
 4800                                let cursor_is_after_delimiter = {
 4801                                    let delimiter_trim = delimiter.trim_end();
 4802                                    let delimiter_line = snapshot
 4803                                        .chars_for_range(range.clone())
 4804                                        .skip(num_of_whitespaces)
 4805                                        .take(delimiter_trim.len())
 4806                                        .collect::<String>();
 4807                                    if delimiter_line.starts_with(delimiter_trim) {
 4808                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4809                                    } else {
 4810                                        false
 4811                                    }
 4812                                };
 4813
 4814                                let cursor_is_before_end_tag_if_exists = {
 4815                                    let mut char_position = 0u32;
 4816                                    let mut end_tag_offset = None;
 4817
 4818                                    'outer: for chunk in snapshot.text_for_range(range) {
 4819                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4820                                            let chars_before_match =
 4821                                                chunk[..byte_pos].chars().count() as u32;
 4822                                            end_tag_offset =
 4823                                                Some(char_position + chars_before_match);
 4824                                            break 'outer;
 4825                                        }
 4826                                        char_position += chunk.chars().count() as u32;
 4827                                    }
 4828
 4829                                    if let Some(end_tag_offset) = end_tag_offset {
 4830                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4831                                        if cursor_is_after_start_tag {
 4832                                            if cursor_is_before_end_tag {
 4833                                                insert_extra_newline = true;
 4834                                            }
 4835                                            let cursor_is_at_start_of_end_tag =
 4836                                                column == end_tag_offset;
 4837                                            if cursor_is_at_start_of_end_tag {
 4838                                                indent_on_extra_newline.len = *len;
 4839                                            }
 4840                                        }
 4841                                        cursor_is_before_end_tag
 4842                                    } else {
 4843                                        true
 4844                                    }
 4845                                };
 4846
 4847                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4848                                    && cursor_is_before_end_tag_if_exists
 4849                                {
 4850                                    if cursor_is_after_start_tag {
 4851                                        indent_on_newline.len = *len;
 4852                                    }
 4853                                    Some(delimiter.clone())
 4854                                } else {
 4855                                    None
 4856                                }
 4857                            });
 4858
 4859                            (
 4860                                comment_delimiter,
 4861                                doc_delimiter,
 4862                                insert_extra_newline,
 4863                                indent_on_newline,
 4864                                indent_on_extra_newline,
 4865                            )
 4866                        } else {
 4867                            (
 4868                                None,
 4869                                None,
 4870                                false,
 4871                                IndentSize::default(),
 4872                                IndentSize::default(),
 4873                            )
 4874                        };
 4875
 4876                        let prevent_auto_indent = doc_delimiter.is_some();
 4877                        let delimiter = comment_delimiter.or(doc_delimiter);
 4878
 4879                        let capacity_for_delimiter =
 4880                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4881                        let mut new_text = String::with_capacity(
 4882                            1 + capacity_for_delimiter
 4883                                + existing_indent.len as usize
 4884                                + indent_on_newline.len as usize
 4885                                + indent_on_extra_newline.len as usize,
 4886                        );
 4887                        new_text.push('\n');
 4888                        new_text.extend(existing_indent.chars());
 4889                        new_text.extend(indent_on_newline.chars());
 4890
 4891                        if let Some(delimiter) = &delimiter {
 4892                            new_text.push_str(delimiter);
 4893                        }
 4894
 4895                        if insert_extra_newline {
 4896                            new_text.push('\n');
 4897                            new_text.extend(existing_indent.chars());
 4898                            new_text.extend(indent_on_extra_newline.chars());
 4899                        }
 4900
 4901                        let anchor = buffer.anchor_after(end);
 4902                        let new_selection = selection.map(|_| anchor);
 4903                        (
 4904                            ((start..end, new_text), prevent_auto_indent),
 4905                            (insert_extra_newline, new_selection),
 4906                        )
 4907                    })
 4908                    .unzip()
 4909            };
 4910
 4911            let mut auto_indent_edits = Vec::new();
 4912            let mut edits = Vec::new();
 4913            for (edit, prevent_auto_indent) in edits_with_flags {
 4914                if prevent_auto_indent {
 4915                    edits.push(edit);
 4916                } else {
 4917                    auto_indent_edits.push(edit);
 4918                }
 4919            }
 4920            if !edits.is_empty() {
 4921                this.edit(edits, cx);
 4922            }
 4923            if !auto_indent_edits.is_empty() {
 4924                this.edit_with_autoindent(auto_indent_edits, cx);
 4925            }
 4926
 4927            let buffer = this.buffer.read(cx).snapshot(cx);
 4928            let new_selections = selection_info
 4929                .into_iter()
 4930                .map(|(extra_newline_inserted, new_selection)| {
 4931                    let mut cursor = new_selection.end.to_point(&buffer);
 4932                    if extra_newline_inserted {
 4933                        cursor.row -= 1;
 4934                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4935                    }
 4936                    new_selection.map(|_| cursor)
 4937                })
 4938                .collect();
 4939
 4940            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4941            this.refresh_edit_prediction(true, false, window, cx);
 4942        });
 4943    }
 4944
 4945    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4947
 4948        let buffer = self.buffer.read(cx);
 4949        let snapshot = buffer.snapshot(cx);
 4950
 4951        let mut edits = Vec::new();
 4952        let mut rows = Vec::new();
 4953
 4954        for (rows_inserted, selection) in self
 4955            .selections
 4956            .all_adjusted(&self.display_snapshot(cx))
 4957            .into_iter()
 4958            .enumerate()
 4959        {
 4960            let cursor = selection.head();
 4961            let row = cursor.row;
 4962
 4963            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4964
 4965            let newline = "\n".to_string();
 4966            edits.push((start_of_line..start_of_line, newline));
 4967
 4968            rows.push(row + rows_inserted as u32);
 4969        }
 4970
 4971        self.transact(window, cx, |editor, window, cx| {
 4972            editor.edit(edits, cx);
 4973
 4974            editor.change_selections(Default::default(), window, cx, |s| {
 4975                let mut index = 0;
 4976                s.move_cursors_with(|map, _, _| {
 4977                    let row = rows[index];
 4978                    index += 1;
 4979
 4980                    let point = Point::new(row, 0);
 4981                    let boundary = map.next_line_boundary(point).1;
 4982                    let clipped = map.clip_point(boundary, Bias::Left);
 4983
 4984                    (clipped, SelectionGoal::None)
 4985                });
 4986            });
 4987
 4988            let mut indent_edits = Vec::new();
 4989            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4990            for row in rows {
 4991                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4992                for (row, indent) in indents {
 4993                    if indent.len == 0 {
 4994                        continue;
 4995                    }
 4996
 4997                    let text = match indent.kind {
 4998                        IndentKind::Space => " ".repeat(indent.len as usize),
 4999                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5000                    };
 5001                    let point = Point::new(row.0, 0);
 5002                    indent_edits.push((point..point, text));
 5003                }
 5004            }
 5005            editor.edit(indent_edits, cx);
 5006        });
 5007    }
 5008
 5009    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5011
 5012        let buffer = self.buffer.read(cx);
 5013        let snapshot = buffer.snapshot(cx);
 5014
 5015        let mut edits = Vec::new();
 5016        let mut rows = Vec::new();
 5017        let mut rows_inserted = 0;
 5018
 5019        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5020            let cursor = selection.head();
 5021            let row = cursor.row;
 5022
 5023            let point = Point::new(row + 1, 0);
 5024            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5025
 5026            let newline = "\n".to_string();
 5027            edits.push((start_of_line..start_of_line, newline));
 5028
 5029            rows_inserted += 1;
 5030            rows.push(row + rows_inserted);
 5031        }
 5032
 5033        self.transact(window, cx, |editor, window, cx| {
 5034            editor.edit(edits, cx);
 5035
 5036            editor.change_selections(Default::default(), window, cx, |s| {
 5037                let mut index = 0;
 5038                s.move_cursors_with(|map, _, _| {
 5039                    let row = rows[index];
 5040                    index += 1;
 5041
 5042                    let point = Point::new(row, 0);
 5043                    let boundary = map.next_line_boundary(point).1;
 5044                    let clipped = map.clip_point(boundary, Bias::Left);
 5045
 5046                    (clipped, SelectionGoal::None)
 5047                });
 5048            });
 5049
 5050            let mut indent_edits = Vec::new();
 5051            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5052            for row in rows {
 5053                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5054                for (row, indent) in indents {
 5055                    if indent.len == 0 {
 5056                        continue;
 5057                    }
 5058
 5059                    let text = match indent.kind {
 5060                        IndentKind::Space => " ".repeat(indent.len as usize),
 5061                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5062                    };
 5063                    let point = Point::new(row.0, 0);
 5064                    indent_edits.push((point..point, text));
 5065                }
 5066            }
 5067            editor.edit(indent_edits, cx);
 5068        });
 5069    }
 5070
 5071    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5072        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5073            original_indent_columns: Vec::new(),
 5074        });
 5075        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5076    }
 5077
 5078    fn insert_with_autoindent_mode(
 5079        &mut self,
 5080        text: &str,
 5081        autoindent_mode: Option<AutoindentMode>,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        if self.read_only(cx) {
 5086            return;
 5087        }
 5088
 5089        let text: Arc<str> = text.into();
 5090        self.transact(window, cx, |this, window, cx| {
 5091            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5092            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5093                let anchors = {
 5094                    let snapshot = buffer.read(cx);
 5095                    old_selections
 5096                        .iter()
 5097                        .map(|s| {
 5098                            let anchor = snapshot.anchor_after(s.head());
 5099                            s.map(|_| anchor)
 5100                        })
 5101                        .collect::<Vec<_>>()
 5102                };
 5103                buffer.edit(
 5104                    old_selections
 5105                        .iter()
 5106                        .map(|s| (s.start..s.end, text.clone())),
 5107                    autoindent_mode,
 5108                    cx,
 5109                );
 5110                anchors
 5111            });
 5112
 5113            this.change_selections(Default::default(), window, cx, |s| {
 5114                s.select_anchors(selection_anchors);
 5115            });
 5116
 5117            cx.notify();
 5118        });
 5119    }
 5120
 5121    fn trigger_completion_on_input(
 5122        &mut self,
 5123        text: &str,
 5124        trigger_in_words: bool,
 5125        window: &mut Window,
 5126        cx: &mut Context<Self>,
 5127    ) {
 5128        let completions_source = self
 5129            .context_menu
 5130            .borrow()
 5131            .as_ref()
 5132            .and_then(|menu| match menu {
 5133                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5134                CodeContextMenu::CodeActions(_) => None,
 5135            });
 5136
 5137        match completions_source {
 5138            Some(CompletionsMenuSource::Words { .. }) => {
 5139                self.open_or_update_completions_menu(
 5140                    Some(CompletionsMenuSource::Words {
 5141                        ignore_threshold: false,
 5142                    }),
 5143                    None,
 5144                    trigger_in_words,
 5145                    window,
 5146                    cx,
 5147                );
 5148            }
 5149            _ => self.open_or_update_completions_menu(
 5150                None,
 5151                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5152                true,
 5153                window,
 5154                cx,
 5155            ),
 5156        }
 5157    }
 5158
 5159    /// If any empty selections is touching the start of its innermost containing autoclose
 5160    /// region, expand it to select the brackets.
 5161    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5162        let selections = self
 5163            .selections
 5164            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5165        let buffer = self.buffer.read(cx).read(cx);
 5166        let new_selections = self
 5167            .selections_with_autoclose_regions(selections, &buffer)
 5168            .map(|(mut selection, region)| {
 5169                if !selection.is_empty() {
 5170                    return selection;
 5171                }
 5172
 5173                if let Some(region) = region {
 5174                    let mut range = region.range.to_offset(&buffer);
 5175                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5176                        range.start -= region.pair.start.len();
 5177                        if buffer.contains_str_at(range.start, &region.pair.start)
 5178                            && buffer.contains_str_at(range.end, &region.pair.end)
 5179                        {
 5180                            range.end += region.pair.end.len();
 5181                            selection.start = range.start;
 5182                            selection.end = range.end;
 5183
 5184                            return selection;
 5185                        }
 5186                    }
 5187                }
 5188
 5189                let always_treat_brackets_as_autoclosed = buffer
 5190                    .language_settings_at(selection.start, cx)
 5191                    .always_treat_brackets_as_autoclosed;
 5192
 5193                if !always_treat_brackets_as_autoclosed {
 5194                    return selection;
 5195                }
 5196
 5197                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5198                    for (pair, enabled) in scope.brackets() {
 5199                        if !enabled || !pair.close {
 5200                            continue;
 5201                        }
 5202
 5203                        if buffer.contains_str_at(selection.start, &pair.end) {
 5204                            let pair_start_len = pair.start.len();
 5205                            if buffer.contains_str_at(
 5206                                selection.start.saturating_sub_usize(pair_start_len),
 5207                                &pair.start,
 5208                            ) {
 5209                                selection.start -= pair_start_len;
 5210                                selection.end += pair.end.len();
 5211
 5212                                return selection;
 5213                            }
 5214                        }
 5215                    }
 5216                }
 5217
 5218                selection
 5219            })
 5220            .collect();
 5221
 5222        drop(buffer);
 5223        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5224            selections.select(new_selections)
 5225        });
 5226    }
 5227
 5228    /// Iterate the given selections, and for each one, find the smallest surrounding
 5229    /// autoclose region. This uses the ordering of the selections and the autoclose
 5230    /// regions to avoid repeated comparisons.
 5231    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5232        &'a self,
 5233        selections: impl IntoIterator<Item = Selection<D>>,
 5234        buffer: &'a MultiBufferSnapshot,
 5235    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5236        let mut i = 0;
 5237        let mut regions = self.autoclose_regions.as_slice();
 5238        selections.into_iter().map(move |selection| {
 5239            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5240
 5241            let mut enclosing = None;
 5242            while let Some(pair_state) = regions.get(i) {
 5243                if pair_state.range.end.to_offset(buffer) < range.start {
 5244                    regions = &regions[i + 1..];
 5245                    i = 0;
 5246                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5247                    break;
 5248                } else {
 5249                    if pair_state.selection_id == selection.id {
 5250                        enclosing = Some(pair_state);
 5251                    }
 5252                    i += 1;
 5253                }
 5254            }
 5255
 5256            (selection, enclosing)
 5257        })
 5258    }
 5259
 5260    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5261    fn invalidate_autoclose_regions(
 5262        &mut self,
 5263        mut selections: &[Selection<Anchor>],
 5264        buffer: &MultiBufferSnapshot,
 5265    ) {
 5266        self.autoclose_regions.retain(|state| {
 5267            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5268                return false;
 5269            }
 5270
 5271            let mut i = 0;
 5272            while let Some(selection) = selections.get(i) {
 5273                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5274                    selections = &selections[1..];
 5275                    continue;
 5276                }
 5277                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5278                    break;
 5279                }
 5280                if selection.id == state.selection_id {
 5281                    return true;
 5282                } else {
 5283                    i += 1;
 5284                }
 5285            }
 5286            false
 5287        });
 5288    }
 5289
 5290    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5291        let offset = position.to_offset(buffer);
 5292        let (word_range, kind) =
 5293            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5294        if offset > word_range.start && kind == Some(CharKind::Word) {
 5295            Some(
 5296                buffer
 5297                    .text_for_range(word_range.start..offset)
 5298                    .collect::<String>(),
 5299            )
 5300        } else {
 5301            None
 5302        }
 5303    }
 5304
 5305    pub fn visible_excerpts(
 5306        &self,
 5307        cx: &mut Context<Editor>,
 5308    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5309        let Some(project) = self.project() else {
 5310            return HashMap::default();
 5311        };
 5312        let project = project.read(cx);
 5313        let multi_buffer = self.buffer().read(cx);
 5314        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5315        let multi_buffer_visible_start = self
 5316            .scroll_manager
 5317            .anchor()
 5318            .anchor
 5319            .to_point(&multi_buffer_snapshot);
 5320        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5321            multi_buffer_visible_start
 5322                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5323            Bias::Left,
 5324        );
 5325        multi_buffer_snapshot
 5326            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5327            .into_iter()
 5328            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5329            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5330                let buffer_file = project::File::from_dyn(buffer.file())?;
 5331                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5332                let worktree_entry = buffer_worktree
 5333                    .read(cx)
 5334                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5335                if worktree_entry.is_ignored {
 5336                    None
 5337                } else {
 5338                    Some((
 5339                        excerpt_id,
 5340                        (
 5341                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5342                            buffer.version().clone(),
 5343                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5344                        ),
 5345                    ))
 5346                }
 5347            })
 5348            .collect()
 5349    }
 5350
 5351    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5352        TextLayoutDetails {
 5353            text_system: window.text_system().clone(),
 5354            editor_style: self.style.clone().unwrap(),
 5355            rem_size: window.rem_size(),
 5356            scroll_anchor: self.scroll_manager.anchor(),
 5357            visible_rows: self.visible_line_count(),
 5358            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5359        }
 5360    }
 5361
 5362    fn trigger_on_type_formatting(
 5363        &self,
 5364        input: String,
 5365        window: &mut Window,
 5366        cx: &mut Context<Self>,
 5367    ) -> Option<Task<Result<()>>> {
 5368        if input.len() != 1 {
 5369            return None;
 5370        }
 5371
 5372        let project = self.project()?;
 5373        let position = self.selections.newest_anchor().head();
 5374        let (buffer, buffer_position) = self
 5375            .buffer
 5376            .read(cx)
 5377            .text_anchor_for_position(position, cx)?;
 5378
 5379        let settings = language_settings::language_settings(
 5380            buffer
 5381                .read(cx)
 5382                .language_at(buffer_position)
 5383                .map(|l| l.name()),
 5384            buffer.read(cx).file(),
 5385            cx,
 5386        );
 5387        if !settings.use_on_type_format {
 5388            return None;
 5389        }
 5390
 5391        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5392        // hence we do LSP request & edit on host side only — add formats to host's history.
 5393        let push_to_lsp_host_history = true;
 5394        // If this is not the host, append its history with new edits.
 5395        let push_to_client_history = project.read(cx).is_via_collab();
 5396
 5397        let on_type_formatting = project.update(cx, |project, cx| {
 5398            project.on_type_format(
 5399                buffer.clone(),
 5400                buffer_position,
 5401                input,
 5402                push_to_lsp_host_history,
 5403                cx,
 5404            )
 5405        });
 5406        Some(cx.spawn_in(window, async move |editor, cx| {
 5407            if let Some(transaction) = on_type_formatting.await? {
 5408                if push_to_client_history {
 5409                    buffer
 5410                        .update(cx, |buffer, _| {
 5411                            buffer.push_transaction(transaction, Instant::now());
 5412                            buffer.finalize_last_transaction();
 5413                        })
 5414                        .ok();
 5415                }
 5416                editor.update(cx, |editor, cx| {
 5417                    editor.refresh_document_highlights(cx);
 5418                })?;
 5419            }
 5420            Ok(())
 5421        }))
 5422    }
 5423
 5424    pub fn show_word_completions(
 5425        &mut self,
 5426        _: &ShowWordCompletions,
 5427        window: &mut Window,
 5428        cx: &mut Context<Self>,
 5429    ) {
 5430        self.open_or_update_completions_menu(
 5431            Some(CompletionsMenuSource::Words {
 5432                ignore_threshold: true,
 5433            }),
 5434            None,
 5435            false,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        _: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, None, false, window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<String>,
 5454        trigger_in_words: bool,
 5455        window: &mut Window,
 5456        cx: &mut Context<Self>,
 5457    ) {
 5458        if self.pending_rename.is_some() {
 5459            return;
 5460        }
 5461
 5462        let completions_source = self
 5463            .context_menu
 5464            .borrow()
 5465            .as_ref()
 5466            .and_then(|menu| match menu {
 5467                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5468                CodeContextMenu::CodeActions(_) => None,
 5469            });
 5470
 5471        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5472
 5473        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5474        // inserted and selected. To handle that case, the start of the selection is used so that
 5475        // the menu starts with all choices.
 5476        let position = self
 5477            .selections
 5478            .newest_anchor()
 5479            .start
 5480            .bias_right(&multibuffer_snapshot);
 5481        if position.diff_base_anchor.is_some() {
 5482            return;
 5483        }
 5484        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5485        let Some(buffer) = buffer_position
 5486            .text_anchor
 5487            .buffer_id
 5488            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5489        else {
 5490            return;
 5491        };
 5492        let buffer_snapshot = buffer.read(cx).snapshot();
 5493
 5494        let query: Option<Arc<String>> =
 5495            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5496                .map(|query| query.into());
 5497
 5498        drop(multibuffer_snapshot);
 5499
 5500        // Hide the current completions menu when query is empty. Without this, cached
 5501        // completions from before the trigger char may be reused (#32774).
 5502        if query.is_none() {
 5503            let menu_is_open = matches!(
 5504                self.context_menu.borrow().as_ref(),
 5505                Some(CodeContextMenu::Completions(_))
 5506            );
 5507            if menu_is_open {
 5508                self.hide_context_menu(window, cx);
 5509            }
 5510        }
 5511
 5512        let mut ignore_word_threshold = false;
 5513        let provider = match requested_source {
 5514            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5515            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5516                ignore_word_threshold = ignore_threshold;
 5517                None
 5518            }
 5519            Some(CompletionsMenuSource::SnippetChoices)
 5520            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5521                log::error!("bug: SnippetChoices requested_source is not handled");
 5522                None
 5523            }
 5524        };
 5525
 5526        let sort_completions = provider
 5527            .as_ref()
 5528            .is_some_and(|provider| provider.sort_completions());
 5529
 5530        let filter_completions = provider
 5531            .as_ref()
 5532            .is_none_or(|provider| provider.filter_completions());
 5533
 5534        let was_snippets_only = matches!(
 5535            completions_source,
 5536            Some(CompletionsMenuSource::SnippetsOnly)
 5537        );
 5538
 5539        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5540            if filter_completions {
 5541                menu.filter(
 5542                    query.clone().unwrap_or_default(),
 5543                    buffer_position.text_anchor,
 5544                    &buffer,
 5545                    provider.clone(),
 5546                    window,
 5547                    cx,
 5548                );
 5549            }
 5550            // When `is_incomplete` is false, no need to re-query completions when the current query
 5551            // is a suffix of the initial query.
 5552            let was_complete = !menu.is_incomplete;
 5553            if was_complete && !was_snippets_only {
 5554                // If the new query is a suffix of the old query (typing more characters) and
 5555                // the previous result was complete, the existing completions can be filtered.
 5556                //
 5557                // Note that snippet completions are always complete.
 5558                let query_matches = match (&menu.initial_query, &query) {
 5559                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5560                    (None, _) => true,
 5561                    _ => false,
 5562                };
 5563                if query_matches {
 5564                    let position_matches = if menu.initial_position == position {
 5565                        true
 5566                    } else {
 5567                        let snapshot = self.buffer.read(cx).read(cx);
 5568                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5569                    };
 5570                    if position_matches {
 5571                        return;
 5572                    }
 5573                }
 5574            }
 5575        };
 5576
 5577        let Anchor {
 5578            excerpt_id: buffer_excerpt_id,
 5579            text_anchor: buffer_position,
 5580            ..
 5581        } = buffer_position;
 5582
 5583        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5584            buffer_snapshot.surrounding_word(buffer_position, None)
 5585        {
 5586            let word_to_exclude = buffer_snapshot
 5587                .text_for_range(word_range.clone())
 5588                .collect::<String>();
 5589            (
 5590                buffer_snapshot.anchor_before(word_range.start)
 5591                    ..buffer_snapshot.anchor_after(buffer_position),
 5592                Some(word_to_exclude),
 5593            )
 5594        } else {
 5595            (buffer_position..buffer_position, None)
 5596        };
 5597
 5598        let language = buffer_snapshot
 5599            .language_at(buffer_position)
 5600            .map(|language| language.name());
 5601
 5602        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5603            .completions
 5604            .clone();
 5605
 5606        let show_completion_documentation = buffer_snapshot
 5607            .settings_at(buffer_position, cx)
 5608            .show_completion_documentation;
 5609
 5610        // The document can be large, so stay in reasonable bounds when searching for words,
 5611        // otherwise completion pop-up might be slow to appear.
 5612        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5613        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5614        let min_word_search = buffer_snapshot.clip_point(
 5615            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5616            Bias::Left,
 5617        );
 5618        let max_word_search = buffer_snapshot.clip_point(
 5619            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5620            Bias::Right,
 5621        );
 5622        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5623            ..buffer_snapshot.point_to_offset(max_word_search);
 5624
 5625        let skip_digits = query
 5626            .as_ref()
 5627            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5628
 5629        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5630            trigger.as_ref().is_none_or(|trigger| {
 5631                provider.is_completion_trigger(
 5632                    &buffer,
 5633                    position.text_anchor,
 5634                    trigger,
 5635                    trigger_in_words,
 5636                    completions_source.is_some(),
 5637                    cx,
 5638                )
 5639            })
 5640        });
 5641
 5642        let provider_responses = if let Some(provider) = &provider
 5643            && load_provider_completions
 5644        {
 5645            let trigger_character =
 5646                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5647            let completion_context = CompletionContext {
 5648                trigger_kind: match &trigger_character {
 5649                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5650                    None => CompletionTriggerKind::INVOKED,
 5651                },
 5652                trigger_character,
 5653            };
 5654
 5655            provider.completions(
 5656                buffer_excerpt_id,
 5657                &buffer,
 5658                buffer_position,
 5659                completion_context,
 5660                window,
 5661                cx,
 5662            )
 5663        } else {
 5664            Task::ready(Ok(Vec::new()))
 5665        };
 5666
 5667        let load_word_completions = if !self.word_completions_enabled {
 5668            false
 5669        } else if requested_source
 5670            == Some(CompletionsMenuSource::Words {
 5671                ignore_threshold: true,
 5672            })
 5673        {
 5674            true
 5675        } else {
 5676            load_provider_completions
 5677                && completion_settings.words != WordsCompletionMode::Disabled
 5678                && (ignore_word_threshold || {
 5679                    let words_min_length = completion_settings.words_min_length;
 5680                    // check whether word has at least `words_min_length` characters
 5681                    let query_chars = query.iter().flat_map(|q| q.chars());
 5682                    query_chars.take(words_min_length).count() == words_min_length
 5683                })
 5684        };
 5685
 5686        let mut words = if load_word_completions {
 5687            cx.background_spawn({
 5688                let buffer_snapshot = buffer_snapshot.clone();
 5689                async move {
 5690                    buffer_snapshot.words_in_range(WordsQuery {
 5691                        fuzzy_contents: None,
 5692                        range: word_search_range,
 5693                        skip_digits,
 5694                    })
 5695                }
 5696            })
 5697        } else {
 5698            Task::ready(BTreeMap::default())
 5699        };
 5700
 5701        let snippets = if let Some(provider) = &provider
 5702            && provider.show_snippets()
 5703            && let Some(project) = self.project()
 5704        {
 5705            let char_classifier = buffer_snapshot
 5706                .char_classifier_at(buffer_position)
 5707                .scope_context(Some(CharScopeContext::Completion));
 5708            project.update(cx, |project, cx| {
 5709                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5710            })
 5711        } else {
 5712            Task::ready(Ok(CompletionResponse {
 5713                completions: Vec::new(),
 5714                display_options: Default::default(),
 5715                is_incomplete: false,
 5716            }))
 5717        };
 5718
 5719        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5720
 5721        let id = post_inc(&mut self.next_completion_id);
 5722        let task = cx.spawn_in(window, async move |editor, cx| {
 5723            let Ok(()) = editor.update(cx, |this, _| {
 5724                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5725            }) else {
 5726                return;
 5727            };
 5728
 5729            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5730            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5731            let mut completions = Vec::new();
 5732            let mut is_incomplete = false;
 5733            let mut display_options: Option<CompletionDisplayOptions> = None;
 5734            if let Some(provider_responses) = provider_responses.await.log_err()
 5735                && !provider_responses.is_empty()
 5736            {
 5737                for response in provider_responses {
 5738                    completions.extend(response.completions);
 5739                    is_incomplete = is_incomplete || response.is_incomplete;
 5740                    match display_options.as_mut() {
 5741                        None => {
 5742                            display_options = Some(response.display_options);
 5743                        }
 5744                        Some(options) => options.merge(&response.display_options),
 5745                    }
 5746                }
 5747                if completion_settings.words == WordsCompletionMode::Fallback {
 5748                    words = Task::ready(BTreeMap::default());
 5749                }
 5750            }
 5751            let display_options = display_options.unwrap_or_default();
 5752
 5753            let mut words = words.await;
 5754            if let Some(word_to_exclude) = &word_to_exclude {
 5755                words.remove(word_to_exclude);
 5756            }
 5757            for lsp_completion in &completions {
 5758                words.remove(&lsp_completion.new_text);
 5759            }
 5760            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5761                replace_range: word_replace_range.clone(),
 5762                new_text: word.clone(),
 5763                label: CodeLabel::plain(word, None),
 5764                match_start: None,
 5765                snippet_deduplication_key: None,
 5766                icon_path: None,
 5767                documentation: None,
 5768                source: CompletionSource::BufferWord {
 5769                    word_range,
 5770                    resolved: false,
 5771                },
 5772                insert_text_mode: Some(InsertTextMode::AS_IS),
 5773                confirm: None,
 5774            }));
 5775
 5776            completions.extend(
 5777                snippets
 5778                    .await
 5779                    .into_iter()
 5780                    .flat_map(|response| response.completions),
 5781            );
 5782
 5783            let menu = if completions.is_empty() {
 5784                None
 5785            } else {
 5786                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5787                    let languages = editor
 5788                        .workspace
 5789                        .as_ref()
 5790                        .and_then(|(workspace, _)| workspace.upgrade())
 5791                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5792                    let menu = CompletionsMenu::new(
 5793                        id,
 5794                        requested_source.unwrap_or(if load_provider_completions {
 5795                            CompletionsMenuSource::Normal
 5796                        } else {
 5797                            CompletionsMenuSource::SnippetsOnly
 5798                        }),
 5799                        sort_completions,
 5800                        show_completion_documentation,
 5801                        position,
 5802                        query.clone(),
 5803                        is_incomplete,
 5804                        buffer.clone(),
 5805                        completions.into(),
 5806                        display_options,
 5807                        snippet_sort_order,
 5808                        languages,
 5809                        language,
 5810                        cx,
 5811                    );
 5812
 5813                    let query = if filter_completions { query } else { None };
 5814                    let matches_task = menu.do_async_filtering(
 5815                        query.unwrap_or_default(),
 5816                        buffer_position,
 5817                        &buffer,
 5818                        cx,
 5819                    );
 5820                    (menu, matches_task)
 5821                }) else {
 5822                    return;
 5823                };
 5824
 5825                let matches = matches_task.await;
 5826
 5827                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5828                    // Newer menu already set, so exit.
 5829                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5830                        editor.context_menu.borrow().as_ref()
 5831                        && prev_menu.id > id
 5832                    {
 5833                        return;
 5834                    };
 5835
 5836                    // Only valid to take prev_menu because either the new menu is immediately set
 5837                    // below, or the menu is hidden.
 5838                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5839                        editor.context_menu.borrow_mut().take()
 5840                    {
 5841                        let position_matches =
 5842                            if prev_menu.initial_position == menu.initial_position {
 5843                                true
 5844                            } else {
 5845                                let snapshot = editor.buffer.read(cx).read(cx);
 5846                                prev_menu.initial_position.to_offset(&snapshot)
 5847                                    == menu.initial_position.to_offset(&snapshot)
 5848                            };
 5849                        if position_matches {
 5850                            // Preserve markdown cache before `set_filter_results` because it will
 5851                            // try to populate the documentation cache.
 5852                            menu.preserve_markdown_cache(prev_menu);
 5853                        }
 5854                    };
 5855
 5856                    menu.set_filter_results(matches, provider, window, cx);
 5857                }) else {
 5858                    return;
 5859                };
 5860
 5861                menu.visible().then_some(menu)
 5862            };
 5863
 5864            editor
 5865                .update_in(cx, |editor, window, cx| {
 5866                    if editor.focus_handle.is_focused(window)
 5867                        && let Some(menu) = menu
 5868                    {
 5869                        *editor.context_menu.borrow_mut() =
 5870                            Some(CodeContextMenu::Completions(menu));
 5871
 5872                        crate::hover_popover::hide_hover(editor, cx);
 5873                        if editor.show_edit_predictions_in_menu() {
 5874                            editor.update_visible_edit_prediction(window, cx);
 5875                        } else {
 5876                            editor.discard_edit_prediction(false, cx);
 5877                        }
 5878
 5879                        cx.notify();
 5880                        return;
 5881                    }
 5882
 5883                    if editor.completion_tasks.len() <= 1 {
 5884                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5885                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5886                        // If it was already hidden and we don't show edit predictions in the menu,
 5887                        // we should also show the edit prediction when available.
 5888                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5889                            editor.update_visible_edit_prediction(window, cx);
 5890                        }
 5891                    }
 5892                })
 5893                .ok();
 5894        });
 5895
 5896        self.completion_tasks.push((id, task));
 5897    }
 5898
 5899    #[cfg(feature = "test-support")]
 5900    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5901        let menu = self.context_menu.borrow();
 5902        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5903            let completions = menu.completions.borrow();
 5904            Some(completions.to_vec())
 5905        } else {
 5906            None
 5907        }
 5908    }
 5909
 5910    pub fn with_completions_menu_matching_id<R>(
 5911        &self,
 5912        id: CompletionId,
 5913        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5914    ) -> R {
 5915        let mut context_menu = self.context_menu.borrow_mut();
 5916        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5917            return f(None);
 5918        };
 5919        if completions_menu.id != id {
 5920            return f(None);
 5921        }
 5922        f(Some(completions_menu))
 5923    }
 5924
 5925    pub fn confirm_completion(
 5926        &mut self,
 5927        action: &ConfirmCompletion,
 5928        window: &mut Window,
 5929        cx: &mut Context<Self>,
 5930    ) -> Option<Task<Result<()>>> {
 5931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5932        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5933    }
 5934
 5935    pub fn confirm_completion_insert(
 5936        &mut self,
 5937        _: &ConfirmCompletionInsert,
 5938        window: &mut Window,
 5939        cx: &mut Context<Self>,
 5940    ) -> Option<Task<Result<()>>> {
 5941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5942        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5943    }
 5944
 5945    pub fn confirm_completion_replace(
 5946        &mut self,
 5947        _: &ConfirmCompletionReplace,
 5948        window: &mut Window,
 5949        cx: &mut Context<Self>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5952        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5953    }
 5954
 5955    pub fn compose_completion(
 5956        &mut self,
 5957        action: &ComposeCompletion,
 5958        window: &mut Window,
 5959        cx: &mut Context<Self>,
 5960    ) -> Option<Task<Result<()>>> {
 5961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5962        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5963    }
 5964
 5965    fn do_completion(
 5966        &mut self,
 5967        item_ix: Option<usize>,
 5968        intent: CompletionIntent,
 5969        window: &mut Window,
 5970        cx: &mut Context<Editor>,
 5971    ) -> Option<Task<Result<()>>> {
 5972        use language::ToOffset as _;
 5973
 5974        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5975        else {
 5976            return None;
 5977        };
 5978
 5979        let candidate_id = {
 5980            let entries = completions_menu.entries.borrow();
 5981            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5982            if self.show_edit_predictions_in_menu() {
 5983                self.discard_edit_prediction(true, cx);
 5984            }
 5985            mat.candidate_id
 5986        };
 5987
 5988        let completion = completions_menu
 5989            .completions
 5990            .borrow()
 5991            .get(candidate_id)?
 5992            .clone();
 5993        cx.stop_propagation();
 5994
 5995        let buffer_handle = completions_menu.buffer.clone();
 5996
 5997        let CompletionEdit {
 5998            new_text,
 5999            snippet,
 6000            replace_range,
 6001        } = process_completion_for_edit(
 6002            &completion,
 6003            intent,
 6004            &buffer_handle,
 6005            &completions_menu.initial_position.text_anchor,
 6006            cx,
 6007        );
 6008
 6009        let buffer = buffer_handle.read(cx);
 6010        let snapshot = self.buffer.read(cx).snapshot(cx);
 6011        let newest_anchor = self.selections.newest_anchor();
 6012        let replace_range_multibuffer = {
 6013            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6014            excerpt.map_range_from_buffer(replace_range.clone())
 6015        };
 6016        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6017            return None;
 6018        }
 6019
 6020        let old_text = buffer
 6021            .text_for_range(replace_range.clone())
 6022            .collect::<String>();
 6023        let lookbehind = newest_anchor
 6024            .start
 6025            .text_anchor
 6026            .to_offset(buffer)
 6027            .saturating_sub(replace_range.start.0);
 6028        let lookahead = replace_range
 6029            .end
 6030            .0
 6031            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6032        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6033        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6034
 6035        let selections = self
 6036            .selections
 6037            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6038        let mut ranges = Vec::new();
 6039        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6040
 6041        for selection in &selections {
 6042            let range = if selection.id == newest_anchor.id {
 6043                replace_range_multibuffer.clone()
 6044            } else {
 6045                let mut range = selection.range();
 6046
 6047                // if prefix is present, don't duplicate it
 6048                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6049                    range.start = range.start.saturating_sub_usize(lookbehind);
 6050
 6051                    // if suffix is also present, mimic the newest cursor and replace it
 6052                    if selection.id != newest_anchor.id
 6053                        && snapshot.contains_str_at(range.end, suffix)
 6054                    {
 6055                        range.end += lookahead;
 6056                    }
 6057                }
 6058                range
 6059            };
 6060
 6061            ranges.push(range.clone());
 6062
 6063            if !self.linked_edit_ranges.is_empty() {
 6064                let start_anchor = snapshot.anchor_before(range.start);
 6065                let end_anchor = snapshot.anchor_after(range.end);
 6066                if let Some(ranges) = self
 6067                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6068                {
 6069                    for (buffer, edits) in ranges {
 6070                        linked_edits
 6071                            .entry(buffer.clone())
 6072                            .or_default()
 6073                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6074                    }
 6075                }
 6076            }
 6077        }
 6078
 6079        let common_prefix_len = old_text
 6080            .chars()
 6081            .zip(new_text.chars())
 6082            .take_while(|(a, b)| a == b)
 6083            .map(|(a, _)| a.len_utf8())
 6084            .sum::<usize>();
 6085
 6086        cx.emit(EditorEvent::InputHandled {
 6087            utf16_range_to_replace: None,
 6088            text: new_text[common_prefix_len..].into(),
 6089        });
 6090
 6091        self.transact(window, cx, |editor, window, cx| {
 6092            if let Some(mut snippet) = snippet {
 6093                snippet.text = new_text.to_string();
 6094                editor
 6095                    .insert_snippet(&ranges, snippet, window, cx)
 6096                    .log_err();
 6097            } else {
 6098                editor.buffer.update(cx, |multi_buffer, cx| {
 6099                    let auto_indent = match completion.insert_text_mode {
 6100                        Some(InsertTextMode::AS_IS) => None,
 6101                        _ => editor.autoindent_mode.clone(),
 6102                    };
 6103                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6104                    multi_buffer.edit(edits, auto_indent, cx);
 6105                });
 6106            }
 6107            for (buffer, edits) in linked_edits {
 6108                buffer.update(cx, |buffer, cx| {
 6109                    let snapshot = buffer.snapshot();
 6110                    let edits = edits
 6111                        .into_iter()
 6112                        .map(|(range, text)| {
 6113                            use text::ToPoint as TP;
 6114                            let end_point = TP::to_point(&range.end, &snapshot);
 6115                            let start_point = TP::to_point(&range.start, &snapshot);
 6116                            (start_point..end_point, text)
 6117                        })
 6118                        .sorted_by_key(|(range, _)| range.start);
 6119                    buffer.edit(edits, None, cx);
 6120                })
 6121            }
 6122
 6123            editor.refresh_edit_prediction(true, false, window, cx);
 6124        });
 6125        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6126
 6127        let show_new_completions_on_confirm = completion
 6128            .confirm
 6129            .as_ref()
 6130            .is_some_and(|confirm| confirm(intent, window, cx));
 6131        if show_new_completions_on_confirm {
 6132            self.open_or_update_completions_menu(None, None, false, window, cx);
 6133        }
 6134
 6135        let provider = self.completion_provider.as_ref()?;
 6136        drop(completion);
 6137        let apply_edits = provider.apply_additional_edits_for_completion(
 6138            buffer_handle,
 6139            completions_menu.completions.clone(),
 6140            candidate_id,
 6141            true,
 6142            cx,
 6143        );
 6144
 6145        let editor_settings = EditorSettings::get_global(cx);
 6146        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6147            // After the code completion is finished, users often want to know what signatures are needed.
 6148            // so we should automatically call signature_help
 6149            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6150        }
 6151
 6152        Some(cx.foreground_executor().spawn(async move {
 6153            apply_edits.await?;
 6154            Ok(())
 6155        }))
 6156    }
 6157
 6158    pub fn toggle_code_actions(
 6159        &mut self,
 6160        action: &ToggleCodeActions,
 6161        window: &mut Window,
 6162        cx: &mut Context<Self>,
 6163    ) {
 6164        let quick_launch = action.quick_launch;
 6165        let mut context_menu = self.context_menu.borrow_mut();
 6166        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6167            if code_actions.deployed_from == action.deployed_from {
 6168                // Toggle if we're selecting the same one
 6169                *context_menu = None;
 6170                cx.notify();
 6171                return;
 6172            } else {
 6173                // Otherwise, clear it and start a new one
 6174                *context_menu = None;
 6175                cx.notify();
 6176            }
 6177        }
 6178        drop(context_menu);
 6179        let snapshot = self.snapshot(window, cx);
 6180        let deployed_from = action.deployed_from.clone();
 6181        let action = action.clone();
 6182        self.completion_tasks.clear();
 6183        self.discard_edit_prediction(false, cx);
 6184
 6185        let multibuffer_point = match &action.deployed_from {
 6186            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6187                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6188            }
 6189            _ => self
 6190                .selections
 6191                .newest::<Point>(&snapshot.display_snapshot)
 6192                .head(),
 6193        };
 6194        let Some((buffer, buffer_row)) = snapshot
 6195            .buffer_snapshot()
 6196            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6197            .and_then(|(buffer_snapshot, range)| {
 6198                self.buffer()
 6199                    .read(cx)
 6200                    .buffer(buffer_snapshot.remote_id())
 6201                    .map(|buffer| (buffer, range.start.row))
 6202            })
 6203        else {
 6204            return;
 6205        };
 6206        let buffer_id = buffer.read(cx).remote_id();
 6207        let tasks = self
 6208            .tasks
 6209            .get(&(buffer_id, buffer_row))
 6210            .map(|t| Arc::new(t.to_owned()));
 6211
 6212        if !self.focus_handle.is_focused(window) {
 6213            return;
 6214        }
 6215        let project = self.project.clone();
 6216
 6217        let code_actions_task = match deployed_from {
 6218            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6219            _ => self.code_actions(buffer_row, window, cx),
 6220        };
 6221
 6222        let runnable_task = match deployed_from {
 6223            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6224            _ => {
 6225                let mut task_context_task = Task::ready(None);
 6226                if let Some(tasks) = &tasks
 6227                    && let Some(project) = project
 6228                {
 6229                    task_context_task =
 6230                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6231                }
 6232
 6233                cx.spawn_in(window, {
 6234                    let buffer = buffer.clone();
 6235                    async move |editor, cx| {
 6236                        let task_context = task_context_task.await;
 6237
 6238                        let resolved_tasks =
 6239                            tasks
 6240                                .zip(task_context.clone())
 6241                                .map(|(tasks, task_context)| ResolvedTasks {
 6242                                    templates: tasks.resolve(&task_context).collect(),
 6243                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6244                                        multibuffer_point.row,
 6245                                        tasks.column,
 6246                                    )),
 6247                                });
 6248                        let debug_scenarios = editor
 6249                            .update(cx, |editor, cx| {
 6250                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6251                            })?
 6252                            .await;
 6253                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6254                    }
 6255                })
 6256            }
 6257        };
 6258
 6259        cx.spawn_in(window, async move |editor, cx| {
 6260            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6261            let code_actions = code_actions_task.await;
 6262            let spawn_straight_away = quick_launch
 6263                && resolved_tasks
 6264                    .as_ref()
 6265                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6266                && code_actions
 6267                    .as_ref()
 6268                    .is_none_or(|actions| actions.is_empty())
 6269                && debug_scenarios.is_empty();
 6270
 6271            editor.update_in(cx, |editor, window, cx| {
 6272                crate::hover_popover::hide_hover(editor, cx);
 6273                let actions = CodeActionContents::new(
 6274                    resolved_tasks,
 6275                    code_actions,
 6276                    debug_scenarios,
 6277                    task_context.unwrap_or_default(),
 6278                );
 6279
 6280                // Don't show the menu if there are no actions available
 6281                if actions.is_empty() {
 6282                    cx.notify();
 6283                    return Task::ready(Ok(()));
 6284                }
 6285
 6286                *editor.context_menu.borrow_mut() =
 6287                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6288                        buffer,
 6289                        actions,
 6290                        selected_item: Default::default(),
 6291                        scroll_handle: UniformListScrollHandle::default(),
 6292                        deployed_from,
 6293                    }));
 6294                cx.notify();
 6295                if spawn_straight_away
 6296                    && let Some(task) = editor.confirm_code_action(
 6297                        &ConfirmCodeAction { item_ix: Some(0) },
 6298                        window,
 6299                        cx,
 6300                    )
 6301                {
 6302                    return task;
 6303                }
 6304
 6305                Task::ready(Ok(()))
 6306            })
 6307        })
 6308        .detach_and_log_err(cx);
 6309    }
 6310
 6311    fn debug_scenarios(
 6312        &mut self,
 6313        resolved_tasks: &Option<ResolvedTasks>,
 6314        buffer: &Entity<Buffer>,
 6315        cx: &mut App,
 6316    ) -> Task<Vec<task::DebugScenario>> {
 6317        maybe!({
 6318            let project = self.project()?;
 6319            let dap_store = project.read(cx).dap_store();
 6320            let mut scenarios = vec![];
 6321            let resolved_tasks = resolved_tasks.as_ref()?;
 6322            let buffer = buffer.read(cx);
 6323            let language = buffer.language()?;
 6324            let file = buffer.file();
 6325            let debug_adapter = language_settings(language.name().into(), file, cx)
 6326                .debuggers
 6327                .first()
 6328                .map(SharedString::from)
 6329                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6330
 6331            dap_store.update(cx, |dap_store, cx| {
 6332                for (_, task) in &resolved_tasks.templates {
 6333                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6334                        task.original_task().clone(),
 6335                        debug_adapter.clone().into(),
 6336                        task.display_label().to_owned().into(),
 6337                        cx,
 6338                    );
 6339                    scenarios.push(maybe_scenario);
 6340                }
 6341            });
 6342            Some(cx.background_spawn(async move {
 6343                futures::future::join_all(scenarios)
 6344                    .await
 6345                    .into_iter()
 6346                    .flatten()
 6347                    .collect::<Vec<_>>()
 6348            }))
 6349        })
 6350        .unwrap_or_else(|| Task::ready(vec![]))
 6351    }
 6352
 6353    fn code_actions(
 6354        &mut self,
 6355        buffer_row: u32,
 6356        window: &mut Window,
 6357        cx: &mut Context<Self>,
 6358    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6359        let mut task = self.code_actions_task.take();
 6360        cx.spawn_in(window, async move |editor, cx| {
 6361            while let Some(prev_task) = task {
 6362                prev_task.await.log_err();
 6363                task = editor
 6364                    .update(cx, |this, _| this.code_actions_task.take())
 6365                    .ok()?;
 6366            }
 6367
 6368            editor
 6369                .update(cx, |editor, cx| {
 6370                    editor
 6371                        .available_code_actions
 6372                        .clone()
 6373                        .and_then(|(location, code_actions)| {
 6374                            let snapshot = location.buffer.read(cx).snapshot();
 6375                            let point_range = location.range.to_point(&snapshot);
 6376                            let point_range = point_range.start.row..=point_range.end.row;
 6377                            if point_range.contains(&buffer_row) {
 6378                                Some(code_actions)
 6379                            } else {
 6380                                None
 6381                            }
 6382                        })
 6383                })
 6384                .ok()
 6385                .flatten()
 6386        })
 6387    }
 6388
 6389    pub fn confirm_code_action(
 6390        &mut self,
 6391        action: &ConfirmCodeAction,
 6392        window: &mut Window,
 6393        cx: &mut Context<Self>,
 6394    ) -> Option<Task<Result<()>>> {
 6395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6396
 6397        let actions_menu =
 6398            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6399                menu
 6400            } else {
 6401                return None;
 6402            };
 6403
 6404        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6405        let action = actions_menu.actions.get(action_ix)?;
 6406        let title = action.label();
 6407        let buffer = actions_menu.buffer;
 6408        let workspace = self.workspace()?;
 6409
 6410        match action {
 6411            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6412                workspace.update(cx, |workspace, cx| {
 6413                    workspace.schedule_resolved_task(
 6414                        task_source_kind,
 6415                        resolved_task,
 6416                        false,
 6417                        window,
 6418                        cx,
 6419                    );
 6420
 6421                    Some(Task::ready(Ok(())))
 6422                })
 6423            }
 6424            CodeActionsItem::CodeAction {
 6425                excerpt_id,
 6426                action,
 6427                provider,
 6428            } => {
 6429                let apply_code_action =
 6430                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6431                let workspace = workspace.downgrade();
 6432                Some(cx.spawn_in(window, async move |editor, cx| {
 6433                    let project_transaction = apply_code_action.await?;
 6434                    Self::open_project_transaction(
 6435                        &editor,
 6436                        workspace,
 6437                        project_transaction,
 6438                        title,
 6439                        cx,
 6440                    )
 6441                    .await
 6442                }))
 6443            }
 6444            CodeActionsItem::DebugScenario(scenario) => {
 6445                let context = actions_menu.actions.context;
 6446
 6447                workspace.update(cx, |workspace, cx| {
 6448                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6449                    workspace.start_debug_session(
 6450                        scenario,
 6451                        context,
 6452                        Some(buffer),
 6453                        None,
 6454                        window,
 6455                        cx,
 6456                    );
 6457                });
 6458                Some(Task::ready(Ok(())))
 6459            }
 6460        }
 6461    }
 6462
 6463    pub async fn open_project_transaction(
 6464        editor: &WeakEntity<Editor>,
 6465        workspace: WeakEntity<Workspace>,
 6466        transaction: ProjectTransaction,
 6467        title: String,
 6468        cx: &mut AsyncWindowContext,
 6469    ) -> Result<()> {
 6470        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6471        cx.update(|_, cx| {
 6472            entries.sort_unstable_by_key(|(buffer, _)| {
 6473                buffer.read(cx).file().map(|f| f.path().clone())
 6474            });
 6475        })?;
 6476        if entries.is_empty() {
 6477            return Ok(());
 6478        }
 6479
 6480        // If the project transaction's edits are all contained within this editor, then
 6481        // avoid opening a new editor to display them.
 6482
 6483        if let [(buffer, transaction)] = &*entries {
 6484            let excerpt = editor.update(cx, |editor, cx| {
 6485                editor
 6486                    .buffer()
 6487                    .read(cx)
 6488                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6489            })?;
 6490            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6491                && excerpted_buffer == *buffer
 6492            {
 6493                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6494                    let excerpt_range = excerpt_range.to_offset(buffer);
 6495                    buffer
 6496                        .edited_ranges_for_transaction::<usize>(transaction)
 6497                        .all(|range| {
 6498                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6499                        })
 6500                })?;
 6501
 6502                if all_edits_within_excerpt {
 6503                    return Ok(());
 6504                }
 6505            }
 6506        }
 6507
 6508        let mut ranges_to_highlight = Vec::new();
 6509        let excerpt_buffer = cx.new(|cx| {
 6510            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6511            for (buffer_handle, transaction) in &entries {
 6512                let edited_ranges = buffer_handle
 6513                    .read(cx)
 6514                    .edited_ranges_for_transaction::<Point>(transaction)
 6515                    .collect::<Vec<_>>();
 6516                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6517                    PathKey::for_buffer(buffer_handle, cx),
 6518                    buffer_handle.clone(),
 6519                    edited_ranges,
 6520                    multibuffer_context_lines(cx),
 6521                    cx,
 6522                );
 6523
 6524                ranges_to_highlight.extend(ranges);
 6525            }
 6526            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6527            multibuffer
 6528        })?;
 6529
 6530        workspace.update_in(cx, |workspace, window, cx| {
 6531            let project = workspace.project().clone();
 6532            let editor =
 6533                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6534            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6535            editor.update(cx, |editor, cx| {
 6536                editor.highlight_background::<Self>(
 6537                    &ranges_to_highlight,
 6538                    |theme| theme.colors().editor_highlighted_line_background,
 6539                    cx,
 6540                );
 6541            });
 6542        })?;
 6543
 6544        Ok(())
 6545    }
 6546
 6547    pub fn clear_code_action_providers(&mut self) {
 6548        self.code_action_providers.clear();
 6549        self.available_code_actions.take();
 6550    }
 6551
 6552    pub fn add_code_action_provider(
 6553        &mut self,
 6554        provider: Rc<dyn CodeActionProvider>,
 6555        window: &mut Window,
 6556        cx: &mut Context<Self>,
 6557    ) {
 6558        if self
 6559            .code_action_providers
 6560            .iter()
 6561            .any(|existing_provider| existing_provider.id() == provider.id())
 6562        {
 6563            return;
 6564        }
 6565
 6566        self.code_action_providers.push(provider);
 6567        self.refresh_code_actions(window, cx);
 6568    }
 6569
 6570    pub fn remove_code_action_provider(
 6571        &mut self,
 6572        id: Arc<str>,
 6573        window: &mut Window,
 6574        cx: &mut Context<Self>,
 6575    ) {
 6576        self.code_action_providers
 6577            .retain(|provider| provider.id() != id);
 6578        self.refresh_code_actions(window, cx);
 6579    }
 6580
 6581    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6582        !self.code_action_providers.is_empty()
 6583            && EditorSettings::get_global(cx).toolbar.code_actions
 6584    }
 6585
 6586    pub fn has_available_code_actions(&self) -> bool {
 6587        self.available_code_actions
 6588            .as_ref()
 6589            .is_some_and(|(_, actions)| !actions.is_empty())
 6590    }
 6591
 6592    fn render_inline_code_actions(
 6593        &self,
 6594        icon_size: ui::IconSize,
 6595        display_row: DisplayRow,
 6596        is_active: bool,
 6597        cx: &mut Context<Self>,
 6598    ) -> AnyElement {
 6599        let show_tooltip = !self.context_menu_visible();
 6600        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6601            .icon_size(icon_size)
 6602            .shape(ui::IconButtonShape::Square)
 6603            .icon_color(ui::Color::Hidden)
 6604            .toggle_state(is_active)
 6605            .when(show_tooltip, |this| {
 6606                this.tooltip({
 6607                    let focus_handle = self.focus_handle.clone();
 6608                    move |_window, cx| {
 6609                        Tooltip::for_action_in(
 6610                            "Toggle Code Actions",
 6611                            &ToggleCodeActions {
 6612                                deployed_from: None,
 6613                                quick_launch: false,
 6614                            },
 6615                            &focus_handle,
 6616                            cx,
 6617                        )
 6618                    }
 6619                })
 6620            })
 6621            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6622                window.focus(&editor.focus_handle(cx));
 6623                editor.toggle_code_actions(
 6624                    &crate::actions::ToggleCodeActions {
 6625                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6626                            display_row,
 6627                        )),
 6628                        quick_launch: false,
 6629                    },
 6630                    window,
 6631                    cx,
 6632                );
 6633            }))
 6634            .into_any_element()
 6635    }
 6636
 6637    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6638        &self.context_menu
 6639    }
 6640
 6641    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6642        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6643            cx.background_executor()
 6644                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6645                .await;
 6646
 6647            let (start_buffer, start, _, end, newest_selection) = this
 6648                .update(cx, |this, cx| {
 6649                    let newest_selection = this.selections.newest_anchor().clone();
 6650                    if newest_selection.head().diff_base_anchor.is_some() {
 6651                        return None;
 6652                    }
 6653                    let display_snapshot = this.display_snapshot(cx);
 6654                    let newest_selection_adjusted =
 6655                        this.selections.newest_adjusted(&display_snapshot);
 6656                    let buffer = this.buffer.read(cx);
 6657
 6658                    let (start_buffer, start) =
 6659                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6660                    let (end_buffer, end) =
 6661                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6662
 6663                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6664                })?
 6665                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6666                .context(
 6667                    "Expected selection to lie in a single buffer when refreshing code actions",
 6668                )?;
 6669            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6670                let providers = this.code_action_providers.clone();
 6671                let tasks = this
 6672                    .code_action_providers
 6673                    .iter()
 6674                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6675                    .collect::<Vec<_>>();
 6676                (providers, tasks)
 6677            })?;
 6678
 6679            let mut actions = Vec::new();
 6680            for (provider, provider_actions) in
 6681                providers.into_iter().zip(future::join_all(tasks).await)
 6682            {
 6683                if let Some(provider_actions) = provider_actions.log_err() {
 6684                    actions.extend(provider_actions.into_iter().map(|action| {
 6685                        AvailableCodeAction {
 6686                            excerpt_id: newest_selection.start.excerpt_id,
 6687                            action,
 6688                            provider: provider.clone(),
 6689                        }
 6690                    }));
 6691                }
 6692            }
 6693
 6694            this.update(cx, |this, cx| {
 6695                this.available_code_actions = if actions.is_empty() {
 6696                    None
 6697                } else {
 6698                    Some((
 6699                        Location {
 6700                            buffer: start_buffer,
 6701                            range: start..end,
 6702                        },
 6703                        actions.into(),
 6704                    ))
 6705                };
 6706                cx.notify();
 6707            })
 6708        }));
 6709    }
 6710
 6711    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6712        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6713            self.show_git_blame_inline = false;
 6714
 6715            self.show_git_blame_inline_delay_task =
 6716                Some(cx.spawn_in(window, async move |this, cx| {
 6717                    cx.background_executor().timer(delay).await;
 6718
 6719                    this.update(cx, |this, cx| {
 6720                        this.show_git_blame_inline = true;
 6721                        cx.notify();
 6722                    })
 6723                    .log_err();
 6724                }));
 6725        }
 6726    }
 6727
 6728    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6729        let snapshot = self.snapshot(window, cx);
 6730        let cursor = self
 6731            .selections
 6732            .newest::<Point>(&snapshot.display_snapshot)
 6733            .head();
 6734        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6735        else {
 6736            return;
 6737        };
 6738
 6739        let Some(blame) = self.blame.as_ref() else {
 6740            return;
 6741        };
 6742
 6743        let row_info = RowInfo {
 6744            buffer_id: Some(buffer.remote_id()),
 6745            buffer_row: Some(point.row),
 6746            ..Default::default()
 6747        };
 6748        let Some((buffer, blame_entry)) = blame
 6749            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6750            .flatten()
 6751        else {
 6752            return;
 6753        };
 6754
 6755        let anchor = self.selections.newest_anchor().head();
 6756        let position = self.to_pixel_point(anchor, &snapshot, window);
 6757        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6758            self.show_blame_popover(
 6759                buffer,
 6760                &blame_entry,
 6761                position + last_bounds.origin,
 6762                true,
 6763                cx,
 6764            );
 6765        };
 6766    }
 6767
 6768    fn show_blame_popover(
 6769        &mut self,
 6770        buffer: BufferId,
 6771        blame_entry: &BlameEntry,
 6772        position: gpui::Point<Pixels>,
 6773        ignore_timeout: bool,
 6774        cx: &mut Context<Self>,
 6775    ) {
 6776        if let Some(state) = &mut self.inline_blame_popover {
 6777            state.hide_task.take();
 6778        } else {
 6779            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6780            let blame_entry = blame_entry.clone();
 6781            let show_task = cx.spawn(async move |editor, cx| {
 6782                if !ignore_timeout {
 6783                    cx.background_executor()
 6784                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6785                        .await;
 6786                }
 6787                editor
 6788                    .update(cx, |editor, cx| {
 6789                        editor.inline_blame_popover_show_task.take();
 6790                        let Some(blame) = editor.blame.as_ref() else {
 6791                            return;
 6792                        };
 6793                        let blame = blame.read(cx);
 6794                        let details = blame.details_for_entry(buffer, &blame_entry);
 6795                        let markdown = cx.new(|cx| {
 6796                            Markdown::new(
 6797                                details
 6798                                    .as_ref()
 6799                                    .map(|message| message.message.clone())
 6800                                    .unwrap_or_default(),
 6801                                None,
 6802                                None,
 6803                                cx,
 6804                            )
 6805                        });
 6806                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6807                            position,
 6808                            hide_task: None,
 6809                            popover_bounds: None,
 6810                            popover_state: InlineBlamePopoverState {
 6811                                scroll_handle: ScrollHandle::new(),
 6812                                commit_message: details,
 6813                                markdown,
 6814                            },
 6815                            keyboard_grace: ignore_timeout,
 6816                        });
 6817                        cx.notify();
 6818                    })
 6819                    .ok();
 6820            });
 6821            self.inline_blame_popover_show_task = Some(show_task);
 6822        }
 6823    }
 6824
 6825    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6826        self.inline_blame_popover_show_task.take();
 6827        if let Some(state) = &mut self.inline_blame_popover {
 6828            let hide_task = cx.spawn(async move |editor, cx| {
 6829                if !ignore_timeout {
 6830                    cx.background_executor()
 6831                        .timer(std::time::Duration::from_millis(100))
 6832                        .await;
 6833                }
 6834                editor
 6835                    .update(cx, |editor, cx| {
 6836                        editor.inline_blame_popover.take();
 6837                        cx.notify();
 6838                    })
 6839                    .ok();
 6840            });
 6841            state.hide_task = Some(hide_task);
 6842            true
 6843        } else {
 6844            false
 6845        }
 6846    }
 6847
 6848    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6849        if self.pending_rename.is_some() {
 6850            return None;
 6851        }
 6852
 6853        let provider = self.semantics_provider.clone()?;
 6854        let buffer = self.buffer.read(cx);
 6855        let newest_selection = self.selections.newest_anchor().clone();
 6856        let cursor_position = newest_selection.head();
 6857        let (cursor_buffer, cursor_buffer_position) =
 6858            buffer.text_anchor_for_position(cursor_position, cx)?;
 6859        let (tail_buffer, tail_buffer_position) =
 6860            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6861        if cursor_buffer != tail_buffer {
 6862            return None;
 6863        }
 6864
 6865        let snapshot = cursor_buffer.read(cx).snapshot();
 6866        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6867        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6868        if start_word_range != end_word_range {
 6869            self.document_highlights_task.take();
 6870            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6871            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6872            return None;
 6873        }
 6874
 6875        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6876        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6877            cx.background_executor()
 6878                .timer(Duration::from_millis(debounce))
 6879                .await;
 6880
 6881            let highlights = if let Some(highlights) = cx
 6882                .update(|cx| {
 6883                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6884                })
 6885                .ok()
 6886                .flatten()
 6887            {
 6888                highlights.await.log_err()
 6889            } else {
 6890                None
 6891            };
 6892
 6893            if let Some(highlights) = highlights {
 6894                this.update(cx, |this, cx| {
 6895                    if this.pending_rename.is_some() {
 6896                        return;
 6897                    }
 6898
 6899                    let buffer = this.buffer.read(cx);
 6900                    if buffer
 6901                        .text_anchor_for_position(cursor_position, cx)
 6902                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6903                    {
 6904                        return;
 6905                    }
 6906
 6907                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6908                    let mut write_ranges = Vec::new();
 6909                    let mut read_ranges = Vec::new();
 6910                    for highlight in highlights {
 6911                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6912                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6913                        {
 6914                            let start = highlight
 6915                                .range
 6916                                .start
 6917                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6918                            let end = highlight
 6919                                .range
 6920                                .end
 6921                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6922                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6923                                continue;
 6924                            }
 6925
 6926                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6927                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6928                                write_ranges.push(range);
 6929                            } else {
 6930                                read_ranges.push(range);
 6931                            }
 6932                        }
 6933                    }
 6934
 6935                    this.highlight_background::<DocumentHighlightRead>(
 6936                        &read_ranges,
 6937                        |theme| theme.colors().editor_document_highlight_read_background,
 6938                        cx,
 6939                    );
 6940                    this.highlight_background::<DocumentHighlightWrite>(
 6941                        &write_ranges,
 6942                        |theme| theme.colors().editor_document_highlight_write_background,
 6943                        cx,
 6944                    );
 6945                    cx.notify();
 6946                })
 6947                .log_err();
 6948            }
 6949        }));
 6950        None
 6951    }
 6952
 6953    fn prepare_highlight_query_from_selection(
 6954        &mut self,
 6955        window: &Window,
 6956        cx: &mut Context<Editor>,
 6957    ) -> Option<(String, Range<Anchor>)> {
 6958        if matches!(self.mode, EditorMode::SingleLine) {
 6959            return None;
 6960        }
 6961        if !EditorSettings::get_global(cx).selection_highlight {
 6962            return None;
 6963        }
 6964        if self.selections.count() != 1 || self.selections.line_mode() {
 6965            return None;
 6966        }
 6967        let snapshot = self.snapshot(window, cx);
 6968        let selection = self.selections.newest::<Point>(&snapshot);
 6969        // If the selection spans multiple rows OR it is empty
 6970        if selection.start.row != selection.end.row
 6971            || selection.start.column == selection.end.column
 6972        {
 6973            return None;
 6974        }
 6975        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6976        let query = snapshot
 6977            .buffer_snapshot()
 6978            .text_for_range(selection_anchor_range.clone())
 6979            .collect::<String>();
 6980        if query.trim().is_empty() {
 6981            return None;
 6982        }
 6983        Some((query, selection_anchor_range))
 6984    }
 6985
 6986    fn update_selection_occurrence_highlights(
 6987        &mut self,
 6988        query_text: String,
 6989        query_range: Range<Anchor>,
 6990        multi_buffer_range_to_query: Range<Point>,
 6991        use_debounce: bool,
 6992        window: &mut Window,
 6993        cx: &mut Context<Editor>,
 6994    ) -> Task<()> {
 6995        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6996        cx.spawn_in(window, async move |editor, cx| {
 6997            if use_debounce {
 6998                cx.background_executor()
 6999                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7000                    .await;
 7001            }
 7002            let match_task = cx.background_spawn(async move {
 7003                let buffer_ranges = multi_buffer_snapshot
 7004                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7005                    .into_iter()
 7006                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7007                let mut match_ranges = Vec::new();
 7008                let Ok(regex) = project::search::SearchQuery::text(
 7009                    query_text.clone(),
 7010                    false,
 7011                    false,
 7012                    false,
 7013                    Default::default(),
 7014                    Default::default(),
 7015                    false,
 7016                    None,
 7017                ) else {
 7018                    return Vec::default();
 7019                };
 7020                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7021                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7022                    match_ranges.extend(
 7023                        regex
 7024                            .search(
 7025                                buffer_snapshot,
 7026                                Some(search_range.start.0..search_range.end.0),
 7027                            )
 7028                            .await
 7029                            .into_iter()
 7030                            .filter_map(|match_range| {
 7031                                let match_start = buffer_snapshot
 7032                                    .anchor_after(search_range.start + match_range.start);
 7033                                let match_end = buffer_snapshot
 7034                                    .anchor_before(search_range.start + match_range.end);
 7035                                let match_anchor_range =
 7036                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7037                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7038                            }),
 7039                    );
 7040                }
 7041                match_ranges
 7042            });
 7043            let match_ranges = match_task.await;
 7044            editor
 7045                .update_in(cx, |editor, _, cx| {
 7046                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7047                    if !match_ranges.is_empty() {
 7048                        editor.highlight_background::<SelectedTextHighlight>(
 7049                            &match_ranges,
 7050                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7051                            cx,
 7052                        )
 7053                    }
 7054                })
 7055                .log_err();
 7056        })
 7057    }
 7058
 7059    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7060        struct NewlineFold;
 7061        let type_id = std::any::TypeId::of::<NewlineFold>();
 7062        if !self.mode.is_single_line() {
 7063            return;
 7064        }
 7065        let snapshot = self.snapshot(window, cx);
 7066        if snapshot.buffer_snapshot().max_point().row == 0 {
 7067            return;
 7068        }
 7069        let task = cx.background_spawn(async move {
 7070            let new_newlines = snapshot
 7071                .buffer_chars_at(MultiBufferOffset(0))
 7072                .filter_map(|(c, i)| {
 7073                    if c == '\n' {
 7074                        Some(
 7075                            snapshot.buffer_snapshot().anchor_after(i)
 7076                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7077                        )
 7078                    } else {
 7079                        None
 7080                    }
 7081                })
 7082                .collect::<Vec<_>>();
 7083            let existing_newlines = snapshot
 7084                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7085                .filter_map(|fold| {
 7086                    if fold.placeholder.type_tag == Some(type_id) {
 7087                        Some(fold.range.start..fold.range.end)
 7088                    } else {
 7089                        None
 7090                    }
 7091                })
 7092                .collect::<Vec<_>>();
 7093
 7094            (new_newlines, existing_newlines)
 7095        });
 7096        self.folding_newlines = cx.spawn(async move |this, cx| {
 7097            let (new_newlines, existing_newlines) = task.await;
 7098            if new_newlines == existing_newlines {
 7099                return;
 7100            }
 7101            let placeholder = FoldPlaceholder {
 7102                render: Arc::new(move |_, _, cx| {
 7103                    div()
 7104                        .bg(cx.theme().status().hint_background)
 7105                        .border_b_1()
 7106                        .size_full()
 7107                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7108                        .border_color(cx.theme().status().hint)
 7109                        .child("\\n")
 7110                        .into_any()
 7111                }),
 7112                constrain_width: false,
 7113                merge_adjacent: false,
 7114                type_tag: Some(type_id),
 7115            };
 7116            let creases = new_newlines
 7117                .into_iter()
 7118                .map(|range| Crease::simple(range, placeholder.clone()))
 7119                .collect();
 7120            this.update(cx, |this, cx| {
 7121                this.display_map.update(cx, |display_map, cx| {
 7122                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7123                    display_map.fold(creases, cx);
 7124                });
 7125            })
 7126            .ok();
 7127        });
 7128    }
 7129
 7130    fn refresh_selected_text_highlights(
 7131        &mut self,
 7132        on_buffer_edit: bool,
 7133        window: &mut Window,
 7134        cx: &mut Context<Editor>,
 7135    ) {
 7136        let Some((query_text, query_range)) =
 7137            self.prepare_highlight_query_from_selection(window, cx)
 7138        else {
 7139            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7140            self.quick_selection_highlight_task.take();
 7141            self.debounced_selection_highlight_task.take();
 7142            return;
 7143        };
 7144        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7145        if on_buffer_edit
 7146            || self
 7147                .quick_selection_highlight_task
 7148                .as_ref()
 7149                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7150        {
 7151            let multi_buffer_visible_start = self
 7152                .scroll_manager
 7153                .anchor()
 7154                .anchor
 7155                .to_point(&multi_buffer_snapshot);
 7156            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7157                multi_buffer_visible_start
 7158                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7159                Bias::Left,
 7160            );
 7161            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7162            self.quick_selection_highlight_task = Some((
 7163                query_range.clone(),
 7164                self.update_selection_occurrence_highlights(
 7165                    query_text.clone(),
 7166                    query_range.clone(),
 7167                    multi_buffer_visible_range,
 7168                    false,
 7169                    window,
 7170                    cx,
 7171                ),
 7172            ));
 7173        }
 7174        if on_buffer_edit
 7175            || self
 7176                .debounced_selection_highlight_task
 7177                .as_ref()
 7178                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7179        {
 7180            let multi_buffer_start = multi_buffer_snapshot
 7181                .anchor_before(MultiBufferOffset(0))
 7182                .to_point(&multi_buffer_snapshot);
 7183            let multi_buffer_end = multi_buffer_snapshot
 7184                .anchor_after(multi_buffer_snapshot.len())
 7185                .to_point(&multi_buffer_snapshot);
 7186            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7187            self.debounced_selection_highlight_task = Some((
 7188                query_range.clone(),
 7189                self.update_selection_occurrence_highlights(
 7190                    query_text,
 7191                    query_range,
 7192                    multi_buffer_full_range,
 7193                    true,
 7194                    window,
 7195                    cx,
 7196                ),
 7197            ));
 7198        }
 7199    }
 7200
 7201    pub fn refresh_edit_prediction(
 7202        &mut self,
 7203        debounce: bool,
 7204        user_requested: bool,
 7205        window: &mut Window,
 7206        cx: &mut Context<Self>,
 7207    ) -> Option<()> {
 7208        if DisableAiSettings::get_global(cx).disable_ai {
 7209            return None;
 7210        }
 7211
 7212        let provider = self.edit_prediction_provider()?;
 7213        let cursor = self.selections.newest_anchor().head();
 7214        let (buffer, cursor_buffer_position) =
 7215            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7216
 7217        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7218            self.discard_edit_prediction(false, cx);
 7219            return None;
 7220        }
 7221
 7222        self.update_visible_edit_prediction(window, cx);
 7223
 7224        if !user_requested
 7225            && (!self.should_show_edit_predictions()
 7226                || !self.is_focused(window)
 7227                || buffer.read(cx).is_empty())
 7228        {
 7229            self.discard_edit_prediction(false, cx);
 7230            return None;
 7231        }
 7232
 7233        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7234        Some(())
 7235    }
 7236
 7237    fn show_edit_predictions_in_menu(&self) -> bool {
 7238        match self.edit_prediction_settings {
 7239            EditPredictionSettings::Disabled => false,
 7240            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7241        }
 7242    }
 7243
 7244    pub fn edit_predictions_enabled(&self) -> bool {
 7245        match self.edit_prediction_settings {
 7246            EditPredictionSettings::Disabled => false,
 7247            EditPredictionSettings::Enabled { .. } => true,
 7248        }
 7249    }
 7250
 7251    fn edit_prediction_requires_modifier(&self) -> bool {
 7252        match self.edit_prediction_settings {
 7253            EditPredictionSettings::Disabled => false,
 7254            EditPredictionSettings::Enabled {
 7255                preview_requires_modifier,
 7256                ..
 7257            } => preview_requires_modifier,
 7258        }
 7259    }
 7260
 7261    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7262        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7263            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7264            self.discard_edit_prediction(false, cx);
 7265        } else {
 7266            let selection = self.selections.newest_anchor();
 7267            let cursor = selection.head();
 7268
 7269            if let Some((buffer, cursor_buffer_position)) =
 7270                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7271            {
 7272                self.edit_prediction_settings =
 7273                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7274            }
 7275        }
 7276    }
 7277
 7278    fn edit_prediction_settings_at_position(
 7279        &self,
 7280        buffer: &Entity<Buffer>,
 7281        buffer_position: language::Anchor,
 7282        cx: &App,
 7283    ) -> EditPredictionSettings {
 7284        if !self.mode.is_full()
 7285            || !self.show_edit_predictions_override.unwrap_or(true)
 7286            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7287        {
 7288            return EditPredictionSettings::Disabled;
 7289        }
 7290
 7291        let buffer = buffer.read(cx);
 7292
 7293        let file = buffer.file();
 7294
 7295        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7296            return EditPredictionSettings::Disabled;
 7297        };
 7298
 7299        let by_provider = matches!(
 7300            self.menu_edit_predictions_policy,
 7301            MenuEditPredictionsPolicy::ByProvider
 7302        );
 7303
 7304        let show_in_menu = by_provider
 7305            && self
 7306                .edit_prediction_provider
 7307                .as_ref()
 7308                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7309
 7310        let preview_requires_modifier =
 7311            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7312
 7313        EditPredictionSettings::Enabled {
 7314            show_in_menu,
 7315            preview_requires_modifier,
 7316        }
 7317    }
 7318
 7319    fn should_show_edit_predictions(&self) -> bool {
 7320        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7321    }
 7322
 7323    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7324        matches!(
 7325            self.edit_prediction_preview,
 7326            EditPredictionPreview::Active { .. }
 7327        )
 7328    }
 7329
 7330    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7331        let cursor = self.selections.newest_anchor().head();
 7332        if let Some((buffer, cursor_position)) =
 7333            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7334        {
 7335            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7336        } else {
 7337            false
 7338        }
 7339    }
 7340
 7341    pub fn supports_minimap(&self, cx: &App) -> bool {
 7342        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7343    }
 7344
 7345    fn edit_predictions_enabled_in_buffer(
 7346        &self,
 7347        buffer: &Entity<Buffer>,
 7348        buffer_position: language::Anchor,
 7349        cx: &App,
 7350    ) -> bool {
 7351        maybe!({
 7352            if self.read_only(cx) {
 7353                return Some(false);
 7354            }
 7355            let provider = self.edit_prediction_provider()?;
 7356            if !provider.is_enabled(buffer, buffer_position, cx) {
 7357                return Some(false);
 7358            }
 7359            let buffer = buffer.read(cx);
 7360            let Some(file) = buffer.file() else {
 7361                return Some(true);
 7362            };
 7363            let settings = all_language_settings(Some(file), cx);
 7364            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7365        })
 7366        .unwrap_or(false)
 7367    }
 7368
 7369    fn cycle_edit_prediction(
 7370        &mut self,
 7371        direction: Direction,
 7372        window: &mut Window,
 7373        cx: &mut Context<Self>,
 7374    ) -> Option<()> {
 7375        let provider = self.edit_prediction_provider()?;
 7376        let cursor = self.selections.newest_anchor().head();
 7377        let (buffer, cursor_buffer_position) =
 7378            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7379        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7380            return None;
 7381        }
 7382
 7383        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7384        self.update_visible_edit_prediction(window, cx);
 7385
 7386        Some(())
 7387    }
 7388
 7389    pub fn show_edit_prediction(
 7390        &mut self,
 7391        _: &ShowEditPrediction,
 7392        window: &mut Window,
 7393        cx: &mut Context<Self>,
 7394    ) {
 7395        if !self.has_active_edit_prediction() {
 7396            self.refresh_edit_prediction(false, true, window, cx);
 7397            return;
 7398        }
 7399
 7400        self.update_visible_edit_prediction(window, cx);
 7401    }
 7402
 7403    pub fn display_cursor_names(
 7404        &mut self,
 7405        _: &DisplayCursorNames,
 7406        window: &mut Window,
 7407        cx: &mut Context<Self>,
 7408    ) {
 7409        self.show_cursor_names(window, cx);
 7410    }
 7411
 7412    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7413        self.show_cursor_names = true;
 7414        cx.notify();
 7415        cx.spawn_in(window, async move |this, cx| {
 7416            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7417            this.update(cx, |this, cx| {
 7418                this.show_cursor_names = false;
 7419                cx.notify()
 7420            })
 7421            .ok()
 7422        })
 7423        .detach();
 7424    }
 7425
 7426    pub fn next_edit_prediction(
 7427        &mut self,
 7428        _: &NextEditPrediction,
 7429        window: &mut Window,
 7430        cx: &mut Context<Self>,
 7431    ) {
 7432        if self.has_active_edit_prediction() {
 7433            self.cycle_edit_prediction(Direction::Next, window, cx);
 7434        } else {
 7435            let is_copilot_disabled = self
 7436                .refresh_edit_prediction(false, true, window, cx)
 7437                .is_none();
 7438            if is_copilot_disabled {
 7439                cx.propagate();
 7440            }
 7441        }
 7442    }
 7443
 7444    pub fn previous_edit_prediction(
 7445        &mut self,
 7446        _: &PreviousEditPrediction,
 7447        window: &mut Window,
 7448        cx: &mut Context<Self>,
 7449    ) {
 7450        if self.has_active_edit_prediction() {
 7451            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7452        } else {
 7453            let is_copilot_disabled = self
 7454                .refresh_edit_prediction(false, true, window, cx)
 7455                .is_none();
 7456            if is_copilot_disabled {
 7457                cx.propagate();
 7458            }
 7459        }
 7460    }
 7461
 7462    pub fn accept_edit_prediction(
 7463        &mut self,
 7464        _: &AcceptEditPrediction,
 7465        window: &mut Window,
 7466        cx: &mut Context<Self>,
 7467    ) {
 7468        if self.show_edit_predictions_in_menu() {
 7469            self.hide_context_menu(window, cx);
 7470        }
 7471
 7472        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7473            return;
 7474        };
 7475
 7476        match &active_edit_prediction.completion {
 7477            EditPrediction::MoveWithin { target, .. } => {
 7478                let target = *target;
 7479
 7480                if let Some(position_map) = &self.last_position_map {
 7481                    if position_map
 7482                        .visible_row_range
 7483                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7484                        || !self.edit_prediction_requires_modifier()
 7485                    {
 7486                        self.unfold_ranges(&[target..target], true, false, cx);
 7487                        // Note that this is also done in vim's handler of the Tab action.
 7488                        self.change_selections(
 7489                            SelectionEffects::scroll(Autoscroll::newest()),
 7490                            window,
 7491                            cx,
 7492                            |selections| {
 7493                                selections.select_anchor_ranges([target..target]);
 7494                            },
 7495                        );
 7496                        self.clear_row_highlights::<EditPredictionPreview>();
 7497
 7498                        self.edit_prediction_preview
 7499                            .set_previous_scroll_position(None);
 7500                    } else {
 7501                        self.edit_prediction_preview
 7502                            .set_previous_scroll_position(Some(
 7503                                position_map.snapshot.scroll_anchor,
 7504                            ));
 7505
 7506                        self.highlight_rows::<EditPredictionPreview>(
 7507                            target..target,
 7508                            cx.theme().colors().editor_highlighted_line_background,
 7509                            RowHighlightOptions {
 7510                                autoscroll: true,
 7511                                ..Default::default()
 7512                            },
 7513                            cx,
 7514                        );
 7515                        self.request_autoscroll(Autoscroll::fit(), cx);
 7516                    }
 7517                }
 7518            }
 7519            EditPrediction::MoveOutside { snapshot, target } => {
 7520                if let Some(workspace) = self.workspace() {
 7521                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7522                        .detach_and_log_err(cx);
 7523                }
 7524            }
 7525            EditPrediction::Edit { edits, .. } => {
 7526                self.report_edit_prediction_event(
 7527                    active_edit_prediction.completion_id.clone(),
 7528                    true,
 7529                    cx,
 7530                );
 7531
 7532                if let Some(provider) = self.edit_prediction_provider() {
 7533                    provider.accept(cx);
 7534                }
 7535
 7536                // Store the transaction ID and selections before applying the edit
 7537                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7538
 7539                let snapshot = self.buffer.read(cx).snapshot(cx);
 7540                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7541
 7542                self.buffer.update(cx, |buffer, cx| {
 7543                    buffer.edit(edits.iter().cloned(), None, cx)
 7544                });
 7545
 7546                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7547                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7548                });
 7549
 7550                let selections = self.selections.disjoint_anchors_arc();
 7551                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7552                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7553                    if has_new_transaction {
 7554                        self.selection_history
 7555                            .insert_transaction(transaction_id_now, selections);
 7556                    }
 7557                }
 7558
 7559                self.update_visible_edit_prediction(window, cx);
 7560                if self.active_edit_prediction.is_none() {
 7561                    self.refresh_edit_prediction(true, true, window, cx);
 7562                }
 7563
 7564                cx.notify();
 7565            }
 7566        }
 7567
 7568        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7569    }
 7570
 7571    pub fn accept_partial_edit_prediction(
 7572        &mut self,
 7573        _: &AcceptPartialEditPrediction,
 7574        window: &mut Window,
 7575        cx: &mut Context<Self>,
 7576    ) {
 7577        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7578            return;
 7579        };
 7580        if self.selections.count() != 1 {
 7581            return;
 7582        }
 7583
 7584        match &active_edit_prediction.completion {
 7585            EditPrediction::MoveWithin { target, .. } => {
 7586                let target = *target;
 7587                self.change_selections(
 7588                    SelectionEffects::scroll(Autoscroll::newest()),
 7589                    window,
 7590                    cx,
 7591                    |selections| {
 7592                        selections.select_anchor_ranges([target..target]);
 7593                    },
 7594                );
 7595            }
 7596            EditPrediction::MoveOutside { snapshot, target } => {
 7597                if let Some(workspace) = self.workspace() {
 7598                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7599                        .detach_and_log_err(cx);
 7600                }
 7601            }
 7602            EditPrediction::Edit { edits, .. } => {
 7603                self.report_edit_prediction_event(
 7604                    active_edit_prediction.completion_id.clone(),
 7605                    true,
 7606                    cx,
 7607                );
 7608
 7609                // Find an insertion that starts at the cursor position.
 7610                let snapshot = self.buffer.read(cx).snapshot(cx);
 7611                let cursor_offset = self
 7612                    .selections
 7613                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7614                    .head();
 7615                let insertion = edits.iter().find_map(|(range, text)| {
 7616                    let range = range.to_offset(&snapshot);
 7617                    if range.is_empty() && range.start == cursor_offset {
 7618                        Some(text)
 7619                    } else {
 7620                        None
 7621                    }
 7622                });
 7623
 7624                if let Some(text) = insertion {
 7625                    let mut partial_completion = text
 7626                        .chars()
 7627                        .by_ref()
 7628                        .take_while(|c| c.is_alphabetic())
 7629                        .collect::<String>();
 7630                    if partial_completion.is_empty() {
 7631                        partial_completion = text
 7632                            .chars()
 7633                            .by_ref()
 7634                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7635                            .collect::<String>();
 7636                    }
 7637
 7638                    cx.emit(EditorEvent::InputHandled {
 7639                        utf16_range_to_replace: None,
 7640                        text: partial_completion.clone().into(),
 7641                    });
 7642
 7643                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7644
 7645                    self.refresh_edit_prediction(true, true, window, cx);
 7646                    cx.notify();
 7647                } else {
 7648                    self.accept_edit_prediction(&Default::default(), window, cx);
 7649                }
 7650            }
 7651        }
 7652    }
 7653
 7654    fn discard_edit_prediction(
 7655        &mut self,
 7656        should_report_edit_prediction_event: bool,
 7657        cx: &mut Context<Self>,
 7658    ) -> bool {
 7659        if should_report_edit_prediction_event {
 7660            let completion_id = self
 7661                .active_edit_prediction
 7662                .as_ref()
 7663                .and_then(|active_completion| active_completion.completion_id.clone());
 7664
 7665            self.report_edit_prediction_event(completion_id, false, cx);
 7666        }
 7667
 7668        if let Some(provider) = self.edit_prediction_provider() {
 7669            provider.discard(cx);
 7670        }
 7671
 7672        self.take_active_edit_prediction(cx)
 7673    }
 7674
 7675    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7676        let Some(provider) = self.edit_prediction_provider() else {
 7677            return;
 7678        };
 7679
 7680        let Some((_, buffer, _)) = self
 7681            .buffer
 7682            .read(cx)
 7683            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7684        else {
 7685            return;
 7686        };
 7687
 7688        let extension = buffer
 7689            .read(cx)
 7690            .file()
 7691            .and_then(|file| Some(file.path().extension()?.to_string()));
 7692
 7693        let event_type = match accepted {
 7694            true => "Edit Prediction Accepted",
 7695            false => "Edit Prediction Discarded",
 7696        };
 7697        telemetry::event!(
 7698            event_type,
 7699            provider = provider.name(),
 7700            prediction_id = id,
 7701            suggestion_accepted = accepted,
 7702            file_extension = extension,
 7703        );
 7704    }
 7705
 7706    fn open_editor_at_anchor(
 7707        snapshot: &language::BufferSnapshot,
 7708        target: language::Anchor,
 7709        workspace: &Entity<Workspace>,
 7710        window: &mut Window,
 7711        cx: &mut App,
 7712    ) -> Task<Result<()>> {
 7713        workspace.update(cx, |workspace, cx| {
 7714            let path = snapshot.file().map(|file| file.full_path(cx));
 7715            let Some(path) =
 7716                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7717            else {
 7718                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7719            };
 7720            let target = text::ToPoint::to_point(&target, snapshot);
 7721            let item = workspace.open_path(path, None, true, window, cx);
 7722            window.spawn(cx, async move |cx| {
 7723                let Some(editor) = item.await?.downcast::<Editor>() else {
 7724                    return Ok(());
 7725                };
 7726                editor
 7727                    .update_in(cx, |editor, window, cx| {
 7728                        editor.go_to_singleton_buffer_point(target, window, cx);
 7729                    })
 7730                    .ok();
 7731                anyhow::Ok(())
 7732            })
 7733        })
 7734    }
 7735
 7736    pub fn has_active_edit_prediction(&self) -> bool {
 7737        self.active_edit_prediction.is_some()
 7738    }
 7739
 7740    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7741        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7742            return false;
 7743        };
 7744
 7745        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7746        self.clear_highlights::<EditPredictionHighlight>(cx);
 7747        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7748        true
 7749    }
 7750
 7751    /// Returns true when we're displaying the edit prediction popover below the cursor
 7752    /// like we are not previewing and the LSP autocomplete menu is visible
 7753    /// or we are in `when_holding_modifier` mode.
 7754    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7755        if self.edit_prediction_preview_is_active()
 7756            || !self.show_edit_predictions_in_menu()
 7757            || !self.edit_predictions_enabled()
 7758        {
 7759            return false;
 7760        }
 7761
 7762        if self.has_visible_completions_menu() {
 7763            return true;
 7764        }
 7765
 7766        has_completion && self.edit_prediction_requires_modifier()
 7767    }
 7768
 7769    fn handle_modifiers_changed(
 7770        &mut self,
 7771        modifiers: Modifiers,
 7772        position_map: &PositionMap,
 7773        window: &mut Window,
 7774        cx: &mut Context<Self>,
 7775    ) {
 7776        // Ensure that the edit prediction preview is updated, even when not
 7777        // enabled, if there's an active edit prediction preview.
 7778        if self.show_edit_predictions_in_menu()
 7779            || matches!(
 7780                self.edit_prediction_preview,
 7781                EditPredictionPreview::Active { .. }
 7782            )
 7783        {
 7784            self.update_edit_prediction_preview(&modifiers, window, cx);
 7785        }
 7786
 7787        self.update_selection_mode(&modifiers, position_map, window, cx);
 7788
 7789        let mouse_position = window.mouse_position();
 7790        if !position_map.text_hitbox.is_hovered(window) {
 7791            return;
 7792        }
 7793
 7794        self.update_hovered_link(
 7795            position_map.point_for_position(mouse_position),
 7796            &position_map.snapshot,
 7797            modifiers,
 7798            window,
 7799            cx,
 7800        )
 7801    }
 7802
 7803    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7804        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7805            MultiCursorModifier::Alt => modifiers.secondary(),
 7806            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7807        }
 7808    }
 7809
 7810    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7811        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7812            MultiCursorModifier::Alt => modifiers.alt,
 7813            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7814        }
 7815    }
 7816
 7817    fn columnar_selection_mode(
 7818        modifiers: &Modifiers,
 7819        cx: &mut Context<Self>,
 7820    ) -> Option<ColumnarMode> {
 7821        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7822            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7823                Some(ColumnarMode::FromMouse)
 7824            } else if Self::is_alt_pressed(modifiers, cx) {
 7825                Some(ColumnarMode::FromSelection)
 7826            } else {
 7827                None
 7828            }
 7829        } else {
 7830            None
 7831        }
 7832    }
 7833
 7834    fn update_selection_mode(
 7835        &mut self,
 7836        modifiers: &Modifiers,
 7837        position_map: &PositionMap,
 7838        window: &mut Window,
 7839        cx: &mut Context<Self>,
 7840    ) {
 7841        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7842            return;
 7843        };
 7844        if self.selections.pending_anchor().is_none() {
 7845            return;
 7846        }
 7847
 7848        let mouse_position = window.mouse_position();
 7849        let point_for_position = position_map.point_for_position(mouse_position);
 7850        let position = point_for_position.previous_valid;
 7851
 7852        self.select(
 7853            SelectPhase::BeginColumnar {
 7854                position,
 7855                reset: false,
 7856                mode,
 7857                goal_column: point_for_position.exact_unclipped.column(),
 7858            },
 7859            window,
 7860            cx,
 7861        );
 7862    }
 7863
 7864    fn update_edit_prediction_preview(
 7865        &mut self,
 7866        modifiers: &Modifiers,
 7867        window: &mut Window,
 7868        cx: &mut Context<Self>,
 7869    ) {
 7870        let mut modifiers_held = false;
 7871        if let Some(accept_keystroke) = self
 7872            .accept_edit_prediction_keybind(false, window, cx)
 7873            .keystroke()
 7874        {
 7875            modifiers_held = modifiers_held
 7876                || (accept_keystroke.modifiers() == modifiers
 7877                    && accept_keystroke.modifiers().modified());
 7878        };
 7879        if let Some(accept_partial_keystroke) = self
 7880            .accept_edit_prediction_keybind(true, window, cx)
 7881            .keystroke()
 7882        {
 7883            modifiers_held = modifiers_held
 7884                || (accept_partial_keystroke.modifiers() == modifiers
 7885                    && accept_partial_keystroke.modifiers().modified());
 7886        }
 7887
 7888        if modifiers_held {
 7889            if matches!(
 7890                self.edit_prediction_preview,
 7891                EditPredictionPreview::Inactive { .. }
 7892            ) {
 7893                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7894                    provider.provider.did_show(cx)
 7895                }
 7896
 7897                self.edit_prediction_preview = EditPredictionPreview::Active {
 7898                    previous_scroll_position: None,
 7899                    since: Instant::now(),
 7900                };
 7901
 7902                self.update_visible_edit_prediction(window, cx);
 7903                cx.notify();
 7904            }
 7905        } else if let EditPredictionPreview::Active {
 7906            previous_scroll_position,
 7907            since,
 7908        } = self.edit_prediction_preview
 7909        {
 7910            if let (Some(previous_scroll_position), Some(position_map)) =
 7911                (previous_scroll_position, self.last_position_map.as_ref())
 7912            {
 7913                self.set_scroll_position(
 7914                    previous_scroll_position
 7915                        .scroll_position(&position_map.snapshot.display_snapshot),
 7916                    window,
 7917                    cx,
 7918                );
 7919            }
 7920
 7921            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7922                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7923            };
 7924            self.clear_row_highlights::<EditPredictionPreview>();
 7925            self.update_visible_edit_prediction(window, cx);
 7926            cx.notify();
 7927        }
 7928    }
 7929
 7930    fn update_visible_edit_prediction(
 7931        &mut self,
 7932        _window: &mut Window,
 7933        cx: &mut Context<Self>,
 7934    ) -> Option<()> {
 7935        if DisableAiSettings::get_global(cx).disable_ai {
 7936            return None;
 7937        }
 7938
 7939        if self.ime_transaction.is_some() {
 7940            self.discard_edit_prediction(false, cx);
 7941            return None;
 7942        }
 7943
 7944        let selection = self.selections.newest_anchor();
 7945        let cursor = selection.head();
 7946        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7947        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7948        let excerpt_id = cursor.excerpt_id;
 7949
 7950        let show_in_menu = self.show_edit_predictions_in_menu();
 7951        let completions_menu_has_precedence = !show_in_menu
 7952            && (self.context_menu.borrow().is_some()
 7953                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7954
 7955        if completions_menu_has_precedence
 7956            || !offset_selection.is_empty()
 7957            || self
 7958                .active_edit_prediction
 7959                .as_ref()
 7960                .is_some_and(|completion| {
 7961                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7962                        return false;
 7963                    };
 7964                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7965                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7966                    !invalidation_range.contains(&offset_selection.head())
 7967                })
 7968        {
 7969            self.discard_edit_prediction(false, cx);
 7970            return None;
 7971        }
 7972
 7973        self.take_active_edit_prediction(cx);
 7974        let Some(provider) = self.edit_prediction_provider() else {
 7975            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7976            return None;
 7977        };
 7978
 7979        let (buffer, cursor_buffer_position) =
 7980            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7981
 7982        self.edit_prediction_settings =
 7983            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7984
 7985        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7986
 7987        if self.edit_prediction_indent_conflict {
 7988            let cursor_point = cursor.to_point(&multibuffer);
 7989
 7990            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7991
 7992            if let Some((_, indent)) = indents.iter().next()
 7993                && indent.len == cursor_point.column
 7994            {
 7995                self.edit_prediction_indent_conflict = false;
 7996            }
 7997        }
 7998
 7999        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8000
 8001        let (completion_id, edits, edit_preview) = match edit_prediction {
 8002            edit_prediction::EditPrediction::Local {
 8003                id,
 8004                edits,
 8005                edit_preview,
 8006            } => (id, edits, edit_preview),
 8007            edit_prediction::EditPrediction::Jump {
 8008                id,
 8009                snapshot,
 8010                target,
 8011            } => {
 8012                self.stale_edit_prediction_in_menu = None;
 8013                self.active_edit_prediction = Some(EditPredictionState {
 8014                    inlay_ids: vec![],
 8015                    completion: EditPrediction::MoveOutside { snapshot, target },
 8016                    completion_id: id,
 8017                    invalidation_range: None,
 8018                });
 8019                cx.notify();
 8020                return Some(());
 8021            }
 8022        };
 8023
 8024        let edits = edits
 8025            .into_iter()
 8026            .flat_map(|(range, new_text)| {
 8027                Some((
 8028                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8029                    new_text,
 8030                ))
 8031            })
 8032            .collect::<Vec<_>>();
 8033        if edits.is_empty() {
 8034            return None;
 8035        }
 8036
 8037        let first_edit_start = edits.first().unwrap().0.start;
 8038        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8039        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8040
 8041        let last_edit_end = edits.last().unwrap().0.end;
 8042        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8043        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8044
 8045        let cursor_row = cursor.to_point(&multibuffer).row;
 8046
 8047        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8048
 8049        let mut inlay_ids = Vec::new();
 8050        let invalidation_row_range;
 8051        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8052            Some(cursor_row..edit_end_row)
 8053        } else if cursor_row > edit_end_row {
 8054            Some(edit_start_row..cursor_row)
 8055        } else {
 8056            None
 8057        };
 8058        let supports_jump = self
 8059            .edit_prediction_provider
 8060            .as_ref()
 8061            .map(|provider| provider.provider.supports_jump_to_edit())
 8062            .unwrap_or(true);
 8063
 8064        let is_move = supports_jump
 8065            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8066        let completion = if is_move {
 8067            invalidation_row_range =
 8068                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8069            let target = first_edit_start;
 8070            EditPrediction::MoveWithin { target, snapshot }
 8071        } else {
 8072            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8073                && !self.edit_predictions_hidden_for_vim_mode;
 8074
 8075            if show_completions_in_buffer {
 8076                if let Some(provider) = &self.edit_prediction_provider {
 8077                    provider.provider.did_show(cx);
 8078                }
 8079                if edits
 8080                    .iter()
 8081                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8082                {
 8083                    let mut inlays = Vec::new();
 8084                    for (range, new_text) in &edits {
 8085                        let inlay = Inlay::edit_prediction(
 8086                            post_inc(&mut self.next_inlay_id),
 8087                            range.start,
 8088                            new_text.as_ref(),
 8089                        );
 8090                        inlay_ids.push(inlay.id);
 8091                        inlays.push(inlay);
 8092                    }
 8093
 8094                    self.splice_inlays(&[], inlays, cx);
 8095                } else {
 8096                    let background_color = cx.theme().status().deleted_background;
 8097                    self.highlight_text::<EditPredictionHighlight>(
 8098                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8099                        HighlightStyle {
 8100                            background_color: Some(background_color),
 8101                            ..Default::default()
 8102                        },
 8103                        cx,
 8104                    );
 8105                }
 8106            }
 8107
 8108            invalidation_row_range = edit_start_row..edit_end_row;
 8109
 8110            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8111                if provider.show_tab_accept_marker() {
 8112                    EditDisplayMode::TabAccept
 8113                } else {
 8114                    EditDisplayMode::Inline
 8115                }
 8116            } else {
 8117                EditDisplayMode::DiffPopover
 8118            };
 8119
 8120            EditPrediction::Edit {
 8121                edits,
 8122                edit_preview,
 8123                display_mode,
 8124                snapshot,
 8125            }
 8126        };
 8127
 8128        let invalidation_range = multibuffer
 8129            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8130            ..multibuffer.anchor_after(Point::new(
 8131                invalidation_row_range.end,
 8132                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8133            ));
 8134
 8135        self.stale_edit_prediction_in_menu = None;
 8136        self.active_edit_prediction = Some(EditPredictionState {
 8137            inlay_ids,
 8138            completion,
 8139            completion_id,
 8140            invalidation_range: Some(invalidation_range),
 8141        });
 8142
 8143        cx.notify();
 8144
 8145        Some(())
 8146    }
 8147
 8148    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8149        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8150    }
 8151
 8152    fn clear_tasks(&mut self) {
 8153        self.tasks.clear()
 8154    }
 8155
 8156    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8157        if self.tasks.insert(key, value).is_some() {
 8158            // This case should hopefully be rare, but just in case...
 8159            log::error!(
 8160                "multiple different run targets found on a single line, only the last target will be rendered"
 8161            )
 8162        }
 8163    }
 8164
 8165    /// Get all display points of breakpoints that will be rendered within editor
 8166    ///
 8167    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8168    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8169    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8170    fn active_breakpoints(
 8171        &self,
 8172        range: Range<DisplayRow>,
 8173        window: &mut Window,
 8174        cx: &mut Context<Self>,
 8175    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8176        let mut breakpoint_display_points = HashMap::default();
 8177
 8178        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8179            return breakpoint_display_points;
 8180        };
 8181
 8182        let snapshot = self.snapshot(window, cx);
 8183
 8184        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8185        let Some(project) = self.project() else {
 8186            return breakpoint_display_points;
 8187        };
 8188
 8189        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8190            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8191
 8192        for (buffer_snapshot, range, excerpt_id) in
 8193            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8194        {
 8195            let Some(buffer) = project
 8196                .read(cx)
 8197                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8198            else {
 8199                continue;
 8200            };
 8201            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8202                &buffer,
 8203                Some(
 8204                    buffer_snapshot.anchor_before(range.start)
 8205                        ..buffer_snapshot.anchor_after(range.end),
 8206                ),
 8207                buffer_snapshot,
 8208                cx,
 8209            );
 8210            for (breakpoint, state) in breakpoints {
 8211                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8212                let position = multi_buffer_anchor
 8213                    .to_point(&multi_buffer_snapshot)
 8214                    .to_display_point(&snapshot);
 8215
 8216                breakpoint_display_points.insert(
 8217                    position.row(),
 8218                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8219                );
 8220            }
 8221        }
 8222
 8223        breakpoint_display_points
 8224    }
 8225
 8226    fn breakpoint_context_menu(
 8227        &self,
 8228        anchor: Anchor,
 8229        window: &mut Window,
 8230        cx: &mut Context<Self>,
 8231    ) -> Entity<ui::ContextMenu> {
 8232        let weak_editor = cx.weak_entity();
 8233        let focus_handle = self.focus_handle(cx);
 8234
 8235        let row = self
 8236            .buffer
 8237            .read(cx)
 8238            .snapshot(cx)
 8239            .summary_for_anchor::<Point>(&anchor)
 8240            .row;
 8241
 8242        let breakpoint = self
 8243            .breakpoint_at_row(row, window, cx)
 8244            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8245
 8246        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8247            "Edit Log Breakpoint"
 8248        } else {
 8249            "Set Log Breakpoint"
 8250        };
 8251
 8252        let condition_breakpoint_msg = if breakpoint
 8253            .as_ref()
 8254            .is_some_and(|bp| bp.1.condition.is_some())
 8255        {
 8256            "Edit Condition Breakpoint"
 8257        } else {
 8258            "Set Condition Breakpoint"
 8259        };
 8260
 8261        let hit_condition_breakpoint_msg = if breakpoint
 8262            .as_ref()
 8263            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8264        {
 8265            "Edit Hit Condition Breakpoint"
 8266        } else {
 8267            "Set Hit Condition Breakpoint"
 8268        };
 8269
 8270        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8271            "Unset Breakpoint"
 8272        } else {
 8273            "Set Breakpoint"
 8274        };
 8275
 8276        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8277
 8278        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8279            BreakpointState::Enabled => Some("Disable"),
 8280            BreakpointState::Disabled => Some("Enable"),
 8281        });
 8282
 8283        let (anchor, breakpoint) =
 8284            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8285
 8286        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8287            menu.on_blur_subscription(Subscription::new(|| {}))
 8288                .context(focus_handle)
 8289                .when(run_to_cursor, |this| {
 8290                    let weak_editor = weak_editor.clone();
 8291                    this.entry("Run to cursor", None, move |window, cx| {
 8292                        weak_editor
 8293                            .update(cx, |editor, cx| {
 8294                                editor.change_selections(
 8295                                    SelectionEffects::no_scroll(),
 8296                                    window,
 8297                                    cx,
 8298                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8299                                );
 8300                            })
 8301                            .ok();
 8302
 8303                        window.dispatch_action(Box::new(RunToCursor), cx);
 8304                    })
 8305                    .separator()
 8306                })
 8307                .when_some(toggle_state_msg, |this, msg| {
 8308                    this.entry(msg, None, {
 8309                        let weak_editor = weak_editor.clone();
 8310                        let breakpoint = breakpoint.clone();
 8311                        move |_window, cx| {
 8312                            weak_editor
 8313                                .update(cx, |this, cx| {
 8314                                    this.edit_breakpoint_at_anchor(
 8315                                        anchor,
 8316                                        breakpoint.as_ref().clone(),
 8317                                        BreakpointEditAction::InvertState,
 8318                                        cx,
 8319                                    );
 8320                                })
 8321                                .log_err();
 8322                        }
 8323                    })
 8324                })
 8325                .entry(set_breakpoint_msg, None, {
 8326                    let weak_editor = weak_editor.clone();
 8327                    let breakpoint = breakpoint.clone();
 8328                    move |_window, cx| {
 8329                        weak_editor
 8330                            .update(cx, |this, cx| {
 8331                                this.edit_breakpoint_at_anchor(
 8332                                    anchor,
 8333                                    breakpoint.as_ref().clone(),
 8334                                    BreakpointEditAction::Toggle,
 8335                                    cx,
 8336                                );
 8337                            })
 8338                            .log_err();
 8339                    }
 8340                })
 8341                .entry(log_breakpoint_msg, None, {
 8342                    let breakpoint = breakpoint.clone();
 8343                    let weak_editor = weak_editor.clone();
 8344                    move |window, cx| {
 8345                        weak_editor
 8346                            .update(cx, |this, cx| {
 8347                                this.add_edit_breakpoint_block(
 8348                                    anchor,
 8349                                    breakpoint.as_ref(),
 8350                                    BreakpointPromptEditAction::Log,
 8351                                    window,
 8352                                    cx,
 8353                                );
 8354                            })
 8355                            .log_err();
 8356                    }
 8357                })
 8358                .entry(condition_breakpoint_msg, None, {
 8359                    let breakpoint = breakpoint.clone();
 8360                    let weak_editor = weak_editor.clone();
 8361                    move |window, cx| {
 8362                        weak_editor
 8363                            .update(cx, |this, cx| {
 8364                                this.add_edit_breakpoint_block(
 8365                                    anchor,
 8366                                    breakpoint.as_ref(),
 8367                                    BreakpointPromptEditAction::Condition,
 8368                                    window,
 8369                                    cx,
 8370                                );
 8371                            })
 8372                            .log_err();
 8373                    }
 8374                })
 8375                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8376                    weak_editor
 8377                        .update(cx, |this, cx| {
 8378                            this.add_edit_breakpoint_block(
 8379                                anchor,
 8380                                breakpoint.as_ref(),
 8381                                BreakpointPromptEditAction::HitCondition,
 8382                                window,
 8383                                cx,
 8384                            );
 8385                        })
 8386                        .log_err();
 8387                })
 8388        })
 8389    }
 8390
 8391    fn render_breakpoint(
 8392        &self,
 8393        position: Anchor,
 8394        row: DisplayRow,
 8395        breakpoint: &Breakpoint,
 8396        state: Option<BreakpointSessionState>,
 8397        cx: &mut Context<Self>,
 8398    ) -> IconButton {
 8399        let is_rejected = state.is_some_and(|s| !s.verified);
 8400        // Is it a breakpoint that shows up when hovering over gutter?
 8401        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8402            (false, false),
 8403            |PhantomBreakpointIndicator {
 8404                 is_active,
 8405                 display_row,
 8406                 collides_with_existing_breakpoint,
 8407             }| {
 8408                (
 8409                    is_active && display_row == row,
 8410                    collides_with_existing_breakpoint,
 8411                )
 8412            },
 8413        );
 8414
 8415        let (color, icon) = {
 8416            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8417                (false, false) => ui::IconName::DebugBreakpoint,
 8418                (true, false) => ui::IconName::DebugLogBreakpoint,
 8419                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8420                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8421            };
 8422
 8423            let color = cx.theme().colors();
 8424
 8425            let color = if is_phantom {
 8426                if collides_with_existing {
 8427                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8428                } else {
 8429                    Color::Hint
 8430                }
 8431            } else if is_rejected {
 8432                Color::Disabled
 8433            } else {
 8434                Color::Debugger
 8435            };
 8436
 8437            (color, icon)
 8438        };
 8439
 8440        let breakpoint = Arc::from(breakpoint.clone());
 8441
 8442        let alt_as_text = gpui::Keystroke {
 8443            modifiers: Modifiers::secondary_key(),
 8444            ..Default::default()
 8445        };
 8446        let primary_action_text = if breakpoint.is_disabled() {
 8447            "Enable breakpoint"
 8448        } else if is_phantom && !collides_with_existing {
 8449            "Set breakpoint"
 8450        } else {
 8451            "Unset breakpoint"
 8452        };
 8453        let focus_handle = self.focus_handle.clone();
 8454
 8455        let meta = if is_rejected {
 8456            SharedString::from("No executable code is associated with this line.")
 8457        } else if collides_with_existing && !breakpoint.is_disabled() {
 8458            SharedString::from(format!(
 8459                "{alt_as_text}-click to disable,\nright-click for more options."
 8460            ))
 8461        } else {
 8462            SharedString::from("Right-click for more options.")
 8463        };
 8464        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8465            .icon_size(IconSize::XSmall)
 8466            .size(ui::ButtonSize::None)
 8467            .when(is_rejected, |this| {
 8468                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8469            })
 8470            .icon_color(color)
 8471            .style(ButtonStyle::Transparent)
 8472            .on_click(cx.listener({
 8473                move |editor, event: &ClickEvent, window, cx| {
 8474                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8475                        BreakpointEditAction::InvertState
 8476                    } else {
 8477                        BreakpointEditAction::Toggle
 8478                    };
 8479
 8480                    window.focus(&editor.focus_handle(cx));
 8481                    editor.edit_breakpoint_at_anchor(
 8482                        position,
 8483                        breakpoint.as_ref().clone(),
 8484                        edit_action,
 8485                        cx,
 8486                    );
 8487                }
 8488            }))
 8489            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8490                editor.set_breakpoint_context_menu(
 8491                    row,
 8492                    Some(position),
 8493                    event.position(),
 8494                    window,
 8495                    cx,
 8496                );
 8497            }))
 8498            .tooltip(move |_window, cx| {
 8499                Tooltip::with_meta_in(
 8500                    primary_action_text,
 8501                    Some(&ToggleBreakpoint),
 8502                    meta.clone(),
 8503                    &focus_handle,
 8504                    cx,
 8505                )
 8506            })
 8507    }
 8508
 8509    fn build_tasks_context(
 8510        project: &Entity<Project>,
 8511        buffer: &Entity<Buffer>,
 8512        buffer_row: u32,
 8513        tasks: &Arc<RunnableTasks>,
 8514        cx: &mut Context<Self>,
 8515    ) -> Task<Option<task::TaskContext>> {
 8516        let position = Point::new(buffer_row, tasks.column);
 8517        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8518        let location = Location {
 8519            buffer: buffer.clone(),
 8520            range: range_start..range_start,
 8521        };
 8522        // Fill in the environmental variables from the tree-sitter captures
 8523        let mut captured_task_variables = TaskVariables::default();
 8524        for (capture_name, value) in tasks.extra_variables.clone() {
 8525            captured_task_variables.insert(
 8526                task::VariableName::Custom(capture_name.into()),
 8527                value.clone(),
 8528            );
 8529        }
 8530        project.update(cx, |project, cx| {
 8531            project.task_store().update(cx, |task_store, cx| {
 8532                task_store.task_context_for_location(captured_task_variables, location, cx)
 8533            })
 8534        })
 8535    }
 8536
 8537    pub fn spawn_nearest_task(
 8538        &mut self,
 8539        action: &SpawnNearestTask,
 8540        window: &mut Window,
 8541        cx: &mut Context<Self>,
 8542    ) {
 8543        let Some((workspace, _)) = self.workspace.clone() else {
 8544            return;
 8545        };
 8546        let Some(project) = self.project.clone() else {
 8547            return;
 8548        };
 8549
 8550        // Try to find a closest, enclosing node using tree-sitter that has a task
 8551        let Some((buffer, buffer_row, tasks)) = self
 8552            .find_enclosing_node_task(cx)
 8553            // Or find the task that's closest in row-distance.
 8554            .or_else(|| self.find_closest_task(cx))
 8555        else {
 8556            return;
 8557        };
 8558
 8559        let reveal_strategy = action.reveal;
 8560        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8561        cx.spawn_in(window, async move |_, cx| {
 8562            let context = task_context.await?;
 8563            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8564
 8565            let resolved = &mut resolved_task.resolved;
 8566            resolved.reveal = reveal_strategy;
 8567
 8568            workspace
 8569                .update_in(cx, |workspace, window, cx| {
 8570                    workspace.schedule_resolved_task(
 8571                        task_source_kind,
 8572                        resolved_task,
 8573                        false,
 8574                        window,
 8575                        cx,
 8576                    );
 8577                })
 8578                .ok()
 8579        })
 8580        .detach();
 8581    }
 8582
 8583    fn find_closest_task(
 8584        &mut self,
 8585        cx: &mut Context<Self>,
 8586    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8587        let cursor_row = self
 8588            .selections
 8589            .newest_adjusted(&self.display_snapshot(cx))
 8590            .head()
 8591            .row;
 8592
 8593        let ((buffer_id, row), tasks) = self
 8594            .tasks
 8595            .iter()
 8596            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8597
 8598        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8599        let tasks = Arc::new(tasks.to_owned());
 8600        Some((buffer, *row, tasks))
 8601    }
 8602
 8603    fn find_enclosing_node_task(
 8604        &mut self,
 8605        cx: &mut Context<Self>,
 8606    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8607        let snapshot = self.buffer.read(cx).snapshot(cx);
 8608        let offset = self
 8609            .selections
 8610            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8611            .head();
 8612        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8613        let offset = excerpt.map_offset_to_buffer(offset);
 8614        let buffer_id = excerpt.buffer().remote_id();
 8615
 8616        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8617        let mut cursor = layer.node().walk();
 8618
 8619        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8620            if cursor.node().end_byte() == offset.0 {
 8621                cursor.goto_next_sibling();
 8622            }
 8623        }
 8624
 8625        // Ascend to the smallest ancestor that contains the range and has a task.
 8626        loop {
 8627            let node = cursor.node();
 8628            let node_range = node.byte_range();
 8629            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8630
 8631            // Check if this node contains our offset
 8632            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8633                // If it contains offset, check for task
 8634                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8635                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8636                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8637                }
 8638            }
 8639
 8640            if !cursor.goto_parent() {
 8641                break;
 8642            }
 8643        }
 8644        None
 8645    }
 8646
 8647    fn render_run_indicator(
 8648        &self,
 8649        _style: &EditorStyle,
 8650        is_active: bool,
 8651        row: DisplayRow,
 8652        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8653        cx: &mut Context<Self>,
 8654    ) -> IconButton {
 8655        let color = Color::Muted;
 8656        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8657
 8658        IconButton::new(
 8659            ("run_indicator", row.0 as usize),
 8660            ui::IconName::PlayOutlined,
 8661        )
 8662        .shape(ui::IconButtonShape::Square)
 8663        .icon_size(IconSize::XSmall)
 8664        .icon_color(color)
 8665        .toggle_state(is_active)
 8666        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8667            let quick_launch = match e {
 8668                ClickEvent::Keyboard(_) => true,
 8669                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8670            };
 8671
 8672            window.focus(&editor.focus_handle(cx));
 8673            editor.toggle_code_actions(
 8674                &ToggleCodeActions {
 8675                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8676                    quick_launch,
 8677                },
 8678                window,
 8679                cx,
 8680            );
 8681        }))
 8682        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8683            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8684        }))
 8685    }
 8686
 8687    pub fn context_menu_visible(&self) -> bool {
 8688        !self.edit_prediction_preview_is_active()
 8689            && self
 8690                .context_menu
 8691                .borrow()
 8692                .as_ref()
 8693                .is_some_and(|menu| menu.visible())
 8694    }
 8695
 8696    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8697        self.context_menu
 8698            .borrow()
 8699            .as_ref()
 8700            .map(|menu| menu.origin())
 8701    }
 8702
 8703    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8704        self.context_menu_options = Some(options);
 8705    }
 8706
 8707    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8708    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8709
 8710    fn render_edit_prediction_popover(
 8711        &mut self,
 8712        text_bounds: &Bounds<Pixels>,
 8713        content_origin: gpui::Point<Pixels>,
 8714        right_margin: Pixels,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        scroll_top: ScrollOffset,
 8718        scroll_bottom: ScrollOffset,
 8719        line_layouts: &[LineWithInvisibles],
 8720        line_height: Pixels,
 8721        scroll_position: gpui::Point<ScrollOffset>,
 8722        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8723        newest_selection_head: Option<DisplayPoint>,
 8724        editor_width: Pixels,
 8725        style: &EditorStyle,
 8726        window: &mut Window,
 8727        cx: &mut App,
 8728    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8729        if self.mode().is_minimap() {
 8730            return None;
 8731        }
 8732        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8733
 8734        if self.edit_prediction_visible_in_cursor_popover(true) {
 8735            return None;
 8736        }
 8737
 8738        match &active_edit_prediction.completion {
 8739            EditPrediction::MoveWithin { target, .. } => {
 8740                let target_display_point = target.to_display_point(editor_snapshot);
 8741
 8742                if self.edit_prediction_requires_modifier() {
 8743                    if !self.edit_prediction_preview_is_active() {
 8744                        return None;
 8745                    }
 8746
 8747                    self.render_edit_prediction_modifier_jump_popover(
 8748                        text_bounds,
 8749                        content_origin,
 8750                        visible_row_range,
 8751                        line_layouts,
 8752                        line_height,
 8753                        scroll_pixel_position,
 8754                        newest_selection_head,
 8755                        target_display_point,
 8756                        window,
 8757                        cx,
 8758                    )
 8759                } else {
 8760                    self.render_edit_prediction_eager_jump_popover(
 8761                        text_bounds,
 8762                        content_origin,
 8763                        editor_snapshot,
 8764                        visible_row_range,
 8765                        scroll_top,
 8766                        scroll_bottom,
 8767                        line_height,
 8768                        scroll_pixel_position,
 8769                        target_display_point,
 8770                        editor_width,
 8771                        window,
 8772                        cx,
 8773                    )
 8774                }
 8775            }
 8776            EditPrediction::Edit {
 8777                display_mode: EditDisplayMode::Inline,
 8778                ..
 8779            } => None,
 8780            EditPrediction::Edit {
 8781                display_mode: EditDisplayMode::TabAccept,
 8782                edits,
 8783                ..
 8784            } => {
 8785                let range = &edits.first()?.0;
 8786                let target_display_point = range.end.to_display_point(editor_snapshot);
 8787
 8788                self.render_edit_prediction_end_of_line_popover(
 8789                    "Accept",
 8790                    editor_snapshot,
 8791                    visible_row_range,
 8792                    target_display_point,
 8793                    line_height,
 8794                    scroll_pixel_position,
 8795                    content_origin,
 8796                    editor_width,
 8797                    window,
 8798                    cx,
 8799                )
 8800            }
 8801            EditPrediction::Edit {
 8802                edits,
 8803                edit_preview,
 8804                display_mode: EditDisplayMode::DiffPopover,
 8805                snapshot,
 8806            } => self.render_edit_prediction_diff_popover(
 8807                text_bounds,
 8808                content_origin,
 8809                right_margin,
 8810                editor_snapshot,
 8811                visible_row_range,
 8812                line_layouts,
 8813                line_height,
 8814                scroll_position,
 8815                scroll_pixel_position,
 8816                newest_selection_head,
 8817                editor_width,
 8818                style,
 8819                edits,
 8820                edit_preview,
 8821                snapshot,
 8822                window,
 8823                cx,
 8824            ),
 8825            EditPrediction::MoveOutside { snapshot, .. } => {
 8826                let mut element = self
 8827                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8828                    .into_any();
 8829
 8830                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8831                let origin_x = text_bounds.size.width - size.width - px(30.);
 8832                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8833                element.prepaint_at(origin, window, cx);
 8834
 8835                Some((element, origin))
 8836            }
 8837        }
 8838    }
 8839
 8840    fn render_edit_prediction_modifier_jump_popover(
 8841        &mut self,
 8842        text_bounds: &Bounds<Pixels>,
 8843        content_origin: gpui::Point<Pixels>,
 8844        visible_row_range: Range<DisplayRow>,
 8845        line_layouts: &[LineWithInvisibles],
 8846        line_height: Pixels,
 8847        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8848        newest_selection_head: Option<DisplayPoint>,
 8849        target_display_point: DisplayPoint,
 8850        window: &mut Window,
 8851        cx: &mut App,
 8852    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8853        let scrolled_content_origin =
 8854            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8855
 8856        const SCROLL_PADDING_Y: Pixels = px(12.);
 8857
 8858        if target_display_point.row() < visible_row_range.start {
 8859            return self.render_edit_prediction_scroll_popover(
 8860                |_| SCROLL_PADDING_Y,
 8861                IconName::ArrowUp,
 8862                visible_row_range,
 8863                line_layouts,
 8864                newest_selection_head,
 8865                scrolled_content_origin,
 8866                window,
 8867                cx,
 8868            );
 8869        } else if target_display_point.row() >= visible_row_range.end {
 8870            return self.render_edit_prediction_scroll_popover(
 8871                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8872                IconName::ArrowDown,
 8873                visible_row_range,
 8874                line_layouts,
 8875                newest_selection_head,
 8876                scrolled_content_origin,
 8877                window,
 8878                cx,
 8879            );
 8880        }
 8881
 8882        const POLE_WIDTH: Pixels = px(2.);
 8883
 8884        let line_layout =
 8885            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8886        let target_column = target_display_point.column() as usize;
 8887
 8888        let target_x = line_layout.x_for_index(target_column);
 8889        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8890            - scroll_pixel_position.y;
 8891
 8892        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8893
 8894        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8895        border_color.l += 0.001;
 8896
 8897        let mut element = v_flex()
 8898            .items_end()
 8899            .when(flag_on_right, |el| el.items_start())
 8900            .child(if flag_on_right {
 8901                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8902                    .rounded_bl(px(0.))
 8903                    .rounded_tl(px(0.))
 8904                    .border_l_2()
 8905                    .border_color(border_color)
 8906            } else {
 8907                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8908                    .rounded_br(px(0.))
 8909                    .rounded_tr(px(0.))
 8910                    .border_r_2()
 8911                    .border_color(border_color)
 8912            })
 8913            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8914            .into_any();
 8915
 8916        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8917
 8918        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8919            - point(
 8920                if flag_on_right {
 8921                    POLE_WIDTH
 8922                } else {
 8923                    size.width - POLE_WIDTH
 8924                },
 8925                size.height - line_height,
 8926            );
 8927
 8928        origin.x = origin.x.max(content_origin.x);
 8929
 8930        element.prepaint_at(origin, window, cx);
 8931
 8932        Some((element, origin))
 8933    }
 8934
 8935    fn render_edit_prediction_scroll_popover(
 8936        &mut self,
 8937        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8938        scroll_icon: IconName,
 8939        visible_row_range: Range<DisplayRow>,
 8940        line_layouts: &[LineWithInvisibles],
 8941        newest_selection_head: Option<DisplayPoint>,
 8942        scrolled_content_origin: gpui::Point<Pixels>,
 8943        window: &mut Window,
 8944        cx: &mut App,
 8945    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8946        let mut element = self
 8947            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8948            .into_any();
 8949
 8950        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8951
 8952        let cursor = newest_selection_head?;
 8953        let cursor_row_layout =
 8954            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8955        let cursor_column = cursor.column() as usize;
 8956
 8957        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8958
 8959        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8960
 8961        element.prepaint_at(origin, window, cx);
 8962        Some((element, origin))
 8963    }
 8964
 8965    fn render_edit_prediction_eager_jump_popover(
 8966        &mut self,
 8967        text_bounds: &Bounds<Pixels>,
 8968        content_origin: gpui::Point<Pixels>,
 8969        editor_snapshot: &EditorSnapshot,
 8970        visible_row_range: Range<DisplayRow>,
 8971        scroll_top: ScrollOffset,
 8972        scroll_bottom: ScrollOffset,
 8973        line_height: Pixels,
 8974        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8975        target_display_point: DisplayPoint,
 8976        editor_width: Pixels,
 8977        window: &mut Window,
 8978        cx: &mut App,
 8979    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8980        if target_display_point.row().as_f64() < scroll_top {
 8981            let mut element = self
 8982                .render_edit_prediction_line_popover(
 8983                    "Jump to Edit",
 8984                    Some(IconName::ArrowUp),
 8985                    window,
 8986                    cx,
 8987                )
 8988                .into_any();
 8989
 8990            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8991            let offset = point(
 8992                (text_bounds.size.width - size.width) / 2.,
 8993                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8994            );
 8995
 8996            let origin = text_bounds.origin + offset;
 8997            element.prepaint_at(origin, window, cx);
 8998            Some((element, origin))
 8999        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9000            let mut element = self
 9001                .render_edit_prediction_line_popover(
 9002                    "Jump to Edit",
 9003                    Some(IconName::ArrowDown),
 9004                    window,
 9005                    cx,
 9006                )
 9007                .into_any();
 9008
 9009            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9010            let offset = point(
 9011                (text_bounds.size.width - size.width) / 2.,
 9012                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9013            );
 9014
 9015            let origin = text_bounds.origin + offset;
 9016            element.prepaint_at(origin, window, cx);
 9017            Some((element, origin))
 9018        } else {
 9019            self.render_edit_prediction_end_of_line_popover(
 9020                "Jump to Edit",
 9021                editor_snapshot,
 9022                visible_row_range,
 9023                target_display_point,
 9024                line_height,
 9025                scroll_pixel_position,
 9026                content_origin,
 9027                editor_width,
 9028                window,
 9029                cx,
 9030            )
 9031        }
 9032    }
 9033
 9034    fn render_edit_prediction_end_of_line_popover(
 9035        self: &mut Editor,
 9036        label: &'static str,
 9037        editor_snapshot: &EditorSnapshot,
 9038        visible_row_range: Range<DisplayRow>,
 9039        target_display_point: DisplayPoint,
 9040        line_height: Pixels,
 9041        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9042        content_origin: gpui::Point<Pixels>,
 9043        editor_width: Pixels,
 9044        window: &mut Window,
 9045        cx: &mut App,
 9046    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9047        let target_line_end = DisplayPoint::new(
 9048            target_display_point.row(),
 9049            editor_snapshot.line_len(target_display_point.row()),
 9050        );
 9051
 9052        let mut element = self
 9053            .render_edit_prediction_line_popover(label, None, window, cx)
 9054            .into_any();
 9055
 9056        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9057
 9058        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9059
 9060        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9061        let mut origin = start_point
 9062            + line_origin
 9063            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9064        origin.x = origin.x.max(content_origin.x);
 9065
 9066        let max_x = content_origin.x + editor_width - size.width;
 9067
 9068        if origin.x > max_x {
 9069            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9070
 9071            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9072                origin.y += offset;
 9073                IconName::ArrowUp
 9074            } else {
 9075                origin.y -= offset;
 9076                IconName::ArrowDown
 9077            };
 9078
 9079            element = self
 9080                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9081                .into_any();
 9082
 9083            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9084
 9085            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9086        }
 9087
 9088        element.prepaint_at(origin, window, cx);
 9089        Some((element, origin))
 9090    }
 9091
 9092    fn render_edit_prediction_diff_popover(
 9093        self: &Editor,
 9094        text_bounds: &Bounds<Pixels>,
 9095        content_origin: gpui::Point<Pixels>,
 9096        right_margin: Pixels,
 9097        editor_snapshot: &EditorSnapshot,
 9098        visible_row_range: Range<DisplayRow>,
 9099        line_layouts: &[LineWithInvisibles],
 9100        line_height: Pixels,
 9101        scroll_position: gpui::Point<ScrollOffset>,
 9102        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9103        newest_selection_head: Option<DisplayPoint>,
 9104        editor_width: Pixels,
 9105        style: &EditorStyle,
 9106        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9107        edit_preview: &Option<language::EditPreview>,
 9108        snapshot: &language::BufferSnapshot,
 9109        window: &mut Window,
 9110        cx: &mut App,
 9111    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9112        let edit_start = edits
 9113            .first()
 9114            .unwrap()
 9115            .0
 9116            .start
 9117            .to_display_point(editor_snapshot);
 9118        let edit_end = edits
 9119            .last()
 9120            .unwrap()
 9121            .0
 9122            .end
 9123            .to_display_point(editor_snapshot);
 9124
 9125        let is_visible = visible_row_range.contains(&edit_start.row())
 9126            || visible_row_range.contains(&edit_end.row());
 9127        if !is_visible {
 9128            return None;
 9129        }
 9130
 9131        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9132            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9133        } else {
 9134            // Fallback for providers without edit_preview
 9135            crate::edit_prediction_fallback_text(edits, cx)
 9136        };
 9137
 9138        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9139        let line_count = highlighted_edits.text.lines().count();
 9140
 9141        const BORDER_WIDTH: Pixels = px(1.);
 9142
 9143        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9144        let has_keybind = keybind.is_some();
 9145
 9146        let mut element = h_flex()
 9147            .items_start()
 9148            .child(
 9149                h_flex()
 9150                    .bg(cx.theme().colors().editor_background)
 9151                    .border(BORDER_WIDTH)
 9152                    .shadow_xs()
 9153                    .border_color(cx.theme().colors().border)
 9154                    .rounded_l_lg()
 9155                    .when(line_count > 1, |el| el.rounded_br_lg())
 9156                    .pr_1()
 9157                    .child(styled_text),
 9158            )
 9159            .child(
 9160                h_flex()
 9161                    .h(line_height + BORDER_WIDTH * 2.)
 9162                    .px_1p5()
 9163                    .gap_1()
 9164                    // Workaround: For some reason, there's a gap if we don't do this
 9165                    .ml(-BORDER_WIDTH)
 9166                    .shadow(vec![gpui::BoxShadow {
 9167                        color: gpui::black().opacity(0.05),
 9168                        offset: point(px(1.), px(1.)),
 9169                        blur_radius: px(2.),
 9170                        spread_radius: px(0.),
 9171                    }])
 9172                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9173                    .border(BORDER_WIDTH)
 9174                    .border_color(cx.theme().colors().border)
 9175                    .rounded_r_lg()
 9176                    .id("edit_prediction_diff_popover_keybind")
 9177                    .when(!has_keybind, |el| {
 9178                        let status_colors = cx.theme().status();
 9179
 9180                        el.bg(status_colors.error_background)
 9181                            .border_color(status_colors.error.opacity(0.6))
 9182                            .child(Icon::new(IconName::Info).color(Color::Error))
 9183                            .cursor_default()
 9184                            .hoverable_tooltip(move |_window, cx| {
 9185                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9186                            })
 9187                    })
 9188                    .children(keybind),
 9189            )
 9190            .into_any();
 9191
 9192        let longest_row =
 9193            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9194        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9195            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9196        } else {
 9197            layout_line(
 9198                longest_row,
 9199                editor_snapshot,
 9200                style,
 9201                editor_width,
 9202                |_| false,
 9203                window,
 9204                cx,
 9205            )
 9206            .width
 9207        };
 9208
 9209        let viewport_bounds =
 9210            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9211                right: -right_margin,
 9212                ..Default::default()
 9213            });
 9214
 9215        let x_after_longest = Pixels::from(
 9216            ScrollPixelOffset::from(
 9217                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9218            ) - scroll_pixel_position.x,
 9219        );
 9220
 9221        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9222
 9223        // Fully visible if it can be displayed within the window (allow overlapping other
 9224        // panes). However, this is only allowed if the popover starts within text_bounds.
 9225        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9226            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9227
 9228        let mut origin = if can_position_to_the_right {
 9229            point(
 9230                x_after_longest,
 9231                text_bounds.origin.y
 9232                    + Pixels::from(
 9233                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9234                            - scroll_pixel_position.y,
 9235                    ),
 9236            )
 9237        } else {
 9238            let cursor_row = newest_selection_head.map(|head| head.row());
 9239            let above_edit = edit_start
 9240                .row()
 9241                .0
 9242                .checked_sub(line_count as u32)
 9243                .map(DisplayRow);
 9244            let below_edit = Some(edit_end.row() + 1);
 9245            let above_cursor =
 9246                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9247            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9248
 9249            // Place the edit popover adjacent to the edit if there is a location
 9250            // available that is onscreen and does not obscure the cursor. Otherwise,
 9251            // place it adjacent to the cursor.
 9252            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9253                .into_iter()
 9254                .flatten()
 9255                .find(|&start_row| {
 9256                    let end_row = start_row + line_count as u32;
 9257                    visible_row_range.contains(&start_row)
 9258                        && visible_row_range.contains(&end_row)
 9259                        && cursor_row
 9260                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9261                })?;
 9262
 9263            content_origin
 9264                + point(
 9265                    Pixels::from(-scroll_pixel_position.x),
 9266                    Pixels::from(
 9267                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9268                    ),
 9269                )
 9270        };
 9271
 9272        origin.x -= BORDER_WIDTH;
 9273
 9274        window.defer_draw(element, origin, 1);
 9275
 9276        // Do not return an element, since it will already be drawn due to defer_draw.
 9277        None
 9278    }
 9279
 9280    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9281        px(30.)
 9282    }
 9283
 9284    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9285        if self.read_only(cx) {
 9286            cx.theme().players().read_only()
 9287        } else {
 9288            self.style.as_ref().unwrap().local_player
 9289        }
 9290    }
 9291
 9292    fn render_edit_prediction_accept_keybind(
 9293        &self,
 9294        window: &mut Window,
 9295        cx: &mut App,
 9296    ) -> Option<AnyElement> {
 9297        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9298        let accept_keystroke = accept_binding.keystroke()?;
 9299
 9300        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9301
 9302        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9303            Color::Accent
 9304        } else {
 9305            Color::Muted
 9306        };
 9307
 9308        h_flex()
 9309            .px_0p5()
 9310            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9311            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9312            .text_size(TextSize::XSmall.rems(cx))
 9313            .child(h_flex().children(ui::render_modifiers(
 9314                accept_keystroke.modifiers(),
 9315                PlatformStyle::platform(),
 9316                Some(modifiers_color),
 9317                Some(IconSize::XSmall.rems().into()),
 9318                true,
 9319            )))
 9320            .when(is_platform_style_mac, |parent| {
 9321                parent.child(accept_keystroke.key().to_string())
 9322            })
 9323            .when(!is_platform_style_mac, |parent| {
 9324                parent.child(
 9325                    Key::new(
 9326                        util::capitalize(accept_keystroke.key()),
 9327                        Some(Color::Default),
 9328                    )
 9329                    .size(Some(IconSize::XSmall.rems().into())),
 9330                )
 9331            })
 9332            .into_any()
 9333            .into()
 9334    }
 9335
 9336    fn render_edit_prediction_line_popover(
 9337        &self,
 9338        label: impl Into<SharedString>,
 9339        icon: Option<IconName>,
 9340        window: &mut Window,
 9341        cx: &mut App,
 9342    ) -> Stateful<Div> {
 9343        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9344
 9345        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9346        let has_keybind = keybind.is_some();
 9347
 9348        h_flex()
 9349            .id("ep-line-popover")
 9350            .py_0p5()
 9351            .pl_1()
 9352            .pr(padding_right)
 9353            .gap_1()
 9354            .rounded_md()
 9355            .border_1()
 9356            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9357            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9358            .shadow_xs()
 9359            .when(!has_keybind, |el| {
 9360                let status_colors = cx.theme().status();
 9361
 9362                el.bg(status_colors.error_background)
 9363                    .border_color(status_colors.error.opacity(0.6))
 9364                    .pl_2()
 9365                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9366                    .cursor_default()
 9367                    .hoverable_tooltip(move |_window, cx| {
 9368                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9369                    })
 9370            })
 9371            .children(keybind)
 9372            .child(
 9373                Label::new(label)
 9374                    .size(LabelSize::Small)
 9375                    .when(!has_keybind, |el| {
 9376                        el.color(cx.theme().status().error.into()).strikethrough()
 9377                    }),
 9378            )
 9379            .when(!has_keybind, |el| {
 9380                el.child(
 9381                    h_flex().ml_1().child(
 9382                        Icon::new(IconName::Info)
 9383                            .size(IconSize::Small)
 9384                            .color(cx.theme().status().error.into()),
 9385                    ),
 9386                )
 9387            })
 9388            .when_some(icon, |element, icon| {
 9389                element.child(
 9390                    div()
 9391                        .mt(px(1.5))
 9392                        .child(Icon::new(icon).size(IconSize::Small)),
 9393                )
 9394            })
 9395    }
 9396
 9397    fn render_edit_prediction_jump_outside_popover(
 9398        &self,
 9399        snapshot: &BufferSnapshot,
 9400        window: &mut Window,
 9401        cx: &mut App,
 9402    ) -> Stateful<Div> {
 9403        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9404        let has_keybind = keybind.is_some();
 9405
 9406        let file_name = snapshot
 9407            .file()
 9408            .map(|file| SharedString::new(file.file_name(cx)))
 9409            .unwrap_or(SharedString::new_static("untitled"));
 9410
 9411        h_flex()
 9412            .id("ep-jump-outside-popover")
 9413            .py_1()
 9414            .px_2()
 9415            .gap_1()
 9416            .rounded_md()
 9417            .border_1()
 9418            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9419            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9420            .shadow_xs()
 9421            .when(!has_keybind, |el| {
 9422                let status_colors = cx.theme().status();
 9423
 9424                el.bg(status_colors.error_background)
 9425                    .border_color(status_colors.error.opacity(0.6))
 9426                    .pl_2()
 9427                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9428                    .cursor_default()
 9429                    .hoverable_tooltip(move |_window, cx| {
 9430                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9431                    })
 9432            })
 9433            .children(keybind)
 9434            .child(
 9435                Label::new(file_name)
 9436                    .size(LabelSize::Small)
 9437                    .buffer_font(cx)
 9438                    .when(!has_keybind, |el| {
 9439                        el.color(cx.theme().status().error.into()).strikethrough()
 9440                    }),
 9441            )
 9442            .when(!has_keybind, |el| {
 9443                el.child(
 9444                    h_flex().ml_1().child(
 9445                        Icon::new(IconName::Info)
 9446                            .size(IconSize::Small)
 9447                            .color(cx.theme().status().error.into()),
 9448                    ),
 9449                )
 9450            })
 9451            .child(
 9452                div()
 9453                    .mt(px(1.5))
 9454                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9455            )
 9456    }
 9457
 9458    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9459        let accent_color = cx.theme().colors().text_accent;
 9460        let editor_bg_color = cx.theme().colors().editor_background;
 9461        editor_bg_color.blend(accent_color.opacity(0.1))
 9462    }
 9463
 9464    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9465        let accent_color = cx.theme().colors().text_accent;
 9466        let editor_bg_color = cx.theme().colors().editor_background;
 9467        editor_bg_color.blend(accent_color.opacity(0.6))
 9468    }
 9469    fn get_prediction_provider_icon_name(
 9470        provider: &Option<RegisteredEditPredictionProvider>,
 9471    ) -> IconName {
 9472        match provider {
 9473            Some(provider) => match provider.provider.name() {
 9474                "copilot" => IconName::Copilot,
 9475                "supermaven" => IconName::Supermaven,
 9476                _ => IconName::ZedPredict,
 9477            },
 9478            None => IconName::ZedPredict,
 9479        }
 9480    }
 9481
 9482    fn render_edit_prediction_cursor_popover(
 9483        &self,
 9484        min_width: Pixels,
 9485        max_width: Pixels,
 9486        cursor_point: Point,
 9487        style: &EditorStyle,
 9488        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9489        _window: &Window,
 9490        cx: &mut Context<Editor>,
 9491    ) -> Option<AnyElement> {
 9492        let provider = self.edit_prediction_provider.as_ref()?;
 9493        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9494
 9495        let is_refreshing = provider.provider.is_refreshing(cx);
 9496
 9497        fn pending_completion_container(icon: IconName) -> Div {
 9498            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9499        }
 9500
 9501        let completion = match &self.active_edit_prediction {
 9502            Some(prediction) => {
 9503                if !self.has_visible_completions_menu() {
 9504                    const RADIUS: Pixels = px(6.);
 9505                    const BORDER_WIDTH: Pixels = px(1.);
 9506
 9507                    return Some(
 9508                        h_flex()
 9509                            .elevation_2(cx)
 9510                            .border(BORDER_WIDTH)
 9511                            .border_color(cx.theme().colors().border)
 9512                            .when(accept_keystroke.is_none(), |el| {
 9513                                el.border_color(cx.theme().status().error)
 9514                            })
 9515                            .rounded(RADIUS)
 9516                            .rounded_tl(px(0.))
 9517                            .overflow_hidden()
 9518                            .child(div().px_1p5().child(match &prediction.completion {
 9519                                EditPrediction::MoveWithin { target, snapshot } => {
 9520                                    use text::ToPoint as _;
 9521                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9522                                    {
 9523                                        Icon::new(IconName::ZedPredictDown)
 9524                                    } else {
 9525                                        Icon::new(IconName::ZedPredictUp)
 9526                                    }
 9527                                }
 9528                                EditPrediction::MoveOutside { .. } => {
 9529                                    // TODO [zeta2] custom icon for external jump?
 9530                                    Icon::new(provider_icon)
 9531                                }
 9532                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9533                            }))
 9534                            .child(
 9535                                h_flex()
 9536                                    .gap_1()
 9537                                    .py_1()
 9538                                    .px_2()
 9539                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9540                                    .border_l_1()
 9541                                    .border_color(cx.theme().colors().border)
 9542                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9543                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9544                                        el.child(
 9545                                            Label::new("Hold")
 9546                                                .size(LabelSize::Small)
 9547                                                .when(accept_keystroke.is_none(), |el| {
 9548                                                    el.strikethrough()
 9549                                                })
 9550                                                .line_height_style(LineHeightStyle::UiLabel),
 9551                                        )
 9552                                    })
 9553                                    .id("edit_prediction_cursor_popover_keybind")
 9554                                    .when(accept_keystroke.is_none(), |el| {
 9555                                        let status_colors = cx.theme().status();
 9556
 9557                                        el.bg(status_colors.error_background)
 9558                                            .border_color(status_colors.error.opacity(0.6))
 9559                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9560                                            .cursor_default()
 9561                                            .hoverable_tooltip(move |_window, cx| {
 9562                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9563                                                    .into()
 9564                                            })
 9565                                    })
 9566                                    .when_some(
 9567                                        accept_keystroke.as_ref(),
 9568                                        |el, accept_keystroke| {
 9569                                            el.child(h_flex().children(ui::render_modifiers(
 9570                                                accept_keystroke.modifiers(),
 9571                                                PlatformStyle::platform(),
 9572                                                Some(Color::Default),
 9573                                                Some(IconSize::XSmall.rems().into()),
 9574                                                false,
 9575                                            )))
 9576                                        },
 9577                                    ),
 9578                            )
 9579                            .into_any(),
 9580                    );
 9581                }
 9582
 9583                self.render_edit_prediction_cursor_popover_preview(
 9584                    prediction,
 9585                    cursor_point,
 9586                    style,
 9587                    cx,
 9588                )?
 9589            }
 9590
 9591            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9592                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9593                    stale_completion,
 9594                    cursor_point,
 9595                    style,
 9596                    cx,
 9597                )?,
 9598
 9599                None => pending_completion_container(provider_icon)
 9600                    .child(Label::new("...").size(LabelSize::Small)),
 9601            },
 9602
 9603            None => pending_completion_container(provider_icon)
 9604                .child(Label::new("...").size(LabelSize::Small)),
 9605        };
 9606
 9607        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9608            completion
 9609                .with_animation(
 9610                    "loading-completion",
 9611                    Animation::new(Duration::from_secs(2))
 9612                        .repeat()
 9613                        .with_easing(pulsating_between(0.4, 0.8)),
 9614                    |label, delta| label.opacity(delta),
 9615                )
 9616                .into_any_element()
 9617        } else {
 9618            completion.into_any_element()
 9619        };
 9620
 9621        let has_completion = self.active_edit_prediction.is_some();
 9622
 9623        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9624        Some(
 9625            h_flex()
 9626                .min_w(min_width)
 9627                .max_w(max_width)
 9628                .flex_1()
 9629                .elevation_2(cx)
 9630                .border_color(cx.theme().colors().border)
 9631                .child(
 9632                    div()
 9633                        .flex_1()
 9634                        .py_1()
 9635                        .px_2()
 9636                        .overflow_hidden()
 9637                        .child(completion),
 9638                )
 9639                .when_some(accept_keystroke, |el, accept_keystroke| {
 9640                    if !accept_keystroke.modifiers().modified() {
 9641                        return el;
 9642                    }
 9643
 9644                    el.child(
 9645                        h_flex()
 9646                            .h_full()
 9647                            .border_l_1()
 9648                            .rounded_r_lg()
 9649                            .border_color(cx.theme().colors().border)
 9650                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9651                            .gap_1()
 9652                            .py_1()
 9653                            .px_2()
 9654                            .child(
 9655                                h_flex()
 9656                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9657                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9658                                    .child(h_flex().children(ui::render_modifiers(
 9659                                        accept_keystroke.modifiers(),
 9660                                        PlatformStyle::platform(),
 9661                                        Some(if !has_completion {
 9662                                            Color::Muted
 9663                                        } else {
 9664                                            Color::Default
 9665                                        }),
 9666                                        None,
 9667                                        false,
 9668                                    ))),
 9669                            )
 9670                            .child(Label::new("Preview").into_any_element())
 9671                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9672                    )
 9673                })
 9674                .into_any(),
 9675        )
 9676    }
 9677
 9678    fn render_edit_prediction_cursor_popover_preview(
 9679        &self,
 9680        completion: &EditPredictionState,
 9681        cursor_point: Point,
 9682        style: &EditorStyle,
 9683        cx: &mut Context<Editor>,
 9684    ) -> Option<Div> {
 9685        use text::ToPoint as _;
 9686
 9687        fn render_relative_row_jump(
 9688            prefix: impl Into<String>,
 9689            current_row: u32,
 9690            target_row: u32,
 9691        ) -> Div {
 9692            let (row_diff, arrow) = if target_row < current_row {
 9693                (current_row - target_row, IconName::ArrowUp)
 9694            } else {
 9695                (target_row - current_row, IconName::ArrowDown)
 9696            };
 9697
 9698            h_flex()
 9699                .child(
 9700                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9701                        .color(Color::Muted)
 9702                        .size(LabelSize::Small),
 9703                )
 9704                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9705        }
 9706
 9707        let supports_jump = self
 9708            .edit_prediction_provider
 9709            .as_ref()
 9710            .map(|provider| provider.provider.supports_jump_to_edit())
 9711            .unwrap_or(true);
 9712
 9713        match &completion.completion {
 9714            EditPrediction::MoveWithin {
 9715                target, snapshot, ..
 9716            } => {
 9717                if !supports_jump {
 9718                    return None;
 9719                }
 9720
 9721                Some(
 9722                    h_flex()
 9723                        .px_2()
 9724                        .gap_2()
 9725                        .flex_1()
 9726                        .child(
 9727                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9728                                Icon::new(IconName::ZedPredictDown)
 9729                            } else {
 9730                                Icon::new(IconName::ZedPredictUp)
 9731                            },
 9732                        )
 9733                        .child(Label::new("Jump to Edit")),
 9734                )
 9735            }
 9736            EditPrediction::MoveOutside { snapshot, .. } => {
 9737                let file_name = snapshot
 9738                    .file()
 9739                    .map(|file| file.file_name(cx))
 9740                    .unwrap_or("untitled");
 9741                Some(
 9742                    h_flex()
 9743                        .px_2()
 9744                        .gap_2()
 9745                        .flex_1()
 9746                        .child(Icon::new(IconName::ZedPredict))
 9747                        .child(Label::new(format!("Jump to {file_name}"))),
 9748                )
 9749            }
 9750            EditPrediction::Edit {
 9751                edits,
 9752                edit_preview,
 9753                snapshot,
 9754                display_mode: _,
 9755            } => {
 9756                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9757
 9758                let (highlighted_edits, has_more_lines) =
 9759                    if let Some(edit_preview) = edit_preview.as_ref() {
 9760                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9761                            .first_line_preview()
 9762                    } else {
 9763                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9764                    };
 9765
 9766                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9767                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9768
 9769                let preview = h_flex()
 9770                    .gap_1()
 9771                    .min_w_16()
 9772                    .child(styled_text)
 9773                    .when(has_more_lines, |parent| parent.child(""));
 9774
 9775                let left = if supports_jump && first_edit_row != cursor_point.row {
 9776                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9777                        .into_any_element()
 9778                } else {
 9779                    let icon_name =
 9780                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9781                    Icon::new(icon_name).into_any_element()
 9782                };
 9783
 9784                Some(
 9785                    h_flex()
 9786                        .h_full()
 9787                        .flex_1()
 9788                        .gap_2()
 9789                        .pr_1()
 9790                        .overflow_x_hidden()
 9791                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9792                        .child(left)
 9793                        .child(preview),
 9794                )
 9795            }
 9796        }
 9797    }
 9798
 9799    pub fn render_context_menu(
 9800        &self,
 9801        style: &EditorStyle,
 9802        max_height_in_lines: u32,
 9803        window: &mut Window,
 9804        cx: &mut Context<Editor>,
 9805    ) -> Option<AnyElement> {
 9806        let menu = self.context_menu.borrow();
 9807        let menu = menu.as_ref()?;
 9808        if !menu.visible() {
 9809            return None;
 9810        };
 9811        Some(menu.render(style, max_height_in_lines, window, cx))
 9812    }
 9813
 9814    fn render_context_menu_aside(
 9815        &mut self,
 9816        max_size: Size<Pixels>,
 9817        window: &mut Window,
 9818        cx: &mut Context<Editor>,
 9819    ) -> Option<AnyElement> {
 9820        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9821            if menu.visible() {
 9822                menu.render_aside(max_size, window, cx)
 9823            } else {
 9824                None
 9825            }
 9826        })
 9827    }
 9828
 9829    fn hide_context_menu(
 9830        &mut self,
 9831        window: &mut Window,
 9832        cx: &mut Context<Self>,
 9833    ) -> Option<CodeContextMenu> {
 9834        cx.notify();
 9835        self.completion_tasks.clear();
 9836        let context_menu = self.context_menu.borrow_mut().take();
 9837        self.stale_edit_prediction_in_menu.take();
 9838        self.update_visible_edit_prediction(window, cx);
 9839        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9840            && let Some(completion_provider) = &self.completion_provider
 9841        {
 9842            completion_provider.selection_changed(None, window, cx);
 9843        }
 9844        context_menu
 9845    }
 9846
 9847    fn show_snippet_choices(
 9848        &mut self,
 9849        choices: &Vec<String>,
 9850        selection: Range<Anchor>,
 9851        cx: &mut Context<Self>,
 9852    ) {
 9853        let Some((_, buffer, _)) = self
 9854            .buffer()
 9855            .read(cx)
 9856            .excerpt_containing(selection.start, cx)
 9857        else {
 9858            return;
 9859        };
 9860        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9861        else {
 9862            return;
 9863        };
 9864        if buffer != end_buffer {
 9865            log::error!("expected anchor range to have matching buffer IDs");
 9866            return;
 9867        }
 9868
 9869        let id = post_inc(&mut self.next_completion_id);
 9870        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9871        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9872            CompletionsMenu::new_snippet_choices(
 9873                id,
 9874                true,
 9875                choices,
 9876                selection,
 9877                buffer,
 9878                snippet_sort_order,
 9879            ),
 9880        ));
 9881    }
 9882
 9883    pub fn insert_snippet(
 9884        &mut self,
 9885        insertion_ranges: &[Range<MultiBufferOffset>],
 9886        snippet: Snippet,
 9887        window: &mut Window,
 9888        cx: &mut Context<Self>,
 9889    ) -> Result<()> {
 9890        struct Tabstop<T> {
 9891            is_end_tabstop: bool,
 9892            ranges: Vec<Range<T>>,
 9893            choices: Option<Vec<String>>,
 9894        }
 9895
 9896        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9897            let snippet_text: Arc<str> = snippet.text.clone().into();
 9898            let edits = insertion_ranges
 9899                .iter()
 9900                .cloned()
 9901                .map(|range| (range, snippet_text.clone()));
 9902            let autoindent_mode = AutoindentMode::Block {
 9903                original_indent_columns: Vec::new(),
 9904            };
 9905            buffer.edit(edits, Some(autoindent_mode), cx);
 9906
 9907            let snapshot = &*buffer.read(cx);
 9908            let snippet = &snippet;
 9909            snippet
 9910                .tabstops
 9911                .iter()
 9912                .map(|tabstop| {
 9913                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9914                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9915                    });
 9916                    let mut tabstop_ranges = tabstop
 9917                        .ranges
 9918                        .iter()
 9919                        .flat_map(|tabstop_range| {
 9920                            let mut delta = 0_isize;
 9921                            insertion_ranges.iter().map(move |insertion_range| {
 9922                                let insertion_start = insertion_range.start + delta;
 9923                                delta += snippet.text.len() as isize
 9924                                    - (insertion_range.end - insertion_range.start) as isize;
 9925
 9926                                let start =
 9927                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9928                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9929                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9930                            })
 9931                        })
 9932                        .collect::<Vec<_>>();
 9933                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9934
 9935                    Tabstop {
 9936                        is_end_tabstop,
 9937                        ranges: tabstop_ranges,
 9938                        choices: tabstop.choices.clone(),
 9939                    }
 9940                })
 9941                .collect::<Vec<_>>()
 9942        });
 9943        if let Some(tabstop) = tabstops.first() {
 9944            self.change_selections(Default::default(), window, cx, |s| {
 9945                // Reverse order so that the first range is the newest created selection.
 9946                // Completions will use it and autoscroll will prioritize it.
 9947                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9948            });
 9949
 9950            if let Some(choices) = &tabstop.choices
 9951                && let Some(selection) = tabstop.ranges.first()
 9952            {
 9953                self.show_snippet_choices(choices, selection.clone(), cx)
 9954            }
 9955
 9956            // If we're already at the last tabstop and it's at the end of the snippet,
 9957            // we're done, we don't need to keep the state around.
 9958            if !tabstop.is_end_tabstop {
 9959                let choices = tabstops
 9960                    .iter()
 9961                    .map(|tabstop| tabstop.choices.clone())
 9962                    .collect();
 9963
 9964                let ranges = tabstops
 9965                    .into_iter()
 9966                    .map(|tabstop| tabstop.ranges)
 9967                    .collect::<Vec<_>>();
 9968
 9969                self.snippet_stack.push(SnippetState {
 9970                    active_index: 0,
 9971                    ranges,
 9972                    choices,
 9973                });
 9974            }
 9975
 9976            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9977            if self.autoclose_regions.is_empty() {
 9978                let snapshot = self.buffer.read(cx).snapshot(cx);
 9979                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9980                    let selection_head = selection.head();
 9981                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9982                        continue;
 9983                    };
 9984
 9985                    let mut bracket_pair = None;
 9986                    let max_lookup_length = scope
 9987                        .brackets()
 9988                        .map(|(pair, _)| {
 9989                            pair.start
 9990                                .as_str()
 9991                                .chars()
 9992                                .count()
 9993                                .max(pair.end.as_str().chars().count())
 9994                        })
 9995                        .max();
 9996                    if let Some(max_lookup_length) = max_lookup_length {
 9997                        let next_text = snapshot
 9998                            .chars_at(selection_head)
 9999                            .take(max_lookup_length)
10000                            .collect::<String>();
10001                        let prev_text = snapshot
10002                            .reversed_chars_at(selection_head)
10003                            .take(max_lookup_length)
10004                            .collect::<String>();
10005
10006                        for (pair, enabled) in scope.brackets() {
10007                            if enabled
10008                                && pair.close
10009                                && prev_text.starts_with(pair.start.as_str())
10010                                && next_text.starts_with(pair.end.as_str())
10011                            {
10012                                bracket_pair = Some(pair.clone());
10013                                break;
10014                            }
10015                        }
10016                    }
10017
10018                    if let Some(pair) = bracket_pair {
10019                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10020                        let autoclose_enabled =
10021                            self.use_autoclose && snapshot_settings.use_autoclose;
10022                        if autoclose_enabled {
10023                            let start = snapshot.anchor_after(selection_head);
10024                            let end = snapshot.anchor_after(selection_head);
10025                            self.autoclose_regions.push(AutocloseRegion {
10026                                selection_id: selection.id,
10027                                range: start..end,
10028                                pair,
10029                            });
10030                        }
10031                    }
10032                }
10033            }
10034        }
10035        Ok(())
10036    }
10037
10038    pub fn move_to_next_snippet_tabstop(
10039        &mut self,
10040        window: &mut Window,
10041        cx: &mut Context<Self>,
10042    ) -> bool {
10043        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10044    }
10045
10046    pub fn move_to_prev_snippet_tabstop(
10047        &mut self,
10048        window: &mut Window,
10049        cx: &mut Context<Self>,
10050    ) -> bool {
10051        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10052    }
10053
10054    pub fn move_to_snippet_tabstop(
10055        &mut self,
10056        bias: Bias,
10057        window: &mut Window,
10058        cx: &mut Context<Self>,
10059    ) -> bool {
10060        if let Some(mut snippet) = self.snippet_stack.pop() {
10061            match bias {
10062                Bias::Left => {
10063                    if snippet.active_index > 0 {
10064                        snippet.active_index -= 1;
10065                    } else {
10066                        self.snippet_stack.push(snippet);
10067                        return false;
10068                    }
10069                }
10070                Bias::Right => {
10071                    if snippet.active_index + 1 < snippet.ranges.len() {
10072                        snippet.active_index += 1;
10073                    } else {
10074                        self.snippet_stack.push(snippet);
10075                        return false;
10076                    }
10077                }
10078            }
10079            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10080                self.change_selections(Default::default(), window, cx, |s| {
10081                    // Reverse order so that the first range is the newest created selection.
10082                    // Completions will use it and autoscroll will prioritize it.
10083                    s.select_ranges(current_ranges.iter().rev().cloned())
10084                });
10085
10086                if let Some(choices) = &snippet.choices[snippet.active_index]
10087                    && let Some(selection) = current_ranges.first()
10088                {
10089                    self.show_snippet_choices(choices, selection.clone(), cx);
10090                }
10091
10092                // If snippet state is not at the last tabstop, push it back on the stack
10093                if snippet.active_index + 1 < snippet.ranges.len() {
10094                    self.snippet_stack.push(snippet);
10095                }
10096                return true;
10097            }
10098        }
10099
10100        false
10101    }
10102
10103    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10104        self.transact(window, cx, |this, window, cx| {
10105            this.select_all(&SelectAll, window, cx);
10106            this.insert("", window, cx);
10107        });
10108    }
10109
10110    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10111        if self.read_only(cx) {
10112            return;
10113        }
10114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10115        self.transact(window, cx, |this, window, cx| {
10116            this.select_autoclose_pair(window, cx);
10117
10118            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10119
10120            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10121            if !this.linked_edit_ranges.is_empty() {
10122                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10123                let snapshot = this.buffer.read(cx).snapshot(cx);
10124
10125                for selection in selections.iter() {
10126                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10127                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10128                    if selection_start.buffer_id != selection_end.buffer_id {
10129                        continue;
10130                    }
10131                    if let Some(ranges) =
10132                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10133                    {
10134                        for (buffer, entries) in ranges {
10135                            linked_ranges.entry(buffer).or_default().extend(entries);
10136                        }
10137                    }
10138                }
10139            }
10140
10141            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10142            for selection in &mut selections {
10143                if selection.is_empty() {
10144                    let old_head = selection.head();
10145                    let mut new_head =
10146                        movement::left(&display_map, old_head.to_display_point(&display_map))
10147                            .to_point(&display_map);
10148                    if let Some((buffer, line_buffer_range)) = display_map
10149                        .buffer_snapshot()
10150                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10151                    {
10152                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10153                        let indent_len = match indent_size.kind {
10154                            IndentKind::Space => {
10155                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10156                            }
10157                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10158                        };
10159                        if old_head.column <= indent_size.len && old_head.column > 0 {
10160                            let indent_len = indent_len.get();
10161                            new_head = cmp::min(
10162                                new_head,
10163                                MultiBufferPoint::new(
10164                                    old_head.row,
10165                                    ((old_head.column - 1) / indent_len) * indent_len,
10166                                ),
10167                            );
10168                        }
10169                    }
10170
10171                    selection.set_head(new_head, SelectionGoal::None);
10172                }
10173            }
10174
10175            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10176            this.insert("", window, cx);
10177            let empty_str: Arc<str> = Arc::from("");
10178            for (buffer, edits) in linked_ranges {
10179                let snapshot = buffer.read(cx).snapshot();
10180                use text::ToPoint as TP;
10181
10182                let edits = edits
10183                    .into_iter()
10184                    .map(|range| {
10185                        let end_point = TP::to_point(&range.end, &snapshot);
10186                        let mut start_point = TP::to_point(&range.start, &snapshot);
10187
10188                        if end_point == start_point {
10189                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10190                                .saturating_sub(1);
10191                            start_point =
10192                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10193                        };
10194
10195                        (start_point..end_point, empty_str.clone())
10196                    })
10197                    .sorted_by_key(|(range, _)| range.start)
10198                    .collect::<Vec<_>>();
10199                buffer.update(cx, |this, cx| {
10200                    this.edit(edits, None, cx);
10201                })
10202            }
10203            this.refresh_edit_prediction(true, false, window, cx);
10204            refresh_linked_ranges(this, window, cx);
10205        });
10206    }
10207
10208    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10209        if self.read_only(cx) {
10210            return;
10211        }
10212        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10213        self.transact(window, cx, |this, window, cx| {
10214            this.change_selections(Default::default(), window, cx, |s| {
10215                s.move_with(|map, selection| {
10216                    if selection.is_empty() {
10217                        let cursor = movement::right(map, selection.head());
10218                        selection.end = cursor;
10219                        selection.reversed = true;
10220                        selection.goal = SelectionGoal::None;
10221                    }
10222                })
10223            });
10224            this.insert("", window, cx);
10225            this.refresh_edit_prediction(true, false, window, cx);
10226        });
10227    }
10228
10229    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10230        if self.mode.is_single_line() {
10231            cx.propagate();
10232            return;
10233        }
10234
10235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10236        if self.move_to_prev_snippet_tabstop(window, cx) {
10237            return;
10238        }
10239        self.outdent(&Outdent, window, cx);
10240    }
10241
10242    pub fn next_snippet_tabstop(
10243        &mut self,
10244        _: &NextSnippetTabstop,
10245        window: &mut Window,
10246        cx: &mut Context<Self>,
10247    ) {
10248        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10249            cx.propagate();
10250            return;
10251        }
10252
10253        if self.move_to_next_snippet_tabstop(window, cx) {
10254            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10255            return;
10256        }
10257        cx.propagate();
10258    }
10259
10260    pub fn previous_snippet_tabstop(
10261        &mut self,
10262        _: &PreviousSnippetTabstop,
10263        window: &mut Window,
10264        cx: &mut Context<Self>,
10265    ) {
10266        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10267            cx.propagate();
10268            return;
10269        }
10270
10271        if self.move_to_prev_snippet_tabstop(window, cx) {
10272            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10273            return;
10274        }
10275        cx.propagate();
10276    }
10277
10278    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10279        if self.mode.is_single_line() {
10280            cx.propagate();
10281            return;
10282        }
10283
10284        if self.move_to_next_snippet_tabstop(window, cx) {
10285            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10286            return;
10287        }
10288        if self.read_only(cx) {
10289            return;
10290        }
10291        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10292        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10293        let buffer = self.buffer.read(cx);
10294        let snapshot = buffer.snapshot(cx);
10295        let rows_iter = selections.iter().map(|s| s.head().row);
10296        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10297
10298        let has_some_cursor_in_whitespace = selections
10299            .iter()
10300            .filter(|selection| selection.is_empty())
10301            .any(|selection| {
10302                let cursor = selection.head();
10303                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10304                cursor.column < current_indent.len
10305            });
10306
10307        let mut edits = Vec::new();
10308        let mut prev_edited_row = 0;
10309        let mut row_delta = 0;
10310        for selection in &mut selections {
10311            if selection.start.row != prev_edited_row {
10312                row_delta = 0;
10313            }
10314            prev_edited_row = selection.end.row;
10315
10316            // If the selection is non-empty, then increase the indentation of the selected lines.
10317            if !selection.is_empty() {
10318                row_delta =
10319                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10320                continue;
10321            }
10322
10323            let cursor = selection.head();
10324            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10325            if let Some(suggested_indent) =
10326                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10327            {
10328                // Don't do anything if already at suggested indent
10329                // and there is any other cursor which is not
10330                if has_some_cursor_in_whitespace
10331                    && cursor.column == current_indent.len
10332                    && current_indent.len == suggested_indent.len
10333                {
10334                    continue;
10335                }
10336
10337                // Adjust line and move cursor to suggested indent
10338                // if cursor is not at suggested indent
10339                if cursor.column < suggested_indent.len
10340                    && cursor.column <= current_indent.len
10341                    && current_indent.len <= suggested_indent.len
10342                {
10343                    selection.start = Point::new(cursor.row, suggested_indent.len);
10344                    selection.end = selection.start;
10345                    if row_delta == 0 {
10346                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10347                            cursor.row,
10348                            current_indent,
10349                            suggested_indent,
10350                        ));
10351                        row_delta = suggested_indent.len - current_indent.len;
10352                    }
10353                    continue;
10354                }
10355
10356                // If current indent is more than suggested indent
10357                // only move cursor to current indent and skip indent
10358                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10359                    selection.start = Point::new(cursor.row, current_indent.len);
10360                    selection.end = selection.start;
10361                    continue;
10362                }
10363            }
10364
10365            // Otherwise, insert a hard or soft tab.
10366            let settings = buffer.language_settings_at(cursor, cx);
10367            let tab_size = if settings.hard_tabs {
10368                IndentSize::tab()
10369            } else {
10370                let tab_size = settings.tab_size.get();
10371                let indent_remainder = snapshot
10372                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10373                    .flat_map(str::chars)
10374                    .fold(row_delta % tab_size, |counter: u32, c| {
10375                        if c == '\t' {
10376                            0
10377                        } else {
10378                            (counter + 1) % tab_size
10379                        }
10380                    });
10381
10382                let chars_to_next_tab_stop = tab_size - indent_remainder;
10383                IndentSize::spaces(chars_to_next_tab_stop)
10384            };
10385            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10386            selection.end = selection.start;
10387            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10388            row_delta += tab_size.len;
10389        }
10390
10391        self.transact(window, cx, |this, window, cx| {
10392            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10393            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10394            this.refresh_edit_prediction(true, false, window, cx);
10395        });
10396    }
10397
10398    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10399        if self.read_only(cx) {
10400            return;
10401        }
10402        if self.mode.is_single_line() {
10403            cx.propagate();
10404            return;
10405        }
10406
10407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10408        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10409        let mut prev_edited_row = 0;
10410        let mut row_delta = 0;
10411        let mut edits = Vec::new();
10412        let buffer = self.buffer.read(cx);
10413        let snapshot = buffer.snapshot(cx);
10414        for selection in &mut selections {
10415            if selection.start.row != prev_edited_row {
10416                row_delta = 0;
10417            }
10418            prev_edited_row = selection.end.row;
10419
10420            row_delta =
10421                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10422        }
10423
10424        self.transact(window, cx, |this, window, cx| {
10425            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10426            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10427        });
10428    }
10429
10430    fn indent_selection(
10431        buffer: &MultiBuffer,
10432        snapshot: &MultiBufferSnapshot,
10433        selection: &mut Selection<Point>,
10434        edits: &mut Vec<(Range<Point>, String)>,
10435        delta_for_start_row: u32,
10436        cx: &App,
10437    ) -> u32 {
10438        let settings = buffer.language_settings_at(selection.start, cx);
10439        let tab_size = settings.tab_size.get();
10440        let indent_kind = if settings.hard_tabs {
10441            IndentKind::Tab
10442        } else {
10443            IndentKind::Space
10444        };
10445        let mut start_row = selection.start.row;
10446        let mut end_row = selection.end.row + 1;
10447
10448        // If a selection ends at the beginning of a line, don't indent
10449        // that last line.
10450        if selection.end.column == 0 && selection.end.row > selection.start.row {
10451            end_row -= 1;
10452        }
10453
10454        // Avoid re-indenting a row that has already been indented by a
10455        // previous selection, but still update this selection's column
10456        // to reflect that indentation.
10457        if delta_for_start_row > 0 {
10458            start_row += 1;
10459            selection.start.column += delta_for_start_row;
10460            if selection.end.row == selection.start.row {
10461                selection.end.column += delta_for_start_row;
10462            }
10463        }
10464
10465        let mut delta_for_end_row = 0;
10466        let has_multiple_rows = start_row + 1 != end_row;
10467        for row in start_row..end_row {
10468            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10469            let indent_delta = match (current_indent.kind, indent_kind) {
10470                (IndentKind::Space, IndentKind::Space) => {
10471                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10472                    IndentSize::spaces(columns_to_next_tab_stop)
10473                }
10474                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10475                (_, IndentKind::Tab) => IndentSize::tab(),
10476            };
10477
10478            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10479                0
10480            } else {
10481                selection.start.column
10482            };
10483            let row_start = Point::new(row, start);
10484            edits.push((
10485                row_start..row_start,
10486                indent_delta.chars().collect::<String>(),
10487            ));
10488
10489            // Update this selection's endpoints to reflect the indentation.
10490            if row == selection.start.row {
10491                selection.start.column += indent_delta.len;
10492            }
10493            if row == selection.end.row {
10494                selection.end.column += indent_delta.len;
10495                delta_for_end_row = indent_delta.len;
10496            }
10497        }
10498
10499        if selection.start.row == selection.end.row {
10500            delta_for_start_row + delta_for_end_row
10501        } else {
10502            delta_for_end_row
10503        }
10504    }
10505
10506    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10507        if self.read_only(cx) {
10508            return;
10509        }
10510        if self.mode.is_single_line() {
10511            cx.propagate();
10512            return;
10513        }
10514
10515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10517        let selections = self.selections.all::<Point>(&display_map);
10518        let mut deletion_ranges = Vec::new();
10519        let mut last_outdent = None;
10520        {
10521            let buffer = self.buffer.read(cx);
10522            let snapshot = buffer.snapshot(cx);
10523            for selection in &selections {
10524                let settings = buffer.language_settings_at(selection.start, cx);
10525                let tab_size = settings.tab_size.get();
10526                let mut rows = selection.spanned_rows(false, &display_map);
10527
10528                // Avoid re-outdenting a row that has already been outdented by a
10529                // previous selection.
10530                if let Some(last_row) = last_outdent
10531                    && last_row == rows.start
10532                {
10533                    rows.start = rows.start.next_row();
10534                }
10535                let has_multiple_rows = rows.len() > 1;
10536                for row in rows.iter_rows() {
10537                    let indent_size = snapshot.indent_size_for_line(row);
10538                    if indent_size.len > 0 {
10539                        let deletion_len = match indent_size.kind {
10540                            IndentKind::Space => {
10541                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10542                                if columns_to_prev_tab_stop == 0 {
10543                                    tab_size
10544                                } else {
10545                                    columns_to_prev_tab_stop
10546                                }
10547                            }
10548                            IndentKind::Tab => 1,
10549                        };
10550                        let start = if has_multiple_rows
10551                            || deletion_len > selection.start.column
10552                            || indent_size.len < selection.start.column
10553                        {
10554                            0
10555                        } else {
10556                            selection.start.column - deletion_len
10557                        };
10558                        deletion_ranges.push(
10559                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10560                        );
10561                        last_outdent = Some(row);
10562                    }
10563                }
10564            }
10565        }
10566
10567        self.transact(window, cx, |this, window, cx| {
10568            this.buffer.update(cx, |buffer, cx| {
10569                let empty_str: Arc<str> = Arc::default();
10570                buffer.edit(
10571                    deletion_ranges
10572                        .into_iter()
10573                        .map(|range| (range, empty_str.clone())),
10574                    None,
10575                    cx,
10576                );
10577            });
10578            let selections = this
10579                .selections
10580                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10581            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10582        });
10583    }
10584
10585    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10586        if self.read_only(cx) {
10587            return;
10588        }
10589        if self.mode.is_single_line() {
10590            cx.propagate();
10591            return;
10592        }
10593
10594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10595        let selections = self
10596            .selections
10597            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10598            .into_iter()
10599            .map(|s| s.range());
10600
10601        self.transact(window, cx, |this, window, cx| {
10602            this.buffer.update(cx, |buffer, cx| {
10603                buffer.autoindent_ranges(selections, cx);
10604            });
10605            let selections = this
10606                .selections
10607                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10608            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10609        });
10610    }
10611
10612    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10614        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10615        let selections = self.selections.all::<Point>(&display_map);
10616
10617        let mut new_cursors = Vec::new();
10618        let mut edit_ranges = Vec::new();
10619        let mut selections = selections.iter().peekable();
10620        while let Some(selection) = selections.next() {
10621            let mut rows = selection.spanned_rows(false, &display_map);
10622
10623            // Accumulate contiguous regions of rows that we want to delete.
10624            while let Some(next_selection) = selections.peek() {
10625                let next_rows = next_selection.spanned_rows(false, &display_map);
10626                if next_rows.start <= rows.end {
10627                    rows.end = next_rows.end;
10628                    selections.next().unwrap();
10629                } else {
10630                    break;
10631                }
10632            }
10633
10634            let buffer = display_map.buffer_snapshot();
10635            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10636            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10637                // If there's a line after the range, delete the \n from the end of the row range
10638                (
10639                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10640                    rows.end,
10641                )
10642            } else {
10643                // If there isn't a line after the range, delete the \n from the line before the
10644                // start of the row range
10645                edit_start = edit_start.saturating_sub_usize(1);
10646                (buffer.len(), rows.start.previous_row())
10647            };
10648
10649            let text_layout_details = self.text_layout_details(window);
10650            let x = display_map.x_for_display_point(
10651                selection.head().to_display_point(&display_map),
10652                &text_layout_details,
10653            );
10654            let row = Point::new(target_row.0, 0)
10655                .to_display_point(&display_map)
10656                .row();
10657            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10658
10659            new_cursors.push((
10660                selection.id,
10661                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10662                SelectionGoal::None,
10663            ));
10664            edit_ranges.push(edit_start..edit_end);
10665        }
10666
10667        self.transact(window, cx, |this, window, cx| {
10668            let buffer = this.buffer.update(cx, |buffer, cx| {
10669                let empty_str: Arc<str> = Arc::default();
10670                buffer.edit(
10671                    edit_ranges
10672                        .into_iter()
10673                        .map(|range| (range, empty_str.clone())),
10674                    None,
10675                    cx,
10676                );
10677                buffer.snapshot(cx)
10678            });
10679            let new_selections = new_cursors
10680                .into_iter()
10681                .map(|(id, cursor, goal)| {
10682                    let cursor = cursor.to_point(&buffer);
10683                    Selection {
10684                        id,
10685                        start: cursor,
10686                        end: cursor,
10687                        reversed: false,
10688                        goal,
10689                    }
10690                })
10691                .collect();
10692
10693            this.change_selections(Default::default(), window, cx, |s| {
10694                s.select(new_selections);
10695            });
10696        });
10697    }
10698
10699    pub fn join_lines_impl(
10700        &mut self,
10701        insert_whitespace: bool,
10702        window: &mut Window,
10703        cx: &mut Context<Self>,
10704    ) {
10705        if self.read_only(cx) {
10706            return;
10707        }
10708        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10709        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10710            let start = MultiBufferRow(selection.start.row);
10711            // Treat single line selections as if they include the next line. Otherwise this action
10712            // would do nothing for single line selections individual cursors.
10713            let end = if selection.start.row == selection.end.row {
10714                MultiBufferRow(selection.start.row + 1)
10715            } else {
10716                MultiBufferRow(selection.end.row)
10717            };
10718
10719            if let Some(last_row_range) = row_ranges.last_mut()
10720                && start <= last_row_range.end
10721            {
10722                last_row_range.end = end;
10723                continue;
10724            }
10725            row_ranges.push(start..end);
10726        }
10727
10728        let snapshot = self.buffer.read(cx).snapshot(cx);
10729        let mut cursor_positions = Vec::new();
10730        for row_range in &row_ranges {
10731            let anchor = snapshot.anchor_before(Point::new(
10732                row_range.end.previous_row().0,
10733                snapshot.line_len(row_range.end.previous_row()),
10734            ));
10735            cursor_positions.push(anchor..anchor);
10736        }
10737
10738        self.transact(window, cx, |this, window, cx| {
10739            for row_range in row_ranges.into_iter().rev() {
10740                for row in row_range.iter_rows().rev() {
10741                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10742                    let next_line_row = row.next_row();
10743                    let indent = snapshot.indent_size_for_line(next_line_row);
10744                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10745
10746                    let replace =
10747                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10748                            " "
10749                        } else {
10750                            ""
10751                        };
10752
10753                    this.buffer.update(cx, |buffer, cx| {
10754                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10755                    });
10756                }
10757            }
10758
10759            this.change_selections(Default::default(), window, cx, |s| {
10760                s.select_anchor_ranges(cursor_positions)
10761            });
10762        });
10763    }
10764
10765    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10767        self.join_lines_impl(true, window, cx);
10768    }
10769
10770    pub fn sort_lines_case_sensitive(
10771        &mut self,
10772        _: &SortLinesCaseSensitive,
10773        window: &mut Window,
10774        cx: &mut Context<Self>,
10775    ) {
10776        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10777    }
10778
10779    pub fn sort_lines_by_length(
10780        &mut self,
10781        _: &SortLinesByLength,
10782        window: &mut Window,
10783        cx: &mut Context<Self>,
10784    ) {
10785        self.manipulate_immutable_lines(window, cx, |lines| {
10786            lines.sort_by_key(|&line| line.chars().count())
10787        })
10788    }
10789
10790    pub fn sort_lines_case_insensitive(
10791        &mut self,
10792        _: &SortLinesCaseInsensitive,
10793        window: &mut Window,
10794        cx: &mut Context<Self>,
10795    ) {
10796        self.manipulate_immutable_lines(window, cx, |lines| {
10797            lines.sort_by_key(|line| line.to_lowercase())
10798        })
10799    }
10800
10801    pub fn unique_lines_case_insensitive(
10802        &mut self,
10803        _: &UniqueLinesCaseInsensitive,
10804        window: &mut Window,
10805        cx: &mut Context<Self>,
10806    ) {
10807        self.manipulate_immutable_lines(window, cx, |lines| {
10808            let mut seen = HashSet::default();
10809            lines.retain(|line| seen.insert(line.to_lowercase()));
10810        })
10811    }
10812
10813    pub fn unique_lines_case_sensitive(
10814        &mut self,
10815        _: &UniqueLinesCaseSensitive,
10816        window: &mut Window,
10817        cx: &mut Context<Self>,
10818    ) {
10819        self.manipulate_immutable_lines(window, cx, |lines| {
10820            let mut seen = HashSet::default();
10821            lines.retain(|line| seen.insert(*line));
10822        })
10823    }
10824
10825    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10826        let snapshot = self.buffer.read(cx).snapshot(cx);
10827        for selection in self.selections.disjoint_anchors_arc().iter() {
10828            if snapshot
10829                .language_at(selection.start)
10830                .and_then(|lang| lang.config().wrap_characters.as_ref())
10831                .is_some()
10832            {
10833                return true;
10834            }
10835        }
10836        false
10837    }
10838
10839    fn wrap_selections_in_tag(
10840        &mut self,
10841        _: &WrapSelectionsInTag,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) {
10845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10846
10847        let snapshot = self.buffer.read(cx).snapshot(cx);
10848
10849        let mut edits = Vec::new();
10850        let mut boundaries = Vec::new();
10851
10852        for selection in self
10853            .selections
10854            .all_adjusted(&self.display_snapshot(cx))
10855            .iter()
10856        {
10857            let Some(wrap_config) = snapshot
10858                .language_at(selection.start)
10859                .and_then(|lang| lang.config().wrap_characters.clone())
10860            else {
10861                continue;
10862            };
10863
10864            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10865            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10866
10867            let start_before = snapshot.anchor_before(selection.start);
10868            let end_after = snapshot.anchor_after(selection.end);
10869
10870            edits.push((start_before..start_before, open_tag));
10871            edits.push((end_after..end_after, close_tag));
10872
10873            boundaries.push((
10874                start_before,
10875                end_after,
10876                wrap_config.start_prefix.len(),
10877                wrap_config.end_suffix.len(),
10878            ));
10879        }
10880
10881        if edits.is_empty() {
10882            return;
10883        }
10884
10885        self.transact(window, cx, |this, window, cx| {
10886            let buffer = this.buffer.update(cx, |buffer, cx| {
10887                buffer.edit(edits, None, cx);
10888                buffer.snapshot(cx)
10889            });
10890
10891            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10892            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10893                boundaries.into_iter()
10894            {
10895                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10896                let close_offset = end_after
10897                    .to_offset(&buffer)
10898                    .saturating_sub_usize(end_suffix_len);
10899                new_selections.push(open_offset..open_offset);
10900                new_selections.push(close_offset..close_offset);
10901            }
10902
10903            this.change_selections(Default::default(), window, cx, |s| {
10904                s.select_ranges(new_selections);
10905            });
10906
10907            this.request_autoscroll(Autoscroll::fit(), cx);
10908        });
10909    }
10910
10911    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10912        let Some(project) = self.project.clone() else {
10913            return;
10914        };
10915        self.reload(project, window, cx)
10916            .detach_and_notify_err(window, cx);
10917    }
10918
10919    pub fn restore_file(
10920        &mut self,
10921        _: &::git::RestoreFile,
10922        window: &mut Window,
10923        cx: &mut Context<Self>,
10924    ) {
10925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10926        let mut buffer_ids = HashSet::default();
10927        let snapshot = self.buffer().read(cx).snapshot(cx);
10928        for selection in self
10929            .selections
10930            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10931        {
10932            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10933        }
10934
10935        let buffer = self.buffer().read(cx);
10936        let ranges = buffer_ids
10937            .into_iter()
10938            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10939            .collect::<Vec<_>>();
10940
10941        self.restore_hunks_in_ranges(ranges, window, cx);
10942    }
10943
10944    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10946        let selections = self
10947            .selections
10948            .all(&self.display_snapshot(cx))
10949            .into_iter()
10950            .map(|s| s.range())
10951            .collect();
10952        self.restore_hunks_in_ranges(selections, window, cx);
10953    }
10954
10955    pub fn restore_hunks_in_ranges(
10956        &mut self,
10957        ranges: Vec<Range<Point>>,
10958        window: &mut Window,
10959        cx: &mut Context<Editor>,
10960    ) {
10961        let mut revert_changes = HashMap::default();
10962        let chunk_by = self
10963            .snapshot(window, cx)
10964            .hunks_for_ranges(ranges)
10965            .into_iter()
10966            .chunk_by(|hunk| hunk.buffer_id);
10967        for (buffer_id, hunks) in &chunk_by {
10968            let hunks = hunks.collect::<Vec<_>>();
10969            for hunk in &hunks {
10970                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10971            }
10972            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10973        }
10974        drop(chunk_by);
10975        if !revert_changes.is_empty() {
10976            self.transact(window, cx, |editor, window, cx| {
10977                editor.restore(revert_changes, window, cx);
10978            });
10979        }
10980    }
10981
10982    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10983        if let Some(status) = self
10984            .addons
10985            .iter()
10986            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10987        {
10988            return Some(status);
10989        }
10990        self.project
10991            .as_ref()?
10992            .read(cx)
10993            .status_for_buffer_id(buffer_id, cx)
10994    }
10995
10996    pub fn open_active_item_in_terminal(
10997        &mut self,
10998        _: &OpenInTerminal,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001    ) {
11002        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11003            let project_path = buffer.read(cx).project_path(cx)?;
11004            let project = self.project()?.read(cx);
11005            let entry = project.entry_for_path(&project_path, cx)?;
11006            let parent = match &entry.canonical_path {
11007                Some(canonical_path) => canonical_path.to_path_buf(),
11008                None => project.absolute_path(&project_path, cx)?,
11009            }
11010            .parent()?
11011            .to_path_buf();
11012            Some(parent)
11013        }) {
11014            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11015        }
11016    }
11017
11018    fn set_breakpoint_context_menu(
11019        &mut self,
11020        display_row: DisplayRow,
11021        position: Option<Anchor>,
11022        clicked_point: gpui::Point<Pixels>,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025    ) {
11026        let source = self
11027            .buffer
11028            .read(cx)
11029            .snapshot(cx)
11030            .anchor_before(Point::new(display_row.0, 0u32));
11031
11032        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11033
11034        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11035            self,
11036            source,
11037            clicked_point,
11038            context_menu,
11039            window,
11040            cx,
11041        );
11042    }
11043
11044    fn add_edit_breakpoint_block(
11045        &mut self,
11046        anchor: Anchor,
11047        breakpoint: &Breakpoint,
11048        edit_action: BreakpointPromptEditAction,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        let weak_editor = cx.weak_entity();
11053        let bp_prompt = cx.new(|cx| {
11054            BreakpointPromptEditor::new(
11055                weak_editor,
11056                anchor,
11057                breakpoint.clone(),
11058                edit_action,
11059                window,
11060                cx,
11061            )
11062        });
11063
11064        let height = bp_prompt.update(cx, |this, cx| {
11065            this.prompt
11066                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11067        });
11068        let cloned_prompt = bp_prompt.clone();
11069        let blocks = vec![BlockProperties {
11070            style: BlockStyle::Sticky,
11071            placement: BlockPlacement::Above(anchor),
11072            height: Some(height),
11073            render: Arc::new(move |cx| {
11074                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11075                cloned_prompt.clone().into_any_element()
11076            }),
11077            priority: 0,
11078        }];
11079
11080        let focus_handle = bp_prompt.focus_handle(cx);
11081        window.focus(&focus_handle);
11082
11083        let block_ids = self.insert_blocks(blocks, None, cx);
11084        bp_prompt.update(cx, |prompt, _| {
11085            prompt.add_block_ids(block_ids);
11086        });
11087    }
11088
11089    pub(crate) fn breakpoint_at_row(
11090        &self,
11091        row: u32,
11092        window: &mut Window,
11093        cx: &mut Context<Self>,
11094    ) -> Option<(Anchor, Breakpoint)> {
11095        let snapshot = self.snapshot(window, cx);
11096        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11097
11098        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11099    }
11100
11101    pub(crate) fn breakpoint_at_anchor(
11102        &self,
11103        breakpoint_position: Anchor,
11104        snapshot: &EditorSnapshot,
11105        cx: &mut Context<Self>,
11106    ) -> Option<(Anchor, Breakpoint)> {
11107        let buffer = self
11108            .buffer
11109            .read(cx)
11110            .buffer_for_anchor(breakpoint_position, cx)?;
11111
11112        let enclosing_excerpt = breakpoint_position.excerpt_id;
11113        let buffer_snapshot = buffer.read(cx).snapshot();
11114
11115        let row = buffer_snapshot
11116            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11117            .row;
11118
11119        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11120        let anchor_end = snapshot
11121            .buffer_snapshot()
11122            .anchor_after(Point::new(row, line_len));
11123
11124        self.breakpoint_store
11125            .as_ref()?
11126            .read_with(cx, |breakpoint_store, cx| {
11127                breakpoint_store
11128                    .breakpoints(
11129                        &buffer,
11130                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11131                        &buffer_snapshot,
11132                        cx,
11133                    )
11134                    .next()
11135                    .and_then(|(bp, _)| {
11136                        let breakpoint_row = buffer_snapshot
11137                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11138                            .row;
11139
11140                        if breakpoint_row == row {
11141                            snapshot
11142                                .buffer_snapshot()
11143                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11144                                .map(|position| (position, bp.bp.clone()))
11145                        } else {
11146                            None
11147                        }
11148                    })
11149            })
11150    }
11151
11152    pub fn edit_log_breakpoint(
11153        &mut self,
11154        _: &EditLogBreakpoint,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        if self.breakpoint_store.is_none() {
11159            return;
11160        }
11161
11162        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11163            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11164                message: None,
11165                state: BreakpointState::Enabled,
11166                condition: None,
11167                hit_condition: None,
11168            });
11169
11170            self.add_edit_breakpoint_block(
11171                anchor,
11172                &breakpoint,
11173                BreakpointPromptEditAction::Log,
11174                window,
11175                cx,
11176            );
11177        }
11178    }
11179
11180    fn breakpoints_at_cursors(
11181        &self,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11185        let snapshot = self.snapshot(window, cx);
11186        let cursors = self
11187            .selections
11188            .disjoint_anchors_arc()
11189            .iter()
11190            .map(|selection| {
11191                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11192
11193                let breakpoint_position = self
11194                    .breakpoint_at_row(cursor_position.row, window, cx)
11195                    .map(|bp| bp.0)
11196                    .unwrap_or_else(|| {
11197                        snapshot
11198                            .display_snapshot
11199                            .buffer_snapshot()
11200                            .anchor_after(Point::new(cursor_position.row, 0))
11201                    });
11202
11203                let breakpoint = self
11204                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11205                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11206
11207                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11208            })
11209            // 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.
11210            .collect::<HashMap<Anchor, _>>();
11211
11212        cursors.into_iter().collect()
11213    }
11214
11215    pub fn enable_breakpoint(
11216        &mut self,
11217        _: &crate::actions::EnableBreakpoint,
11218        window: &mut Window,
11219        cx: &mut Context<Self>,
11220    ) {
11221        if self.breakpoint_store.is_none() {
11222            return;
11223        }
11224
11225        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11226            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11227                continue;
11228            };
11229            self.edit_breakpoint_at_anchor(
11230                anchor,
11231                breakpoint,
11232                BreakpointEditAction::InvertState,
11233                cx,
11234            );
11235        }
11236    }
11237
11238    pub fn disable_breakpoint(
11239        &mut self,
11240        _: &crate::actions::DisableBreakpoint,
11241        window: &mut Window,
11242        cx: &mut Context<Self>,
11243    ) {
11244        if self.breakpoint_store.is_none() {
11245            return;
11246        }
11247
11248        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11249            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11250                continue;
11251            };
11252            self.edit_breakpoint_at_anchor(
11253                anchor,
11254                breakpoint,
11255                BreakpointEditAction::InvertState,
11256                cx,
11257            );
11258        }
11259    }
11260
11261    pub fn toggle_breakpoint(
11262        &mut self,
11263        _: &crate::actions::ToggleBreakpoint,
11264        window: &mut Window,
11265        cx: &mut Context<Self>,
11266    ) {
11267        if self.breakpoint_store.is_none() {
11268            return;
11269        }
11270
11271        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11272            if let Some(breakpoint) = breakpoint {
11273                self.edit_breakpoint_at_anchor(
11274                    anchor,
11275                    breakpoint,
11276                    BreakpointEditAction::Toggle,
11277                    cx,
11278                );
11279            } else {
11280                self.edit_breakpoint_at_anchor(
11281                    anchor,
11282                    Breakpoint::new_standard(),
11283                    BreakpointEditAction::Toggle,
11284                    cx,
11285                );
11286            }
11287        }
11288    }
11289
11290    pub fn edit_breakpoint_at_anchor(
11291        &mut self,
11292        breakpoint_position: Anchor,
11293        breakpoint: Breakpoint,
11294        edit_action: BreakpointEditAction,
11295        cx: &mut Context<Self>,
11296    ) {
11297        let Some(breakpoint_store) = &self.breakpoint_store else {
11298            return;
11299        };
11300
11301        let Some(buffer) = self
11302            .buffer
11303            .read(cx)
11304            .buffer_for_anchor(breakpoint_position, cx)
11305        else {
11306            return;
11307        };
11308
11309        breakpoint_store.update(cx, |breakpoint_store, cx| {
11310            breakpoint_store.toggle_breakpoint(
11311                buffer,
11312                BreakpointWithPosition {
11313                    position: breakpoint_position.text_anchor,
11314                    bp: breakpoint,
11315                },
11316                edit_action,
11317                cx,
11318            );
11319        });
11320
11321        cx.notify();
11322    }
11323
11324    #[cfg(any(test, feature = "test-support"))]
11325    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11326        self.breakpoint_store.clone()
11327    }
11328
11329    pub fn prepare_restore_change(
11330        &self,
11331        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11332        hunk: &MultiBufferDiffHunk,
11333        cx: &mut App,
11334    ) -> Option<()> {
11335        if hunk.is_created_file() {
11336            return None;
11337        }
11338        let buffer = self.buffer.read(cx);
11339        let diff = buffer.diff_for(hunk.buffer_id)?;
11340        let buffer = buffer.buffer(hunk.buffer_id)?;
11341        let buffer = buffer.read(cx);
11342        let original_text = diff
11343            .read(cx)
11344            .base_text()
11345            .as_rope()
11346            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11347        let buffer_snapshot = buffer.snapshot();
11348        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11349        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11350            probe
11351                .0
11352                .start
11353                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11354                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11355        }) {
11356            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11357            Some(())
11358        } else {
11359            None
11360        }
11361    }
11362
11363    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11364        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11365    }
11366
11367    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11368        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11369    }
11370
11371    fn manipulate_lines<M>(
11372        &mut self,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375        mut manipulate: M,
11376    ) where
11377        M: FnMut(&str) -> LineManipulationResult,
11378    {
11379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11380
11381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11382        let buffer = self.buffer.read(cx).snapshot(cx);
11383
11384        let mut edits = Vec::new();
11385
11386        let selections = self.selections.all::<Point>(&display_map);
11387        let mut selections = selections.iter().peekable();
11388        let mut contiguous_row_selections = Vec::new();
11389        let mut new_selections = Vec::new();
11390        let mut added_lines = 0;
11391        let mut removed_lines = 0;
11392
11393        while let Some(selection) = selections.next() {
11394            let (start_row, end_row) = consume_contiguous_rows(
11395                &mut contiguous_row_selections,
11396                selection,
11397                &display_map,
11398                &mut selections,
11399            );
11400
11401            let start_point = Point::new(start_row.0, 0);
11402            let end_point = Point::new(
11403                end_row.previous_row().0,
11404                buffer.line_len(end_row.previous_row()),
11405            );
11406            let text = buffer
11407                .text_for_range(start_point..end_point)
11408                .collect::<String>();
11409
11410            let LineManipulationResult {
11411                new_text,
11412                line_count_before,
11413                line_count_after,
11414            } = manipulate(&text);
11415
11416            edits.push((start_point..end_point, new_text));
11417
11418            // Selections must change based on added and removed line count
11419            let start_row =
11420                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11421            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11422            new_selections.push(Selection {
11423                id: selection.id,
11424                start: start_row,
11425                end: end_row,
11426                goal: SelectionGoal::None,
11427                reversed: selection.reversed,
11428            });
11429
11430            if line_count_after > line_count_before {
11431                added_lines += line_count_after - line_count_before;
11432            } else if line_count_before > line_count_after {
11433                removed_lines += line_count_before - line_count_after;
11434            }
11435        }
11436
11437        self.transact(window, cx, |this, window, cx| {
11438            let buffer = this.buffer.update(cx, |buffer, cx| {
11439                buffer.edit(edits, None, cx);
11440                buffer.snapshot(cx)
11441            });
11442
11443            // Recalculate offsets on newly edited buffer
11444            let new_selections = new_selections
11445                .iter()
11446                .map(|s| {
11447                    let start_point = Point::new(s.start.0, 0);
11448                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11449                    Selection {
11450                        id: s.id,
11451                        start: buffer.point_to_offset(start_point),
11452                        end: buffer.point_to_offset(end_point),
11453                        goal: s.goal,
11454                        reversed: s.reversed,
11455                    }
11456                })
11457                .collect();
11458
11459            this.change_selections(Default::default(), window, cx, |s| {
11460                s.select(new_selections);
11461            });
11462
11463            this.request_autoscroll(Autoscroll::fit(), cx);
11464        });
11465    }
11466
11467    fn manipulate_immutable_lines<Fn>(
11468        &mut self,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471        mut callback: Fn,
11472    ) where
11473        Fn: FnMut(&mut Vec<&str>),
11474    {
11475        self.manipulate_lines(window, cx, |text| {
11476            let mut lines: Vec<&str> = text.split('\n').collect();
11477            let line_count_before = lines.len();
11478
11479            callback(&mut lines);
11480
11481            LineManipulationResult {
11482                new_text: lines.join("\n"),
11483                line_count_before,
11484                line_count_after: lines.len(),
11485            }
11486        });
11487    }
11488
11489    fn manipulate_mutable_lines<Fn>(
11490        &mut self,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493        mut callback: Fn,
11494    ) where
11495        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11496    {
11497        self.manipulate_lines(window, cx, |text| {
11498            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11499            let line_count_before = lines.len();
11500
11501            callback(&mut lines);
11502
11503            LineManipulationResult {
11504                new_text: lines.join("\n"),
11505                line_count_before,
11506                line_count_after: lines.len(),
11507            }
11508        });
11509    }
11510
11511    pub fn convert_indentation_to_spaces(
11512        &mut self,
11513        _: &ConvertIndentationToSpaces,
11514        window: &mut Window,
11515        cx: &mut Context<Self>,
11516    ) {
11517        let settings = self.buffer.read(cx).language_settings(cx);
11518        let tab_size = settings.tab_size.get() as usize;
11519
11520        self.manipulate_mutable_lines(window, cx, |lines| {
11521            // Allocates a reasonably sized scratch buffer once for the whole loop
11522            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11523            // Avoids recomputing spaces that could be inserted many times
11524            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11525                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11526                .collect();
11527
11528            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11529                let mut chars = line.as_ref().chars();
11530                let mut col = 0;
11531                let mut changed = false;
11532
11533                for ch in chars.by_ref() {
11534                    match ch {
11535                        ' ' => {
11536                            reindented_line.push(' ');
11537                            col += 1;
11538                        }
11539                        '\t' => {
11540                            // \t are converted to spaces depending on the current column
11541                            let spaces_len = tab_size - (col % tab_size);
11542                            reindented_line.extend(&space_cache[spaces_len - 1]);
11543                            col += spaces_len;
11544                            changed = true;
11545                        }
11546                        _ => {
11547                            // If we dont append before break, the character is consumed
11548                            reindented_line.push(ch);
11549                            break;
11550                        }
11551                    }
11552                }
11553
11554                if !changed {
11555                    reindented_line.clear();
11556                    continue;
11557                }
11558                // Append the rest of the line and replace old reference with new one
11559                reindented_line.extend(chars);
11560                *line = Cow::Owned(reindented_line.clone());
11561                reindented_line.clear();
11562            }
11563        });
11564    }
11565
11566    pub fn convert_indentation_to_tabs(
11567        &mut self,
11568        _: &ConvertIndentationToTabs,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        let settings = self.buffer.read(cx).language_settings(cx);
11573        let tab_size = settings.tab_size.get() as usize;
11574
11575        self.manipulate_mutable_lines(window, cx, |lines| {
11576            // Allocates a reasonably sized buffer once for the whole loop
11577            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11578            // Avoids recomputing spaces that could be inserted many times
11579            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11580                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11581                .collect();
11582
11583            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11584                let mut chars = line.chars();
11585                let mut spaces_count = 0;
11586                let mut first_non_indent_char = None;
11587                let mut changed = false;
11588
11589                for ch in chars.by_ref() {
11590                    match ch {
11591                        ' ' => {
11592                            // Keep track of spaces. Append \t when we reach tab_size
11593                            spaces_count += 1;
11594                            changed = true;
11595                            if spaces_count == tab_size {
11596                                reindented_line.push('\t');
11597                                spaces_count = 0;
11598                            }
11599                        }
11600                        '\t' => {
11601                            reindented_line.push('\t');
11602                            spaces_count = 0;
11603                        }
11604                        _ => {
11605                            // Dont append it yet, we might have remaining spaces
11606                            first_non_indent_char = Some(ch);
11607                            break;
11608                        }
11609                    }
11610                }
11611
11612                if !changed {
11613                    reindented_line.clear();
11614                    continue;
11615                }
11616                // Remaining spaces that didn't make a full tab stop
11617                if spaces_count > 0 {
11618                    reindented_line.extend(&space_cache[spaces_count - 1]);
11619                }
11620                // If we consume an extra character that was not indentation, add it back
11621                if let Some(extra_char) = first_non_indent_char {
11622                    reindented_line.push(extra_char);
11623                }
11624                // Append the rest of the line and replace old reference with new one
11625                reindented_line.extend(chars);
11626                *line = Cow::Owned(reindented_line.clone());
11627                reindented_line.clear();
11628            }
11629        });
11630    }
11631
11632    pub fn convert_to_upper_case(
11633        &mut self,
11634        _: &ConvertToUpperCase,
11635        window: &mut Window,
11636        cx: &mut Context<Self>,
11637    ) {
11638        self.manipulate_text(window, cx, |text| text.to_uppercase())
11639    }
11640
11641    pub fn convert_to_lower_case(
11642        &mut self,
11643        _: &ConvertToLowerCase,
11644        window: &mut Window,
11645        cx: &mut Context<Self>,
11646    ) {
11647        self.manipulate_text(window, cx, |text| text.to_lowercase())
11648    }
11649
11650    pub fn convert_to_title_case(
11651        &mut self,
11652        _: &ConvertToTitleCase,
11653        window: &mut Window,
11654        cx: &mut Context<Self>,
11655    ) {
11656        self.manipulate_text(window, cx, |text| {
11657            text.split('\n')
11658                .map(|line| line.to_case(Case::Title))
11659                .join("\n")
11660        })
11661    }
11662
11663    pub fn convert_to_snake_case(
11664        &mut self,
11665        _: &ConvertToSnakeCase,
11666        window: &mut Window,
11667        cx: &mut Context<Self>,
11668    ) {
11669        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11670    }
11671
11672    pub fn convert_to_kebab_case(
11673        &mut self,
11674        _: &ConvertToKebabCase,
11675        window: &mut Window,
11676        cx: &mut Context<Self>,
11677    ) {
11678        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11679    }
11680
11681    pub fn convert_to_upper_camel_case(
11682        &mut self,
11683        _: &ConvertToUpperCamelCase,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.manipulate_text(window, cx, |text| {
11688            text.split('\n')
11689                .map(|line| line.to_case(Case::UpperCamel))
11690                .join("\n")
11691        })
11692    }
11693
11694    pub fn convert_to_lower_camel_case(
11695        &mut self,
11696        _: &ConvertToLowerCamelCase,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11701    }
11702
11703    pub fn convert_to_opposite_case(
11704        &mut self,
11705        _: &ConvertToOppositeCase,
11706        window: &mut Window,
11707        cx: &mut Context<Self>,
11708    ) {
11709        self.manipulate_text(window, cx, |text| {
11710            text.chars()
11711                .fold(String::with_capacity(text.len()), |mut t, c| {
11712                    if c.is_uppercase() {
11713                        t.extend(c.to_lowercase());
11714                    } else {
11715                        t.extend(c.to_uppercase());
11716                    }
11717                    t
11718                })
11719        })
11720    }
11721
11722    pub fn convert_to_sentence_case(
11723        &mut self,
11724        _: &ConvertToSentenceCase,
11725        window: &mut Window,
11726        cx: &mut Context<Self>,
11727    ) {
11728        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11729    }
11730
11731    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11732        self.manipulate_text(window, cx, |text| {
11733            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11734            if has_upper_case_characters {
11735                text.to_lowercase()
11736            } else {
11737                text.to_uppercase()
11738            }
11739        })
11740    }
11741
11742    pub fn convert_to_rot13(
11743        &mut self,
11744        _: &ConvertToRot13,
11745        window: &mut Window,
11746        cx: &mut Context<Self>,
11747    ) {
11748        self.manipulate_text(window, cx, |text| {
11749            text.chars()
11750                .map(|c| match c {
11751                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11752                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11753                    _ => c,
11754                })
11755                .collect()
11756        })
11757    }
11758
11759    pub fn convert_to_rot47(
11760        &mut self,
11761        _: &ConvertToRot47,
11762        window: &mut Window,
11763        cx: &mut Context<Self>,
11764    ) {
11765        self.manipulate_text(window, cx, |text| {
11766            text.chars()
11767                .map(|c| {
11768                    let code_point = c as u32;
11769                    if code_point >= 33 && code_point <= 126 {
11770                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11771                    }
11772                    c
11773                })
11774                .collect()
11775        })
11776    }
11777
11778    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11779    where
11780        Fn: FnMut(&str) -> String,
11781    {
11782        let buffer = self.buffer.read(cx).snapshot(cx);
11783
11784        let mut new_selections = Vec::new();
11785        let mut edits = Vec::new();
11786        let mut selection_adjustment = 0isize;
11787
11788        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11789            let selection_is_empty = selection.is_empty();
11790
11791            let (start, end) = if selection_is_empty {
11792                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11793                (word_range.start, word_range.end)
11794            } else {
11795                (
11796                    buffer.point_to_offset(selection.start),
11797                    buffer.point_to_offset(selection.end),
11798                )
11799            };
11800
11801            let text = buffer.text_for_range(start..end).collect::<String>();
11802            let old_length = text.len() as isize;
11803            let text = callback(&text);
11804
11805            new_selections.push(Selection {
11806                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11807                end: MultiBufferOffset(
11808                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11809                ),
11810                goal: SelectionGoal::None,
11811                id: selection.id,
11812                reversed: selection.reversed,
11813            });
11814
11815            selection_adjustment += old_length - text.len() as isize;
11816
11817            edits.push((start..end, text));
11818        }
11819
11820        self.transact(window, cx, |this, window, cx| {
11821            this.buffer.update(cx, |buffer, cx| {
11822                buffer.edit(edits, None, cx);
11823            });
11824
11825            this.change_selections(Default::default(), window, cx, |s| {
11826                s.select(new_selections);
11827            });
11828
11829            this.request_autoscroll(Autoscroll::fit(), cx);
11830        });
11831    }
11832
11833    pub fn move_selection_on_drop(
11834        &mut self,
11835        selection: &Selection<Anchor>,
11836        target: DisplayPoint,
11837        is_cut: bool,
11838        window: &mut Window,
11839        cx: &mut Context<Self>,
11840    ) {
11841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11842        let buffer = display_map.buffer_snapshot();
11843        let mut edits = Vec::new();
11844        let insert_point = display_map
11845            .clip_point(target, Bias::Left)
11846            .to_point(&display_map);
11847        let text = buffer
11848            .text_for_range(selection.start..selection.end)
11849            .collect::<String>();
11850        if is_cut {
11851            edits.push(((selection.start..selection.end), String::new()));
11852        }
11853        let insert_anchor = buffer.anchor_before(insert_point);
11854        edits.push(((insert_anchor..insert_anchor), text));
11855        let last_edit_start = insert_anchor.bias_left(buffer);
11856        let last_edit_end = insert_anchor.bias_right(buffer);
11857        self.transact(window, cx, |this, window, cx| {
11858            this.buffer.update(cx, |buffer, cx| {
11859                buffer.edit(edits, None, cx);
11860            });
11861            this.change_selections(Default::default(), window, cx, |s| {
11862                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11863            });
11864        });
11865    }
11866
11867    pub fn clear_selection_drag_state(&mut self) {
11868        self.selection_drag_state = SelectionDragState::None;
11869    }
11870
11871    pub fn duplicate(
11872        &mut self,
11873        upwards: bool,
11874        whole_lines: bool,
11875        window: &mut Window,
11876        cx: &mut Context<Self>,
11877    ) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879
11880        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11881        let buffer = display_map.buffer_snapshot();
11882        let selections = self.selections.all::<Point>(&display_map);
11883
11884        let mut edits = Vec::new();
11885        let mut selections_iter = selections.iter().peekable();
11886        while let Some(selection) = selections_iter.next() {
11887            let mut rows = selection.spanned_rows(false, &display_map);
11888            // duplicate line-wise
11889            if whole_lines || selection.start == selection.end {
11890                // Avoid duplicating the same lines twice.
11891                while let Some(next_selection) = selections_iter.peek() {
11892                    let next_rows = next_selection.spanned_rows(false, &display_map);
11893                    if next_rows.start < rows.end {
11894                        rows.end = next_rows.end;
11895                        selections_iter.next().unwrap();
11896                    } else {
11897                        break;
11898                    }
11899                }
11900
11901                // Copy the text from the selected row region and splice it either at the start
11902                // or end of the region.
11903                let start = Point::new(rows.start.0, 0);
11904                let end = Point::new(
11905                    rows.end.previous_row().0,
11906                    buffer.line_len(rows.end.previous_row()),
11907                );
11908
11909                let mut text = buffer.text_for_range(start..end).collect::<String>();
11910
11911                let insert_location = if upwards {
11912                    // When duplicating upward, we need to insert before the current line.
11913                    // If we're on the last line and it doesn't end with a newline,
11914                    // we need to add a newline before the duplicated content.
11915                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11916                        && buffer.max_point().column > 0
11917                        && !text.ends_with('\n');
11918
11919                    if needs_leading_newline {
11920                        text.insert(0, '\n');
11921                        end
11922                    } else {
11923                        text.push('\n');
11924                        Point::new(rows.start.0, 0)
11925                    }
11926                } else {
11927                    text.push('\n');
11928                    start
11929                };
11930                edits.push((insert_location..insert_location, text));
11931            } else {
11932                // duplicate character-wise
11933                let start = selection.start;
11934                let end = selection.end;
11935                let text = buffer.text_for_range(start..end).collect::<String>();
11936                edits.push((selection.end..selection.end, text));
11937            }
11938        }
11939
11940        self.transact(window, cx, |this, window, cx| {
11941            this.buffer.update(cx, |buffer, cx| {
11942                buffer.edit(edits, None, cx);
11943            });
11944
11945            // When duplicating upward with whole lines, move the cursor to the duplicated line
11946            if upwards && whole_lines {
11947                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11948
11949                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11950                    let mut new_ranges = Vec::new();
11951                    let selections = s.all::<Point>(&display_map);
11952                    let mut selections_iter = selections.iter().peekable();
11953
11954                    while let Some(first_selection) = selections_iter.next() {
11955                        // Group contiguous selections together to find the total row span
11956                        let mut group_selections = vec![first_selection];
11957                        let mut rows = first_selection.spanned_rows(false, &display_map);
11958
11959                        while let Some(next_selection) = selections_iter.peek() {
11960                            let next_rows = next_selection.spanned_rows(false, &display_map);
11961                            if next_rows.start < rows.end {
11962                                rows.end = next_rows.end;
11963                                group_selections.push(selections_iter.next().unwrap());
11964                            } else {
11965                                break;
11966                            }
11967                        }
11968
11969                        let row_count = rows.end.0 - rows.start.0;
11970
11971                        // Move all selections in this group up by the total number of duplicated rows
11972                        for selection in group_selections {
11973                            let new_start = Point::new(
11974                                selection.start.row.saturating_sub(row_count),
11975                                selection.start.column,
11976                            );
11977
11978                            let new_end = Point::new(
11979                                selection.end.row.saturating_sub(row_count),
11980                                selection.end.column,
11981                            );
11982
11983                            new_ranges.push(new_start..new_end);
11984                        }
11985                    }
11986
11987                    s.select_ranges(new_ranges);
11988                });
11989            }
11990
11991            this.request_autoscroll(Autoscroll::fit(), cx);
11992        });
11993    }
11994
11995    pub fn duplicate_line_up(
11996        &mut self,
11997        _: &DuplicateLineUp,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        self.duplicate(true, true, window, cx);
12002    }
12003
12004    pub fn duplicate_line_down(
12005        &mut self,
12006        _: &DuplicateLineDown,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        self.duplicate(false, true, window, cx);
12011    }
12012
12013    pub fn duplicate_selection(
12014        &mut self,
12015        _: &DuplicateSelection,
12016        window: &mut Window,
12017        cx: &mut Context<Self>,
12018    ) {
12019        self.duplicate(false, false, window, cx);
12020    }
12021
12022    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12024        if self.mode.is_single_line() {
12025            cx.propagate();
12026            return;
12027        }
12028
12029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12030        let buffer = self.buffer.read(cx).snapshot(cx);
12031
12032        let mut edits = Vec::new();
12033        let mut unfold_ranges = Vec::new();
12034        let mut refold_creases = Vec::new();
12035
12036        let selections = self.selections.all::<Point>(&display_map);
12037        let mut selections = selections.iter().peekable();
12038        let mut contiguous_row_selections = Vec::new();
12039        let mut new_selections = Vec::new();
12040
12041        while let Some(selection) = selections.next() {
12042            // Find all the selections that span a contiguous row range
12043            let (start_row, end_row) = consume_contiguous_rows(
12044                &mut contiguous_row_selections,
12045                selection,
12046                &display_map,
12047                &mut selections,
12048            );
12049
12050            // Move the text spanned by the row range to be before the line preceding the row range
12051            if start_row.0 > 0 {
12052                let range_to_move = Point::new(
12053                    start_row.previous_row().0,
12054                    buffer.line_len(start_row.previous_row()),
12055                )
12056                    ..Point::new(
12057                        end_row.previous_row().0,
12058                        buffer.line_len(end_row.previous_row()),
12059                    );
12060                let insertion_point = display_map
12061                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12062                    .0;
12063
12064                // Don't move lines across excerpts
12065                if buffer
12066                    .excerpt_containing(insertion_point..range_to_move.end)
12067                    .is_some()
12068                {
12069                    let text = buffer
12070                        .text_for_range(range_to_move.clone())
12071                        .flat_map(|s| s.chars())
12072                        .skip(1)
12073                        .chain(['\n'])
12074                        .collect::<String>();
12075
12076                    edits.push((
12077                        buffer.anchor_after(range_to_move.start)
12078                            ..buffer.anchor_before(range_to_move.end),
12079                        String::new(),
12080                    ));
12081                    let insertion_anchor = buffer.anchor_after(insertion_point);
12082                    edits.push((insertion_anchor..insertion_anchor, text));
12083
12084                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12085
12086                    // Move selections up
12087                    new_selections.extend(contiguous_row_selections.drain(..).map(
12088                        |mut selection| {
12089                            selection.start.row -= row_delta;
12090                            selection.end.row -= row_delta;
12091                            selection
12092                        },
12093                    ));
12094
12095                    // Move folds up
12096                    unfold_ranges.push(range_to_move.clone());
12097                    for fold in display_map.folds_in_range(
12098                        buffer.anchor_before(range_to_move.start)
12099                            ..buffer.anchor_after(range_to_move.end),
12100                    ) {
12101                        let mut start = fold.range.start.to_point(&buffer);
12102                        let mut end = fold.range.end.to_point(&buffer);
12103                        start.row -= row_delta;
12104                        end.row -= row_delta;
12105                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12106                    }
12107                }
12108            }
12109
12110            // If we didn't move line(s), preserve the existing selections
12111            new_selections.append(&mut contiguous_row_selections);
12112        }
12113
12114        self.transact(window, cx, |this, window, cx| {
12115            this.unfold_ranges(&unfold_ranges, true, true, cx);
12116            this.buffer.update(cx, |buffer, cx| {
12117                for (range, text) in edits {
12118                    buffer.edit([(range, text)], None, cx);
12119                }
12120            });
12121            this.fold_creases(refold_creases, true, window, cx);
12122            this.change_selections(Default::default(), window, cx, |s| {
12123                s.select(new_selections);
12124            })
12125        });
12126    }
12127
12128    pub fn move_line_down(
12129        &mut self,
12130        _: &MoveLineDown,
12131        window: &mut Window,
12132        cx: &mut Context<Self>,
12133    ) {
12134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12135        if self.mode.is_single_line() {
12136            cx.propagate();
12137            return;
12138        }
12139
12140        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12141        let buffer = self.buffer.read(cx).snapshot(cx);
12142
12143        let mut edits = Vec::new();
12144        let mut unfold_ranges = Vec::new();
12145        let mut refold_creases = Vec::new();
12146
12147        let selections = self.selections.all::<Point>(&display_map);
12148        let mut selections = selections.iter().peekable();
12149        let mut contiguous_row_selections = Vec::new();
12150        let mut new_selections = Vec::new();
12151
12152        while let Some(selection) = selections.next() {
12153            // Find all the selections that span a contiguous row range
12154            let (start_row, end_row) = consume_contiguous_rows(
12155                &mut contiguous_row_selections,
12156                selection,
12157                &display_map,
12158                &mut selections,
12159            );
12160
12161            // Move the text spanned by the row range to be after the last line of the row range
12162            if end_row.0 <= buffer.max_point().row {
12163                let range_to_move =
12164                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12165                let insertion_point = display_map
12166                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12167                    .0;
12168
12169                // Don't move lines across excerpt boundaries
12170                if buffer
12171                    .excerpt_containing(range_to_move.start..insertion_point)
12172                    .is_some()
12173                {
12174                    let mut text = String::from("\n");
12175                    text.extend(buffer.text_for_range(range_to_move.clone()));
12176                    text.pop(); // Drop trailing newline
12177                    edits.push((
12178                        buffer.anchor_after(range_to_move.start)
12179                            ..buffer.anchor_before(range_to_move.end),
12180                        String::new(),
12181                    ));
12182                    let insertion_anchor = buffer.anchor_after(insertion_point);
12183                    edits.push((insertion_anchor..insertion_anchor, text));
12184
12185                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12186
12187                    // Move selections down
12188                    new_selections.extend(contiguous_row_selections.drain(..).map(
12189                        |mut selection| {
12190                            selection.start.row += row_delta;
12191                            selection.end.row += row_delta;
12192                            selection
12193                        },
12194                    ));
12195
12196                    // Move folds down
12197                    unfold_ranges.push(range_to_move.clone());
12198                    for fold in display_map.folds_in_range(
12199                        buffer.anchor_before(range_to_move.start)
12200                            ..buffer.anchor_after(range_to_move.end),
12201                    ) {
12202                        let mut start = fold.range.start.to_point(&buffer);
12203                        let mut end = fold.range.end.to_point(&buffer);
12204                        start.row += row_delta;
12205                        end.row += row_delta;
12206                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12207                    }
12208                }
12209            }
12210
12211            // If we didn't move line(s), preserve the existing selections
12212            new_selections.append(&mut contiguous_row_selections);
12213        }
12214
12215        self.transact(window, cx, |this, window, cx| {
12216            this.unfold_ranges(&unfold_ranges, true, true, cx);
12217            this.buffer.update(cx, |buffer, cx| {
12218                for (range, text) in edits {
12219                    buffer.edit([(range, text)], None, cx);
12220                }
12221            });
12222            this.fold_creases(refold_creases, true, window, cx);
12223            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12224        });
12225    }
12226
12227    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12228        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12229        let text_layout_details = &self.text_layout_details(window);
12230        self.transact(window, cx, |this, window, cx| {
12231            let edits = this.change_selections(Default::default(), window, cx, |s| {
12232                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12233                s.move_with(|display_map, selection| {
12234                    if !selection.is_empty() {
12235                        return;
12236                    }
12237
12238                    let mut head = selection.head();
12239                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12240                    if head.column() == display_map.line_len(head.row()) {
12241                        transpose_offset = display_map
12242                            .buffer_snapshot()
12243                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12244                    }
12245
12246                    if transpose_offset == MultiBufferOffset(0) {
12247                        return;
12248                    }
12249
12250                    *head.column_mut() += 1;
12251                    head = display_map.clip_point(head, Bias::Right);
12252                    let goal = SelectionGoal::HorizontalPosition(
12253                        display_map
12254                            .x_for_display_point(head, text_layout_details)
12255                            .into(),
12256                    );
12257                    selection.collapse_to(head, goal);
12258
12259                    let transpose_start = display_map
12260                        .buffer_snapshot()
12261                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12262                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12263                        let transpose_end = display_map
12264                            .buffer_snapshot()
12265                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12266                        if let Some(ch) = display_map
12267                            .buffer_snapshot()
12268                            .chars_at(transpose_start)
12269                            .next()
12270                        {
12271                            edits.push((transpose_start..transpose_offset, String::new()));
12272                            edits.push((transpose_end..transpose_end, ch.to_string()));
12273                        }
12274                    }
12275                });
12276                edits
12277            });
12278            this.buffer
12279                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12280            let selections = this
12281                .selections
12282                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12283            this.change_selections(Default::default(), window, cx, |s| {
12284                s.select(selections);
12285            });
12286        });
12287    }
12288
12289    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12291        if self.mode.is_single_line() {
12292            cx.propagate();
12293            return;
12294        }
12295
12296        self.rewrap_impl(RewrapOptions::default(), cx)
12297    }
12298
12299    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12300        let buffer = self.buffer.read(cx).snapshot(cx);
12301        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12302
12303        #[derive(Clone, Debug, PartialEq)]
12304        enum CommentFormat {
12305            /// single line comment, with prefix for line
12306            Line(String),
12307            /// single line within a block comment, with prefix for line
12308            BlockLine(String),
12309            /// a single line of a block comment that includes the initial delimiter
12310            BlockCommentWithStart(BlockCommentConfig),
12311            /// a single line of a block comment that includes the ending delimiter
12312            BlockCommentWithEnd(BlockCommentConfig),
12313        }
12314
12315        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12316        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12317            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12318                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12319                .peekable();
12320
12321            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12322                row
12323            } else {
12324                return Vec::new();
12325            };
12326
12327            let language_settings = buffer.language_settings_at(selection.head(), cx);
12328            let language_scope = buffer.language_scope_at(selection.head());
12329
12330            let indent_and_prefix_for_row =
12331                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12332                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12333                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12334                        &language_scope
12335                    {
12336                        let indent_end = Point::new(row, indent.len);
12337                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12338                        let line_text_after_indent = buffer
12339                            .text_for_range(indent_end..line_end)
12340                            .collect::<String>();
12341
12342                        let is_within_comment_override = buffer
12343                            .language_scope_at(indent_end)
12344                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12345                        let comment_delimiters = if is_within_comment_override {
12346                            // we are within a comment syntax node, but we don't
12347                            // yet know what kind of comment: block, doc or line
12348                            match (
12349                                language_scope.documentation_comment(),
12350                                language_scope.block_comment(),
12351                            ) {
12352                                (Some(config), _) | (_, Some(config))
12353                                    if buffer.contains_str_at(indent_end, &config.start) =>
12354                                {
12355                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12356                                }
12357                                (Some(config), _) | (_, Some(config))
12358                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12359                                {
12360                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12361                                }
12362                                (Some(config), _) | (_, Some(config))
12363                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12364                                {
12365                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12366                                }
12367                                (_, _) => language_scope
12368                                    .line_comment_prefixes()
12369                                    .iter()
12370                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12371                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12372                            }
12373                        } else {
12374                            // we not in an overridden comment node, but we may
12375                            // be within a non-overridden line comment node
12376                            language_scope
12377                                .line_comment_prefixes()
12378                                .iter()
12379                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12380                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12381                        };
12382
12383                        let rewrap_prefix = language_scope
12384                            .rewrap_prefixes()
12385                            .iter()
12386                            .find_map(|prefix_regex| {
12387                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12388                                    if mat.start() == 0 {
12389                                        Some(mat.as_str().to_string())
12390                                    } else {
12391                                        None
12392                                    }
12393                                })
12394                            })
12395                            .flatten();
12396                        (comment_delimiters, rewrap_prefix)
12397                    } else {
12398                        (None, None)
12399                    };
12400                    (indent, comment_prefix, rewrap_prefix)
12401                };
12402
12403            let mut ranges = Vec::new();
12404            let from_empty_selection = selection.is_empty();
12405
12406            let mut current_range_start = first_row;
12407            let mut prev_row = first_row;
12408            let (
12409                mut current_range_indent,
12410                mut current_range_comment_delimiters,
12411                mut current_range_rewrap_prefix,
12412            ) = indent_and_prefix_for_row(first_row);
12413
12414            for row in non_blank_rows_iter.skip(1) {
12415                let has_paragraph_break = row > prev_row + 1;
12416
12417                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12418                    indent_and_prefix_for_row(row);
12419
12420                let has_indent_change = row_indent != current_range_indent;
12421                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12422
12423                let has_boundary_change = has_comment_change
12424                    || row_rewrap_prefix.is_some()
12425                    || (has_indent_change && current_range_comment_delimiters.is_some());
12426
12427                if has_paragraph_break || has_boundary_change {
12428                    ranges.push((
12429                        language_settings.clone(),
12430                        Point::new(current_range_start, 0)
12431                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12432                        current_range_indent,
12433                        current_range_comment_delimiters.clone(),
12434                        current_range_rewrap_prefix.clone(),
12435                        from_empty_selection,
12436                    ));
12437                    current_range_start = row;
12438                    current_range_indent = row_indent;
12439                    current_range_comment_delimiters = row_comment_delimiters;
12440                    current_range_rewrap_prefix = row_rewrap_prefix;
12441                }
12442                prev_row = row;
12443            }
12444
12445            ranges.push((
12446                language_settings.clone(),
12447                Point::new(current_range_start, 0)
12448                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12449                current_range_indent,
12450                current_range_comment_delimiters,
12451                current_range_rewrap_prefix,
12452                from_empty_selection,
12453            ));
12454
12455            ranges
12456        });
12457
12458        let mut edits = Vec::new();
12459        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12460
12461        for (
12462            language_settings,
12463            wrap_range,
12464            mut indent_size,
12465            comment_prefix,
12466            rewrap_prefix,
12467            from_empty_selection,
12468        ) in wrap_ranges
12469        {
12470            let mut start_row = wrap_range.start.row;
12471            let mut end_row = wrap_range.end.row;
12472
12473            // Skip selections that overlap with a range that has already been rewrapped.
12474            let selection_range = start_row..end_row;
12475            if rewrapped_row_ranges
12476                .iter()
12477                .any(|range| range.overlaps(&selection_range))
12478            {
12479                continue;
12480            }
12481
12482            let tab_size = language_settings.tab_size;
12483
12484            let (line_prefix, inside_comment) = match &comment_prefix {
12485                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12486                    (Some(prefix.as_str()), true)
12487                }
12488                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12489                    (Some(prefix.as_ref()), true)
12490                }
12491                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12492                    start: _,
12493                    end: _,
12494                    prefix,
12495                    tab_size,
12496                })) => {
12497                    indent_size.len += tab_size;
12498                    (Some(prefix.as_ref()), true)
12499                }
12500                None => (None, false),
12501            };
12502            let indent_prefix = indent_size.chars().collect::<String>();
12503            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12504
12505            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12506                RewrapBehavior::InComments => inside_comment,
12507                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12508                RewrapBehavior::Anywhere => true,
12509            };
12510
12511            let should_rewrap = options.override_language_settings
12512                || allow_rewrap_based_on_language
12513                || self.hard_wrap.is_some();
12514            if !should_rewrap {
12515                continue;
12516            }
12517
12518            if from_empty_selection {
12519                'expand_upwards: while start_row > 0 {
12520                    let prev_row = start_row - 1;
12521                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12522                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12523                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12524                    {
12525                        start_row = prev_row;
12526                    } else {
12527                        break 'expand_upwards;
12528                    }
12529                }
12530
12531                'expand_downwards: while end_row < buffer.max_point().row {
12532                    let next_row = end_row + 1;
12533                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12534                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12535                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12536                    {
12537                        end_row = next_row;
12538                    } else {
12539                        break 'expand_downwards;
12540                    }
12541                }
12542            }
12543
12544            let start = Point::new(start_row, 0);
12545            let start_offset = ToOffset::to_offset(&start, &buffer);
12546            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12547            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12548            let mut first_line_delimiter = None;
12549            let mut last_line_delimiter = None;
12550            let Some(lines_without_prefixes) = selection_text
12551                .lines()
12552                .enumerate()
12553                .map(|(ix, line)| {
12554                    let line_trimmed = line.trim_start();
12555                    if rewrap_prefix.is_some() && ix > 0 {
12556                        Ok(line_trimmed)
12557                    } else if let Some(
12558                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12559                            start,
12560                            prefix,
12561                            end,
12562                            tab_size,
12563                        })
12564                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12565                            start,
12566                            prefix,
12567                            end,
12568                            tab_size,
12569                        }),
12570                    ) = &comment_prefix
12571                    {
12572                        let line_trimmed = line_trimmed
12573                            .strip_prefix(start.as_ref())
12574                            .map(|s| {
12575                                let mut indent_size = indent_size;
12576                                indent_size.len -= tab_size;
12577                                let indent_prefix: String = indent_size.chars().collect();
12578                                first_line_delimiter = Some((indent_prefix, start));
12579                                s.trim_start()
12580                            })
12581                            .unwrap_or(line_trimmed);
12582                        let line_trimmed = line_trimmed
12583                            .strip_suffix(end.as_ref())
12584                            .map(|s| {
12585                                last_line_delimiter = Some(end);
12586                                s.trim_end()
12587                            })
12588                            .unwrap_or(line_trimmed);
12589                        let line_trimmed = line_trimmed
12590                            .strip_prefix(prefix.as_ref())
12591                            .unwrap_or(line_trimmed);
12592                        Ok(line_trimmed)
12593                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12594                        line_trimmed.strip_prefix(prefix).with_context(|| {
12595                            format!("line did not start with prefix {prefix:?}: {line:?}")
12596                        })
12597                    } else {
12598                        line_trimmed
12599                            .strip_prefix(&line_prefix.trim_start())
12600                            .with_context(|| {
12601                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12602                            })
12603                    }
12604                })
12605                .collect::<Result<Vec<_>, _>>()
12606                .log_err()
12607            else {
12608                continue;
12609            };
12610
12611            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12612                buffer
12613                    .language_settings_at(Point::new(start_row, 0), cx)
12614                    .preferred_line_length as usize
12615            });
12616
12617            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12618                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12619            } else {
12620                line_prefix.clone()
12621            };
12622
12623            let wrapped_text = {
12624                let mut wrapped_text = wrap_with_prefix(
12625                    line_prefix,
12626                    subsequent_lines_prefix,
12627                    lines_without_prefixes.join("\n"),
12628                    wrap_column,
12629                    tab_size,
12630                    options.preserve_existing_whitespace,
12631                );
12632
12633                if let Some((indent, delimiter)) = first_line_delimiter {
12634                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12635                }
12636                if let Some(last_line) = last_line_delimiter {
12637                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12638                }
12639
12640                wrapped_text
12641            };
12642
12643            // TODO: should always use char-based diff while still supporting cursor behavior that
12644            // matches vim.
12645            let mut diff_options = DiffOptions::default();
12646            if options.override_language_settings {
12647                diff_options.max_word_diff_len = 0;
12648                diff_options.max_word_diff_line_count = 0;
12649            } else {
12650                diff_options.max_word_diff_len = usize::MAX;
12651                diff_options.max_word_diff_line_count = usize::MAX;
12652            }
12653
12654            for (old_range, new_text) in
12655                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12656            {
12657                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12658                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12659                edits.push((edit_start..edit_end, new_text));
12660            }
12661
12662            rewrapped_row_ranges.push(start_row..=end_row);
12663        }
12664
12665        self.buffer
12666            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12667    }
12668
12669    pub fn cut_common(
12670        &mut self,
12671        cut_no_selection_line: bool,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) -> ClipboardItem {
12675        let mut text = String::new();
12676        let buffer = self.buffer.read(cx).snapshot(cx);
12677        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12678        let mut clipboard_selections = Vec::with_capacity(selections.len());
12679        {
12680            let max_point = buffer.max_point();
12681            let mut is_first = true;
12682            let mut prev_selection_was_entire_line = false;
12683            for selection in &mut selections {
12684                let is_entire_line =
12685                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12686                if is_entire_line {
12687                    selection.start = Point::new(selection.start.row, 0);
12688                    if !selection.is_empty() && selection.end.column == 0 {
12689                        selection.end = cmp::min(max_point, selection.end);
12690                    } else {
12691                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12692                    }
12693                    selection.goal = SelectionGoal::None;
12694                }
12695                if is_first {
12696                    is_first = false;
12697                } else if !prev_selection_was_entire_line {
12698                    text += "\n";
12699                }
12700                prev_selection_was_entire_line = is_entire_line;
12701                let mut len = 0;
12702                for chunk in buffer.text_for_range(selection.start..selection.end) {
12703                    text.push_str(chunk);
12704                    len += chunk.len();
12705                }
12706                clipboard_selections.push(ClipboardSelection {
12707                    len,
12708                    is_entire_line,
12709                    first_line_indent: buffer
12710                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12711                        .len,
12712                });
12713            }
12714        }
12715
12716        self.transact(window, cx, |this, window, cx| {
12717            this.change_selections(Default::default(), window, cx, |s| {
12718                s.select(selections);
12719            });
12720            this.insert("", window, cx);
12721        });
12722        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12723    }
12724
12725    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12727        let item = self.cut_common(true, window, cx);
12728        cx.write_to_clipboard(item);
12729    }
12730
12731    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12733        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12734            s.move_with(|snapshot, sel| {
12735                if sel.is_empty() {
12736                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12737                }
12738                if sel.is_empty() {
12739                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12740                }
12741            });
12742        });
12743        let item = self.cut_common(false, window, cx);
12744        cx.set_global(KillRing(item))
12745    }
12746
12747    pub fn kill_ring_yank(
12748        &mut self,
12749        _: &KillRingYank,
12750        window: &mut Window,
12751        cx: &mut Context<Self>,
12752    ) {
12753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12754        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12755            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12756                (kill_ring.text().to_string(), kill_ring.metadata_json())
12757            } else {
12758                return;
12759            }
12760        } else {
12761            return;
12762        };
12763        self.do_paste(&text, metadata, false, window, cx);
12764    }
12765
12766    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12767        self.do_copy(true, cx);
12768    }
12769
12770    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12771        self.do_copy(false, cx);
12772    }
12773
12774    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12775        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12776        let buffer = self.buffer.read(cx).read(cx);
12777        let mut text = String::new();
12778
12779        let mut clipboard_selections = Vec::with_capacity(selections.len());
12780        {
12781            let max_point = buffer.max_point();
12782            let mut is_first = true;
12783            let mut prev_selection_was_entire_line = false;
12784            for selection in &selections {
12785                let mut start = selection.start;
12786                let mut end = selection.end;
12787                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12788                let mut add_trailing_newline = false;
12789                if is_entire_line {
12790                    start = Point::new(start.row, 0);
12791                    let next_line_start = Point::new(end.row + 1, 0);
12792                    if next_line_start <= max_point {
12793                        end = next_line_start;
12794                    } else {
12795                        // We're on the last line without a trailing newline.
12796                        // Copy to the end of the line and add a newline afterwards.
12797                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12798                        add_trailing_newline = true;
12799                    }
12800                }
12801
12802                let mut trimmed_selections = Vec::new();
12803                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12804                    let row = MultiBufferRow(start.row);
12805                    let first_indent = buffer.indent_size_for_line(row);
12806                    if first_indent.len == 0 || start.column > first_indent.len {
12807                        trimmed_selections.push(start..end);
12808                    } else {
12809                        trimmed_selections.push(
12810                            Point::new(row.0, first_indent.len)
12811                                ..Point::new(row.0, buffer.line_len(row)),
12812                        );
12813                        for row in start.row + 1..=end.row {
12814                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12815                            if row == end.row {
12816                                line_len = end.column;
12817                            }
12818                            if line_len == 0 {
12819                                trimmed_selections
12820                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12821                                continue;
12822                            }
12823                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12824                            if row_indent_size.len >= first_indent.len {
12825                                trimmed_selections.push(
12826                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12827                                );
12828                            } else {
12829                                trimmed_selections.clear();
12830                                trimmed_selections.push(start..end);
12831                                break;
12832                            }
12833                        }
12834                    }
12835                } else {
12836                    trimmed_selections.push(start..end);
12837                }
12838
12839                for trimmed_range in trimmed_selections {
12840                    if is_first {
12841                        is_first = false;
12842                    } else if !prev_selection_was_entire_line {
12843                        text += "\n";
12844                    }
12845                    prev_selection_was_entire_line = is_entire_line;
12846                    let mut len = 0;
12847                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12848                        text.push_str(chunk);
12849                        len += chunk.len();
12850                    }
12851                    if add_trailing_newline {
12852                        text.push('\n');
12853                        len += 1;
12854                    }
12855                    clipboard_selections.push(ClipboardSelection {
12856                        len,
12857                        is_entire_line,
12858                        first_line_indent: buffer
12859                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12860                            .len,
12861                    });
12862                }
12863            }
12864        }
12865
12866        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12867            text,
12868            clipboard_selections,
12869        ));
12870    }
12871
12872    pub fn do_paste(
12873        &mut self,
12874        text: &String,
12875        clipboard_selections: Option<Vec<ClipboardSelection>>,
12876        handle_entire_lines: bool,
12877        window: &mut Window,
12878        cx: &mut Context<Self>,
12879    ) {
12880        if self.read_only(cx) {
12881            return;
12882        }
12883
12884        let clipboard_text = Cow::Borrowed(text.as_str());
12885
12886        self.transact(window, cx, |this, window, cx| {
12887            let had_active_edit_prediction = this.has_active_edit_prediction();
12888            let display_map = this.display_snapshot(cx);
12889            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12890            let cursor_offset = this
12891                .selections
12892                .last::<MultiBufferOffset>(&display_map)
12893                .head();
12894
12895            if let Some(mut clipboard_selections) = clipboard_selections {
12896                let all_selections_were_entire_line =
12897                    clipboard_selections.iter().all(|s| s.is_entire_line);
12898                let first_selection_indent_column =
12899                    clipboard_selections.first().map(|s| s.first_line_indent);
12900                if clipboard_selections.len() != old_selections.len() {
12901                    clipboard_selections.drain(..);
12902                }
12903                let mut auto_indent_on_paste = true;
12904
12905                this.buffer.update(cx, |buffer, cx| {
12906                    let snapshot = buffer.read(cx);
12907                    auto_indent_on_paste = snapshot
12908                        .language_settings_at(cursor_offset, cx)
12909                        .auto_indent_on_paste;
12910
12911                    let mut start_offset = 0;
12912                    let mut edits = Vec::new();
12913                    let mut original_indent_columns = Vec::new();
12914                    for (ix, selection) in old_selections.iter().enumerate() {
12915                        let to_insert;
12916                        let entire_line;
12917                        let original_indent_column;
12918                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12919                            let end_offset = start_offset + clipboard_selection.len;
12920                            to_insert = &clipboard_text[start_offset..end_offset];
12921                            entire_line = clipboard_selection.is_entire_line;
12922                            start_offset = if entire_line {
12923                                end_offset
12924                            } else {
12925                                end_offset + 1
12926                            };
12927                            original_indent_column = Some(clipboard_selection.first_line_indent);
12928                        } else {
12929                            to_insert = &*clipboard_text;
12930                            entire_line = all_selections_were_entire_line;
12931                            original_indent_column = first_selection_indent_column
12932                        }
12933
12934                        let (range, to_insert) =
12935                            if selection.is_empty() && handle_entire_lines && entire_line {
12936                                // If the corresponding selection was empty when this slice of the
12937                                // clipboard text was written, then the entire line containing the
12938                                // selection was copied. If this selection is also currently empty,
12939                                // then paste the line before the current line of the buffer.
12940                                let column = selection.start.to_point(&snapshot).column as usize;
12941                                let line_start = selection.start - column;
12942                                (line_start..line_start, Cow::Borrowed(to_insert))
12943                            } else {
12944                                let language = snapshot.language_at(selection.head());
12945                                let range = selection.range();
12946                                if let Some(language) = language
12947                                    && language.name() == "Markdown".into()
12948                                {
12949                                    edit_for_markdown_paste(
12950                                        &snapshot,
12951                                        range,
12952                                        to_insert,
12953                                        url::Url::parse(to_insert).ok(),
12954                                    )
12955                                } else {
12956                                    (range, Cow::Borrowed(to_insert))
12957                                }
12958                            };
12959
12960                        edits.push((range, to_insert));
12961                        original_indent_columns.push(original_indent_column);
12962                    }
12963                    drop(snapshot);
12964
12965                    buffer.edit(
12966                        edits,
12967                        if auto_indent_on_paste {
12968                            Some(AutoindentMode::Block {
12969                                original_indent_columns,
12970                            })
12971                        } else {
12972                            None
12973                        },
12974                        cx,
12975                    );
12976                });
12977
12978                let selections = this
12979                    .selections
12980                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12981                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12982            } else {
12983                let url = url::Url::parse(&clipboard_text).ok();
12984
12985                let auto_indent_mode = if !clipboard_text.is_empty() {
12986                    Some(AutoindentMode::Block {
12987                        original_indent_columns: Vec::new(),
12988                    })
12989                } else {
12990                    None
12991                };
12992
12993                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12994                    let snapshot = buffer.snapshot(cx);
12995
12996                    let anchors = old_selections
12997                        .iter()
12998                        .map(|s| {
12999                            let anchor = snapshot.anchor_after(s.head());
13000                            s.map(|_| anchor)
13001                        })
13002                        .collect::<Vec<_>>();
13003
13004                    let mut edits = Vec::new();
13005
13006                    for selection in old_selections.iter() {
13007                        let language = snapshot.language_at(selection.head());
13008                        let range = selection.range();
13009
13010                        let (edit_range, edit_text) = if let Some(language) = language
13011                            && language.name() == "Markdown".into()
13012                        {
13013                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13014                        } else {
13015                            (range, clipboard_text.clone())
13016                        };
13017
13018                        edits.push((edit_range, edit_text));
13019                    }
13020
13021                    drop(snapshot);
13022                    buffer.edit(edits, auto_indent_mode, cx);
13023
13024                    anchors
13025                });
13026
13027                this.change_selections(Default::default(), window, cx, |s| {
13028                    s.select_anchors(selection_anchors);
13029                });
13030            }
13031
13032            //   🤔                 |    ..     | show_in_menu |
13033            // | ..                  |   true        true
13034            // | had_edit_prediction |   false       true
13035
13036            let trigger_in_words =
13037                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13038
13039            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13040        });
13041    }
13042
13043    pub fn diff_clipboard_with_selection(
13044        &mut self,
13045        _: &DiffClipboardWithSelection,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        let selections = self
13050            .selections
13051            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13052
13053        if selections.is_empty() {
13054            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13055            return;
13056        };
13057
13058        let clipboard_text = match cx.read_from_clipboard() {
13059            Some(item) => match item.entries().first() {
13060                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13061                _ => None,
13062            },
13063            None => None,
13064        };
13065
13066        let Some(clipboard_text) = clipboard_text else {
13067            log::warn!("Clipboard doesn't contain text.");
13068            return;
13069        };
13070
13071        window.dispatch_action(
13072            Box::new(DiffClipboardWithSelectionData {
13073                clipboard_text,
13074                editor: cx.entity(),
13075            }),
13076            cx,
13077        );
13078    }
13079
13080    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13082        if let Some(item) = cx.read_from_clipboard() {
13083            let entries = item.entries();
13084
13085            match entries.first() {
13086                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13087                // of all the pasted entries.
13088                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13089                    .do_paste(
13090                        clipboard_string.text(),
13091                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13092                        true,
13093                        window,
13094                        cx,
13095                    ),
13096                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13097            }
13098        }
13099    }
13100
13101    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13102        if self.read_only(cx) {
13103            return;
13104        }
13105
13106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13107
13108        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13109            if let Some((selections, _)) =
13110                self.selection_history.transaction(transaction_id).cloned()
13111            {
13112                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13113                    s.select_anchors(selections.to_vec());
13114                });
13115            } else {
13116                log::error!(
13117                    "No entry in selection_history found for undo. \
13118                     This may correspond to a bug where undo does not update the selection. \
13119                     If this is occurring, please add details to \
13120                     https://github.com/zed-industries/zed/issues/22692"
13121                );
13122            }
13123            self.request_autoscroll(Autoscroll::fit(), cx);
13124            self.unmark_text(window, cx);
13125            self.refresh_edit_prediction(true, false, window, cx);
13126            cx.emit(EditorEvent::Edited { transaction_id });
13127            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13128        }
13129    }
13130
13131    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13132        if self.read_only(cx) {
13133            return;
13134        }
13135
13136        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13137
13138        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13139            if let Some((_, Some(selections))) =
13140                self.selection_history.transaction(transaction_id).cloned()
13141            {
13142                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13143                    s.select_anchors(selections.to_vec());
13144                });
13145            } else {
13146                log::error!(
13147                    "No entry in selection_history found for redo. \
13148                     This may correspond to a bug where undo does not update the selection. \
13149                     If this is occurring, please add details to \
13150                     https://github.com/zed-industries/zed/issues/22692"
13151                );
13152            }
13153            self.request_autoscroll(Autoscroll::fit(), cx);
13154            self.unmark_text(window, cx);
13155            self.refresh_edit_prediction(true, false, window, cx);
13156            cx.emit(EditorEvent::Edited { transaction_id });
13157        }
13158    }
13159
13160    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13161        self.buffer
13162            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13163    }
13164
13165    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13166        self.buffer
13167            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13168    }
13169
13170    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_with(|map, selection| {
13174                let cursor = if selection.is_empty() {
13175                    movement::left(map, selection.start)
13176                } else {
13177                    selection.start
13178                };
13179                selection.collapse_to(cursor, SelectionGoal::None);
13180            });
13181        })
13182    }
13183
13184    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13188        })
13189    }
13190
13191    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13193        self.change_selections(Default::default(), window, cx, |s| {
13194            s.move_with(|map, selection| {
13195                let cursor = if selection.is_empty() {
13196                    movement::right(map, selection.end)
13197                } else {
13198                    selection.end
13199                };
13200                selection.collapse_to(cursor, SelectionGoal::None)
13201            });
13202        })
13203    }
13204
13205    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13207        self.change_selections(Default::default(), window, cx, |s| {
13208            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13209        });
13210    }
13211
13212    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13213        if self.take_rename(true, window, cx).is_some() {
13214            return;
13215        }
13216
13217        if self.mode.is_single_line() {
13218            cx.propagate();
13219            return;
13220        }
13221
13222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13223
13224        let text_layout_details = &self.text_layout_details(window);
13225        let selection_count = self.selections.count();
13226        let first_selection = self.selections.first_anchor();
13227
13228        self.change_selections(Default::default(), window, cx, |s| {
13229            s.move_with(|map, selection| {
13230                if !selection.is_empty() {
13231                    selection.goal = SelectionGoal::None;
13232                }
13233                let (cursor, goal) = movement::up(
13234                    map,
13235                    selection.start,
13236                    selection.goal,
13237                    false,
13238                    text_layout_details,
13239                );
13240                selection.collapse_to(cursor, goal);
13241            });
13242        });
13243
13244        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13245        {
13246            cx.propagate();
13247        }
13248    }
13249
13250    pub fn move_up_by_lines(
13251        &mut self,
13252        action: &MoveUpByLines,
13253        window: &mut Window,
13254        cx: &mut Context<Self>,
13255    ) {
13256        if self.take_rename(true, window, cx).is_some() {
13257            return;
13258        }
13259
13260        if self.mode.is_single_line() {
13261            cx.propagate();
13262            return;
13263        }
13264
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266
13267        let text_layout_details = &self.text_layout_details(window);
13268
13269        self.change_selections(Default::default(), window, cx, |s| {
13270            s.move_with(|map, selection| {
13271                if !selection.is_empty() {
13272                    selection.goal = SelectionGoal::None;
13273                }
13274                let (cursor, goal) = movement::up_by_rows(
13275                    map,
13276                    selection.start,
13277                    action.lines,
13278                    selection.goal,
13279                    false,
13280                    text_layout_details,
13281                );
13282                selection.collapse_to(cursor, goal);
13283            });
13284        })
13285    }
13286
13287    pub fn move_down_by_lines(
13288        &mut self,
13289        action: &MoveDownByLines,
13290        window: &mut Window,
13291        cx: &mut Context<Self>,
13292    ) {
13293        if self.take_rename(true, window, cx).is_some() {
13294            return;
13295        }
13296
13297        if self.mode.is_single_line() {
13298            cx.propagate();
13299            return;
13300        }
13301
13302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13303
13304        let text_layout_details = &self.text_layout_details(window);
13305
13306        self.change_selections(Default::default(), window, cx, |s| {
13307            s.move_with(|map, selection| {
13308                if !selection.is_empty() {
13309                    selection.goal = SelectionGoal::None;
13310                }
13311                let (cursor, goal) = movement::down_by_rows(
13312                    map,
13313                    selection.start,
13314                    action.lines,
13315                    selection.goal,
13316                    false,
13317                    text_layout_details,
13318                );
13319                selection.collapse_to(cursor, goal);
13320            });
13321        })
13322    }
13323
13324    pub fn select_down_by_lines(
13325        &mut self,
13326        action: &SelectDownByLines,
13327        window: &mut Window,
13328        cx: &mut Context<Self>,
13329    ) {
13330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13331        let text_layout_details = &self.text_layout_details(window);
13332        self.change_selections(Default::default(), window, cx, |s| {
13333            s.move_heads_with(|map, head, goal| {
13334                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13335            })
13336        })
13337    }
13338
13339    pub fn select_up_by_lines(
13340        &mut self,
13341        action: &SelectUpByLines,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        let text_layout_details = &self.text_layout_details(window);
13347        self.change_selections(Default::default(), window, cx, |s| {
13348            s.move_heads_with(|map, head, goal| {
13349                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13350            })
13351        })
13352    }
13353
13354    pub fn select_page_up(
13355        &mut self,
13356        _: &SelectPageUp,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        let Some(row_count) = self.visible_row_count() else {
13361            return;
13362        };
13363
13364        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13365
13366        let text_layout_details = &self.text_layout_details(window);
13367
13368        self.change_selections(Default::default(), window, cx, |s| {
13369            s.move_heads_with(|map, head, goal| {
13370                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13371            })
13372        })
13373    }
13374
13375    pub fn move_page_up(
13376        &mut self,
13377        action: &MovePageUp,
13378        window: &mut Window,
13379        cx: &mut Context<Self>,
13380    ) {
13381        if self.take_rename(true, window, cx).is_some() {
13382            return;
13383        }
13384
13385        if self
13386            .context_menu
13387            .borrow_mut()
13388            .as_mut()
13389            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13390            .unwrap_or(false)
13391        {
13392            return;
13393        }
13394
13395        if matches!(self.mode, EditorMode::SingleLine) {
13396            cx.propagate();
13397            return;
13398        }
13399
13400        let Some(row_count) = self.visible_row_count() else {
13401            return;
13402        };
13403
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405
13406        let effects = if action.center_cursor {
13407            SelectionEffects::scroll(Autoscroll::center())
13408        } else {
13409            SelectionEffects::default()
13410        };
13411
13412        let text_layout_details = &self.text_layout_details(window);
13413
13414        self.change_selections(effects, window, cx, |s| {
13415            s.move_with(|map, selection| {
13416                if !selection.is_empty() {
13417                    selection.goal = SelectionGoal::None;
13418                }
13419                let (cursor, goal) = movement::up_by_rows(
13420                    map,
13421                    selection.end,
13422                    row_count,
13423                    selection.goal,
13424                    false,
13425                    text_layout_details,
13426                );
13427                selection.collapse_to(cursor, goal);
13428            });
13429        });
13430    }
13431
13432    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13434        let text_layout_details = &self.text_layout_details(window);
13435        self.change_selections(Default::default(), window, cx, |s| {
13436            s.move_heads_with(|map, head, goal| {
13437                movement::up(map, head, goal, false, text_layout_details)
13438            })
13439        })
13440    }
13441
13442    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13443        self.take_rename(true, window, cx);
13444
13445        if self.mode.is_single_line() {
13446            cx.propagate();
13447            return;
13448        }
13449
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451
13452        let text_layout_details = &self.text_layout_details(window);
13453        let selection_count = self.selections.count();
13454        let first_selection = self.selections.first_anchor();
13455
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.move_with(|map, selection| {
13458                if !selection.is_empty() {
13459                    selection.goal = SelectionGoal::None;
13460                }
13461                let (cursor, goal) = movement::down(
13462                    map,
13463                    selection.end,
13464                    selection.goal,
13465                    false,
13466                    text_layout_details,
13467                );
13468                selection.collapse_to(cursor, goal);
13469            });
13470        });
13471
13472        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13473        {
13474            cx.propagate();
13475        }
13476    }
13477
13478    pub fn select_page_down(
13479        &mut self,
13480        _: &SelectPageDown,
13481        window: &mut Window,
13482        cx: &mut Context<Self>,
13483    ) {
13484        let Some(row_count) = self.visible_row_count() else {
13485            return;
13486        };
13487
13488        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13489
13490        let text_layout_details = &self.text_layout_details(window);
13491
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_heads_with(|map, head, goal| {
13494                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13495            })
13496        })
13497    }
13498
13499    pub fn move_page_down(
13500        &mut self,
13501        action: &MovePageDown,
13502        window: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) {
13505        if self.take_rename(true, window, cx).is_some() {
13506            return;
13507        }
13508
13509        if self
13510            .context_menu
13511            .borrow_mut()
13512            .as_mut()
13513            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13514            .unwrap_or(false)
13515        {
13516            return;
13517        }
13518
13519        if matches!(self.mode, EditorMode::SingleLine) {
13520            cx.propagate();
13521            return;
13522        }
13523
13524        let Some(row_count) = self.visible_row_count() else {
13525            return;
13526        };
13527
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13529
13530        let effects = if action.center_cursor {
13531            SelectionEffects::scroll(Autoscroll::center())
13532        } else {
13533            SelectionEffects::default()
13534        };
13535
13536        let text_layout_details = &self.text_layout_details(window);
13537        self.change_selections(effects, window, cx, |s| {
13538            s.move_with(|map, selection| {
13539                if !selection.is_empty() {
13540                    selection.goal = SelectionGoal::None;
13541                }
13542                let (cursor, goal) = movement::down_by_rows(
13543                    map,
13544                    selection.end,
13545                    row_count,
13546                    selection.goal,
13547                    false,
13548                    text_layout_details,
13549                );
13550                selection.collapse_to(cursor, goal);
13551            });
13552        });
13553    }
13554
13555    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13557        let text_layout_details = &self.text_layout_details(window);
13558        self.change_selections(Default::default(), window, cx, |s| {
13559            s.move_heads_with(|map, head, goal| {
13560                movement::down(map, head, goal, false, text_layout_details)
13561            })
13562        });
13563    }
13564
13565    pub fn context_menu_first(
13566        &mut self,
13567        _: &ContextMenuFirst,
13568        window: &mut Window,
13569        cx: &mut Context<Self>,
13570    ) {
13571        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13572            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13573        }
13574    }
13575
13576    pub fn context_menu_prev(
13577        &mut self,
13578        _: &ContextMenuPrevious,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13583            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13584        }
13585    }
13586
13587    pub fn context_menu_next(
13588        &mut self,
13589        _: &ContextMenuNext,
13590        window: &mut Window,
13591        cx: &mut Context<Self>,
13592    ) {
13593        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13594            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13595        }
13596    }
13597
13598    pub fn context_menu_last(
13599        &mut self,
13600        _: &ContextMenuLast,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13605            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13606        }
13607    }
13608
13609    pub fn signature_help_prev(
13610        &mut self,
13611        _: &SignatureHelpPrevious,
13612        _: &mut Window,
13613        cx: &mut Context<Self>,
13614    ) {
13615        if let Some(popover) = self.signature_help_state.popover_mut() {
13616            if popover.current_signature == 0 {
13617                popover.current_signature = popover.signatures.len() - 1;
13618            } else {
13619                popover.current_signature -= 1;
13620            }
13621            cx.notify();
13622        }
13623    }
13624
13625    pub fn signature_help_next(
13626        &mut self,
13627        _: &SignatureHelpNext,
13628        _: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        if let Some(popover) = self.signature_help_state.popover_mut() {
13632            if popover.current_signature + 1 == popover.signatures.len() {
13633                popover.current_signature = 0;
13634            } else {
13635                popover.current_signature += 1;
13636            }
13637            cx.notify();
13638        }
13639    }
13640
13641    pub fn move_to_previous_word_start(
13642        &mut self,
13643        _: &MoveToPreviousWordStart,
13644        window: &mut Window,
13645        cx: &mut Context<Self>,
13646    ) {
13647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13648        self.change_selections(Default::default(), window, cx, |s| {
13649            s.move_cursors_with(|map, head, _| {
13650                (
13651                    movement::previous_word_start(map, head),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn move_to_previous_subword_start(
13659        &mut self,
13660        _: &MoveToPreviousSubwordStart,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.move_cursors_with(|map, head, _| {
13667                (
13668                    movement::previous_subword_start(map, head),
13669                    SelectionGoal::None,
13670                )
13671            });
13672        })
13673    }
13674
13675    pub fn select_to_previous_word_start(
13676        &mut self,
13677        _: &SelectToPreviousWordStart,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13682        self.change_selections(Default::default(), window, cx, |s| {
13683            s.move_heads_with(|map, head, _| {
13684                (
13685                    movement::previous_word_start(map, head),
13686                    SelectionGoal::None,
13687                )
13688            });
13689        })
13690    }
13691
13692    pub fn select_to_previous_subword_start(
13693        &mut self,
13694        _: &SelectToPreviousSubwordStart,
13695        window: &mut Window,
13696        cx: &mut Context<Self>,
13697    ) {
13698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_heads_with(|map, head, _| {
13701                (
13702                    movement::previous_subword_start(map, head),
13703                    SelectionGoal::None,
13704                )
13705            });
13706        })
13707    }
13708
13709    pub fn delete_to_previous_word_start(
13710        &mut self,
13711        action: &DeleteToPreviousWordStart,
13712        window: &mut Window,
13713        cx: &mut Context<Self>,
13714    ) {
13715        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13716        self.transact(window, cx, |this, window, cx| {
13717            this.select_autoclose_pair(window, cx);
13718            this.change_selections(Default::default(), window, cx, |s| {
13719                s.move_with(|map, selection| {
13720                    if selection.is_empty() {
13721                        let mut cursor = if action.ignore_newlines {
13722                            movement::previous_word_start(map, selection.head())
13723                        } else {
13724                            movement::previous_word_start_or_newline(map, selection.head())
13725                        };
13726                        cursor = movement::adjust_greedy_deletion(
13727                            map,
13728                            selection.head(),
13729                            cursor,
13730                            action.ignore_brackets,
13731                        );
13732                        selection.set_head(cursor, SelectionGoal::None);
13733                    }
13734                });
13735            });
13736            this.insert("", window, cx);
13737        });
13738    }
13739
13740    pub fn delete_to_previous_subword_start(
13741        &mut self,
13742        _: &DeleteToPreviousSubwordStart,
13743        window: &mut Window,
13744        cx: &mut Context<Self>,
13745    ) {
13746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13747        self.transact(window, cx, |this, window, cx| {
13748            this.select_autoclose_pair(window, cx);
13749            this.change_selections(Default::default(), window, cx, |s| {
13750                s.move_with(|map, selection| {
13751                    if selection.is_empty() {
13752                        let mut cursor = movement::previous_subword_start(map, selection.head());
13753                        cursor =
13754                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13755                        selection.set_head(cursor, SelectionGoal::None);
13756                    }
13757                });
13758            });
13759            this.insert("", window, cx);
13760        });
13761    }
13762
13763    pub fn move_to_next_word_end(
13764        &mut self,
13765        _: &MoveToNextWordEnd,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_cursors_with(|map, head, _| {
13772                (movement::next_word_end(map, head), SelectionGoal::None)
13773            });
13774        })
13775    }
13776
13777    pub fn move_to_next_subword_end(
13778        &mut self,
13779        _: &MoveToNextSubwordEnd,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) {
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_cursors_with(|map, head, _| {
13786                (movement::next_subword_end(map, head), SelectionGoal::None)
13787            });
13788        })
13789    }
13790
13791    pub fn select_to_next_word_end(
13792        &mut self,
13793        _: &SelectToNextWordEnd,
13794        window: &mut Window,
13795        cx: &mut Context<Self>,
13796    ) {
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.move_heads_with(|map, head, _| {
13800                (movement::next_word_end(map, head), SelectionGoal::None)
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_next_subword_end(
13806        &mut self,
13807        _: &SelectToNextSubwordEnd,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_heads_with(|map, head, _| {
13814                (movement::next_subword_end(map, head), SelectionGoal::None)
13815            });
13816        })
13817    }
13818
13819    pub fn delete_to_next_word_end(
13820        &mut self,
13821        action: &DeleteToNextWordEnd,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13826        self.transact(window, cx, |this, window, cx| {
13827            this.change_selections(Default::default(), window, cx, |s| {
13828                s.move_with(|map, selection| {
13829                    if selection.is_empty() {
13830                        let mut cursor = if action.ignore_newlines {
13831                            movement::next_word_end(map, selection.head())
13832                        } else {
13833                            movement::next_word_end_or_newline(map, selection.head())
13834                        };
13835                        cursor = movement::adjust_greedy_deletion(
13836                            map,
13837                            selection.head(),
13838                            cursor,
13839                            action.ignore_brackets,
13840                        );
13841                        selection.set_head(cursor, SelectionGoal::None);
13842                    }
13843                });
13844            });
13845            this.insert("", window, cx);
13846        });
13847    }
13848
13849    pub fn delete_to_next_subword_end(
13850        &mut self,
13851        _: &DeleteToNextSubwordEnd,
13852        window: &mut Window,
13853        cx: &mut Context<Self>,
13854    ) {
13855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13856        self.transact(window, cx, |this, window, cx| {
13857            this.change_selections(Default::default(), window, cx, |s| {
13858                s.move_with(|map, selection| {
13859                    if selection.is_empty() {
13860                        let mut cursor = movement::next_subword_end(map, selection.head());
13861                        cursor =
13862                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13863                        selection.set_head(cursor, SelectionGoal::None);
13864                    }
13865                });
13866            });
13867            this.insert("", window, cx);
13868        });
13869    }
13870
13871    pub fn move_to_beginning_of_line(
13872        &mut self,
13873        action: &MoveToBeginningOfLine,
13874        window: &mut Window,
13875        cx: &mut Context<Self>,
13876    ) {
13877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13878        self.change_selections(Default::default(), window, cx, |s| {
13879            s.move_cursors_with(|map, head, _| {
13880                (
13881                    movement::indented_line_beginning(
13882                        map,
13883                        head,
13884                        action.stop_at_soft_wraps,
13885                        action.stop_at_indent,
13886                    ),
13887                    SelectionGoal::None,
13888                )
13889            });
13890        })
13891    }
13892
13893    pub fn select_to_beginning_of_line(
13894        &mut self,
13895        action: &SelectToBeginningOfLine,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13900        self.change_selections(Default::default(), window, cx, |s| {
13901            s.move_heads_with(|map, head, _| {
13902                (
13903                    movement::indented_line_beginning(
13904                        map,
13905                        head,
13906                        action.stop_at_soft_wraps,
13907                        action.stop_at_indent,
13908                    ),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        });
13913    }
13914
13915    pub fn delete_to_beginning_of_line(
13916        &mut self,
13917        action: &DeleteToBeginningOfLine,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13922        self.transact(window, cx, |this, window, cx| {
13923            this.change_selections(Default::default(), window, cx, |s| {
13924                s.move_with(|_, selection| {
13925                    selection.reversed = true;
13926                });
13927            });
13928
13929            this.select_to_beginning_of_line(
13930                &SelectToBeginningOfLine {
13931                    stop_at_soft_wraps: false,
13932                    stop_at_indent: action.stop_at_indent,
13933                },
13934                window,
13935                cx,
13936            );
13937            this.backspace(&Backspace, window, cx);
13938        });
13939    }
13940
13941    pub fn move_to_end_of_line(
13942        &mut self,
13943        action: &MoveToEndOfLine,
13944        window: &mut Window,
13945        cx: &mut Context<Self>,
13946    ) {
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13948        self.change_selections(Default::default(), window, cx, |s| {
13949            s.move_cursors_with(|map, head, _| {
13950                (
13951                    movement::line_end(map, head, action.stop_at_soft_wraps),
13952                    SelectionGoal::None,
13953                )
13954            });
13955        })
13956    }
13957
13958    pub fn select_to_end_of_line(
13959        &mut self,
13960        action: &SelectToEndOfLine,
13961        window: &mut Window,
13962        cx: &mut Context<Self>,
13963    ) {
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        self.change_selections(Default::default(), window, cx, |s| {
13966            s.move_heads_with(|map, head, _| {
13967                (
13968                    movement::line_end(map, head, action.stop_at_soft_wraps),
13969                    SelectionGoal::None,
13970                )
13971            });
13972        })
13973    }
13974
13975    pub fn delete_to_end_of_line(
13976        &mut self,
13977        _: &DeleteToEndOfLine,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13982        self.transact(window, cx, |this, window, cx| {
13983            this.select_to_end_of_line(
13984                &SelectToEndOfLine {
13985                    stop_at_soft_wraps: false,
13986                },
13987                window,
13988                cx,
13989            );
13990            this.delete(&Delete, window, cx);
13991        });
13992    }
13993
13994    pub fn cut_to_end_of_line(
13995        &mut self,
13996        action: &CutToEndOfLine,
13997        window: &mut Window,
13998        cx: &mut Context<Self>,
13999    ) {
14000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14001        self.transact(window, cx, |this, window, cx| {
14002            this.select_to_end_of_line(
14003                &SelectToEndOfLine {
14004                    stop_at_soft_wraps: false,
14005                },
14006                window,
14007                cx,
14008            );
14009            if !action.stop_at_newlines {
14010                this.change_selections(Default::default(), window, cx, |s| {
14011                    s.move_with(|_, sel| {
14012                        if sel.is_empty() {
14013                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14014                        }
14015                    });
14016                });
14017            }
14018            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14019            let item = this.cut_common(false, window, cx);
14020            cx.write_to_clipboard(item);
14021        });
14022    }
14023
14024    pub fn move_to_start_of_paragraph(
14025        &mut self,
14026        _: &MoveToStartOfParagraph,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) {
14030        if matches!(self.mode, EditorMode::SingleLine) {
14031            cx.propagate();
14032            return;
14033        }
14034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14035        self.change_selections(Default::default(), window, cx, |s| {
14036            s.move_with(|map, selection| {
14037                selection.collapse_to(
14038                    movement::start_of_paragraph(map, selection.head(), 1),
14039                    SelectionGoal::None,
14040                )
14041            });
14042        })
14043    }
14044
14045    pub fn move_to_end_of_paragraph(
14046        &mut self,
14047        _: &MoveToEndOfParagraph,
14048        window: &mut Window,
14049        cx: &mut Context<Self>,
14050    ) {
14051        if matches!(self.mode, EditorMode::SingleLine) {
14052            cx.propagate();
14053            return;
14054        }
14055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14056        self.change_selections(Default::default(), window, cx, |s| {
14057            s.move_with(|map, selection| {
14058                selection.collapse_to(
14059                    movement::end_of_paragraph(map, selection.head(), 1),
14060                    SelectionGoal::None,
14061                )
14062            });
14063        })
14064    }
14065
14066    pub fn select_to_start_of_paragraph(
14067        &mut self,
14068        _: &SelectToStartOfParagraph,
14069        window: &mut Window,
14070        cx: &mut Context<Self>,
14071    ) {
14072        if matches!(self.mode, EditorMode::SingleLine) {
14073            cx.propagate();
14074            return;
14075        }
14076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14077        self.change_selections(Default::default(), window, cx, |s| {
14078            s.move_heads_with(|map, head, _| {
14079                (
14080                    movement::start_of_paragraph(map, head, 1),
14081                    SelectionGoal::None,
14082                )
14083            });
14084        })
14085    }
14086
14087    pub fn select_to_end_of_paragraph(
14088        &mut self,
14089        _: &SelectToEndOfParagraph,
14090        window: &mut Window,
14091        cx: &mut Context<Self>,
14092    ) {
14093        if matches!(self.mode, EditorMode::SingleLine) {
14094            cx.propagate();
14095            return;
14096        }
14097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14098        self.change_selections(Default::default(), window, cx, |s| {
14099            s.move_heads_with(|map, head, _| {
14100                (
14101                    movement::end_of_paragraph(map, head, 1),
14102                    SelectionGoal::None,
14103                )
14104            });
14105        })
14106    }
14107
14108    pub fn move_to_start_of_excerpt(
14109        &mut self,
14110        _: &MoveToStartOfExcerpt,
14111        window: &mut Window,
14112        cx: &mut Context<Self>,
14113    ) {
14114        if matches!(self.mode, EditorMode::SingleLine) {
14115            cx.propagate();
14116            return;
14117        }
14118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14119        self.change_selections(Default::default(), window, cx, |s| {
14120            s.move_with(|map, selection| {
14121                selection.collapse_to(
14122                    movement::start_of_excerpt(
14123                        map,
14124                        selection.head(),
14125                        workspace::searchable::Direction::Prev,
14126                    ),
14127                    SelectionGoal::None,
14128                )
14129            });
14130        })
14131    }
14132
14133    pub fn move_to_start_of_next_excerpt(
14134        &mut self,
14135        _: &MoveToStartOfNextExcerpt,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) {
14139        if matches!(self.mode, EditorMode::SingleLine) {
14140            cx.propagate();
14141            return;
14142        }
14143
14144        self.change_selections(Default::default(), window, cx, |s| {
14145            s.move_with(|map, selection| {
14146                selection.collapse_to(
14147                    movement::start_of_excerpt(
14148                        map,
14149                        selection.head(),
14150                        workspace::searchable::Direction::Next,
14151                    ),
14152                    SelectionGoal::None,
14153                )
14154            });
14155        })
14156    }
14157
14158    pub fn move_to_end_of_excerpt(
14159        &mut self,
14160        _: &MoveToEndOfExcerpt,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) {
14164        if matches!(self.mode, EditorMode::SingleLine) {
14165            cx.propagate();
14166            return;
14167        }
14168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14169        self.change_selections(Default::default(), window, cx, |s| {
14170            s.move_with(|map, selection| {
14171                selection.collapse_to(
14172                    movement::end_of_excerpt(
14173                        map,
14174                        selection.head(),
14175                        workspace::searchable::Direction::Next,
14176                    ),
14177                    SelectionGoal::None,
14178                )
14179            });
14180        })
14181    }
14182
14183    pub fn move_to_end_of_previous_excerpt(
14184        &mut self,
14185        _: &MoveToEndOfPreviousExcerpt,
14186        window: &mut Window,
14187        cx: &mut Context<Self>,
14188    ) {
14189        if matches!(self.mode, EditorMode::SingleLine) {
14190            cx.propagate();
14191            return;
14192        }
14193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14194        self.change_selections(Default::default(), window, cx, |s| {
14195            s.move_with(|map, selection| {
14196                selection.collapse_to(
14197                    movement::end_of_excerpt(
14198                        map,
14199                        selection.head(),
14200                        workspace::searchable::Direction::Prev,
14201                    ),
14202                    SelectionGoal::None,
14203                )
14204            });
14205        })
14206    }
14207
14208    pub fn select_to_start_of_excerpt(
14209        &mut self,
14210        _: &SelectToStartOfExcerpt,
14211        window: &mut Window,
14212        cx: &mut Context<Self>,
14213    ) {
14214        if matches!(self.mode, EditorMode::SingleLine) {
14215            cx.propagate();
14216            return;
14217        }
14218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14219        self.change_selections(Default::default(), window, cx, |s| {
14220            s.move_heads_with(|map, head, _| {
14221                (
14222                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14223                    SelectionGoal::None,
14224                )
14225            });
14226        })
14227    }
14228
14229    pub fn select_to_start_of_next_excerpt(
14230        &mut self,
14231        _: &SelectToStartOfNextExcerpt,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        if matches!(self.mode, EditorMode::SingleLine) {
14236            cx.propagate();
14237            return;
14238        }
14239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14240        self.change_selections(Default::default(), window, cx, |s| {
14241            s.move_heads_with(|map, head, _| {
14242                (
14243                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14244                    SelectionGoal::None,
14245                )
14246            });
14247        })
14248    }
14249
14250    pub fn select_to_end_of_excerpt(
14251        &mut self,
14252        _: &SelectToEndOfExcerpt,
14253        window: &mut Window,
14254        cx: &mut Context<Self>,
14255    ) {
14256        if matches!(self.mode, EditorMode::SingleLine) {
14257            cx.propagate();
14258            return;
14259        }
14260        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14261        self.change_selections(Default::default(), window, cx, |s| {
14262            s.move_heads_with(|map, head, _| {
14263                (
14264                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14265                    SelectionGoal::None,
14266                )
14267            });
14268        })
14269    }
14270
14271    pub fn select_to_end_of_previous_excerpt(
14272        &mut self,
14273        _: &SelectToEndOfPreviousExcerpt,
14274        window: &mut Window,
14275        cx: &mut Context<Self>,
14276    ) {
14277        if matches!(self.mode, EditorMode::SingleLine) {
14278            cx.propagate();
14279            return;
14280        }
14281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14282        self.change_selections(Default::default(), window, cx, |s| {
14283            s.move_heads_with(|map, head, _| {
14284                (
14285                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14286                    SelectionGoal::None,
14287                )
14288            });
14289        })
14290    }
14291
14292    pub fn move_to_beginning(
14293        &mut self,
14294        _: &MoveToBeginning,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        if matches!(self.mode, EditorMode::SingleLine) {
14299            cx.propagate();
14300            return;
14301        }
14302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14303        self.change_selections(Default::default(), window, cx, |s| {
14304            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14305        });
14306    }
14307
14308    pub fn select_to_beginning(
14309        &mut self,
14310        _: &SelectToBeginning,
14311        window: &mut Window,
14312        cx: &mut Context<Self>,
14313    ) {
14314        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14315        selection.set_head(Point::zero(), SelectionGoal::None);
14316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14317        self.change_selections(Default::default(), window, cx, |s| {
14318            s.select(vec![selection]);
14319        });
14320    }
14321
14322    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14323        if matches!(self.mode, EditorMode::SingleLine) {
14324            cx.propagate();
14325            return;
14326        }
14327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14328        let cursor = self.buffer.read(cx).read(cx).len();
14329        self.change_selections(Default::default(), window, cx, |s| {
14330            s.select_ranges(vec![cursor..cursor])
14331        });
14332    }
14333
14334    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14335        self.nav_history = nav_history;
14336    }
14337
14338    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14339        self.nav_history.as_ref()
14340    }
14341
14342    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14343        self.push_to_nav_history(
14344            self.selections.newest_anchor().head(),
14345            None,
14346            false,
14347            true,
14348            cx,
14349        );
14350    }
14351
14352    fn push_to_nav_history(
14353        &mut self,
14354        cursor_anchor: Anchor,
14355        new_position: Option<Point>,
14356        is_deactivate: bool,
14357        always: bool,
14358        cx: &mut Context<Self>,
14359    ) {
14360        if let Some(nav_history) = self.nav_history.as_mut() {
14361            let buffer = self.buffer.read(cx).read(cx);
14362            let cursor_position = cursor_anchor.to_point(&buffer);
14363            let scroll_state = self.scroll_manager.anchor();
14364            let scroll_top_row = scroll_state.top_row(&buffer);
14365            drop(buffer);
14366
14367            if let Some(new_position) = new_position {
14368                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14369                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14370                    return;
14371                }
14372            }
14373
14374            nav_history.push(
14375                Some(NavigationData {
14376                    cursor_anchor,
14377                    cursor_position,
14378                    scroll_anchor: scroll_state,
14379                    scroll_top_row,
14380                }),
14381                cx,
14382            );
14383            cx.emit(EditorEvent::PushedToNavHistory {
14384                anchor: cursor_anchor,
14385                is_deactivate,
14386            })
14387        }
14388    }
14389
14390    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14392        let buffer = self.buffer.read(cx).snapshot(cx);
14393        let mut selection = self
14394            .selections
14395            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14396        selection.set_head(buffer.len(), SelectionGoal::None);
14397        self.change_selections(Default::default(), window, cx, |s| {
14398            s.select(vec![selection]);
14399        });
14400    }
14401
14402    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14404        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14405            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14406        });
14407    }
14408
14409    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14411        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14412        let mut selections = self.selections.all::<Point>(&display_map);
14413        let max_point = display_map.buffer_snapshot().max_point();
14414        for selection in &mut selections {
14415            let rows = selection.spanned_rows(true, &display_map);
14416            selection.start = Point::new(rows.start.0, 0);
14417            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14418            selection.reversed = false;
14419        }
14420        self.change_selections(Default::default(), window, cx, |s| {
14421            s.select(selections);
14422        });
14423    }
14424
14425    pub fn split_selection_into_lines(
14426        &mut self,
14427        action: &SplitSelectionIntoLines,
14428        window: &mut Window,
14429        cx: &mut Context<Self>,
14430    ) {
14431        let selections = self
14432            .selections
14433            .all::<Point>(&self.display_snapshot(cx))
14434            .into_iter()
14435            .map(|selection| selection.start..selection.end)
14436            .collect::<Vec<_>>();
14437        self.unfold_ranges(&selections, true, true, cx);
14438
14439        let mut new_selection_ranges = Vec::new();
14440        {
14441            let buffer = self.buffer.read(cx).read(cx);
14442            for selection in selections {
14443                for row in selection.start.row..selection.end.row {
14444                    let line_start = Point::new(row, 0);
14445                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14446
14447                    if action.keep_selections {
14448                        // Keep the selection range for each line
14449                        let selection_start = if row == selection.start.row {
14450                            selection.start
14451                        } else {
14452                            line_start
14453                        };
14454                        new_selection_ranges.push(selection_start..line_end);
14455                    } else {
14456                        // Collapse to cursor at end of line
14457                        new_selection_ranges.push(line_end..line_end);
14458                    }
14459                }
14460
14461                let is_multiline_selection = selection.start.row != selection.end.row;
14462                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14463                // so this action feels more ergonomic when paired with other selection operations
14464                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14465                if !should_skip_last {
14466                    if action.keep_selections {
14467                        if is_multiline_selection {
14468                            let line_start = Point::new(selection.end.row, 0);
14469                            new_selection_ranges.push(line_start..selection.end);
14470                        } else {
14471                            new_selection_ranges.push(selection.start..selection.end);
14472                        }
14473                    } else {
14474                        new_selection_ranges.push(selection.end..selection.end);
14475                    }
14476                }
14477            }
14478        }
14479        self.change_selections(Default::default(), window, cx, |s| {
14480            s.select_ranges(new_selection_ranges);
14481        });
14482    }
14483
14484    pub fn add_selection_above(
14485        &mut self,
14486        action: &AddSelectionAbove,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) {
14490        self.add_selection(true, action.skip_soft_wrap, window, cx);
14491    }
14492
14493    pub fn add_selection_below(
14494        &mut self,
14495        action: &AddSelectionBelow,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) {
14499        self.add_selection(false, action.skip_soft_wrap, window, cx);
14500    }
14501
14502    fn add_selection(
14503        &mut self,
14504        above: bool,
14505        skip_soft_wrap: bool,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) {
14509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14510
14511        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14512        let all_selections = self.selections.all::<Point>(&display_map);
14513        let text_layout_details = self.text_layout_details(window);
14514
14515        let (mut columnar_selections, new_selections_to_columnarize) = {
14516            if let Some(state) = self.add_selections_state.as_ref() {
14517                let columnar_selection_ids: HashSet<_> = state
14518                    .groups
14519                    .iter()
14520                    .flat_map(|group| group.stack.iter())
14521                    .copied()
14522                    .collect();
14523
14524                all_selections
14525                    .into_iter()
14526                    .partition(|s| columnar_selection_ids.contains(&s.id))
14527            } else {
14528                (Vec::new(), all_selections)
14529            }
14530        };
14531
14532        let mut state = self
14533            .add_selections_state
14534            .take()
14535            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14536
14537        for selection in new_selections_to_columnarize {
14538            let range = selection.display_range(&display_map).sorted();
14539            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14540            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14541            let positions = start_x.min(end_x)..start_x.max(end_x);
14542            let mut stack = Vec::new();
14543            for row in range.start.row().0..=range.end.row().0 {
14544                if let Some(selection) = self.selections.build_columnar_selection(
14545                    &display_map,
14546                    DisplayRow(row),
14547                    &positions,
14548                    selection.reversed,
14549                    &text_layout_details,
14550                ) {
14551                    stack.push(selection.id);
14552                    columnar_selections.push(selection);
14553                }
14554            }
14555            if !stack.is_empty() {
14556                if above {
14557                    stack.reverse();
14558                }
14559                state.groups.push(AddSelectionsGroup { above, stack });
14560            }
14561        }
14562
14563        let mut final_selections = Vec::new();
14564        let end_row = if above {
14565            DisplayRow(0)
14566        } else {
14567            display_map.max_point().row()
14568        };
14569
14570        let mut last_added_item_per_group = HashMap::default();
14571        for group in state.groups.iter_mut() {
14572            if let Some(last_id) = group.stack.last() {
14573                last_added_item_per_group.insert(*last_id, group);
14574            }
14575        }
14576
14577        for selection in columnar_selections {
14578            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14579                if above == group.above {
14580                    let range = selection.display_range(&display_map).sorted();
14581                    debug_assert_eq!(range.start.row(), range.end.row());
14582                    let mut row = range.start.row();
14583                    let positions =
14584                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14585                            Pixels::from(start)..Pixels::from(end)
14586                        } else {
14587                            let start_x =
14588                                display_map.x_for_display_point(range.start, &text_layout_details);
14589                            let end_x =
14590                                display_map.x_for_display_point(range.end, &text_layout_details);
14591                            start_x.min(end_x)..start_x.max(end_x)
14592                        };
14593
14594                    let mut maybe_new_selection = None;
14595                    let direction = if above { -1 } else { 1 };
14596
14597                    while row != end_row {
14598                        if skip_soft_wrap {
14599                            row = display_map
14600                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14601                                .row();
14602                        } else if above {
14603                            row.0 -= 1;
14604                        } else {
14605                            row.0 += 1;
14606                        }
14607
14608                        if let Some(new_selection) = self.selections.build_columnar_selection(
14609                            &display_map,
14610                            row,
14611                            &positions,
14612                            selection.reversed,
14613                            &text_layout_details,
14614                        ) {
14615                            maybe_new_selection = Some(new_selection);
14616                            break;
14617                        }
14618                    }
14619
14620                    if let Some(new_selection) = maybe_new_selection {
14621                        group.stack.push(new_selection.id);
14622                        if above {
14623                            final_selections.push(new_selection);
14624                            final_selections.push(selection);
14625                        } else {
14626                            final_selections.push(selection);
14627                            final_selections.push(new_selection);
14628                        }
14629                    } else {
14630                        final_selections.push(selection);
14631                    }
14632                } else {
14633                    group.stack.pop();
14634                }
14635            } else {
14636                final_selections.push(selection);
14637            }
14638        }
14639
14640        self.change_selections(Default::default(), window, cx, |s| {
14641            s.select(final_selections);
14642        });
14643
14644        let final_selection_ids: HashSet<_> = self
14645            .selections
14646            .all::<Point>(&display_map)
14647            .iter()
14648            .map(|s| s.id)
14649            .collect();
14650        state.groups.retain_mut(|group| {
14651            // selections might get merged above so we remove invalid items from stacks
14652            group.stack.retain(|id| final_selection_ids.contains(id));
14653
14654            // single selection in stack can be treated as initial state
14655            group.stack.len() > 1
14656        });
14657
14658        if !state.groups.is_empty() {
14659            self.add_selections_state = Some(state);
14660        }
14661    }
14662
14663    fn select_match_ranges(
14664        &mut self,
14665        range: Range<MultiBufferOffset>,
14666        reversed: bool,
14667        replace_newest: bool,
14668        auto_scroll: Option<Autoscroll>,
14669        window: &mut Window,
14670        cx: &mut Context<Editor>,
14671    ) {
14672        self.unfold_ranges(
14673            std::slice::from_ref(&range),
14674            false,
14675            auto_scroll.is_some(),
14676            cx,
14677        );
14678        let effects = if let Some(scroll) = auto_scroll {
14679            SelectionEffects::scroll(scroll)
14680        } else {
14681            SelectionEffects::no_scroll()
14682        };
14683        self.change_selections(effects, window, cx, |s| {
14684            if replace_newest {
14685                s.delete(s.newest_anchor().id);
14686            }
14687            if reversed {
14688                s.insert_range(range.end..range.start);
14689            } else {
14690                s.insert_range(range);
14691            }
14692        });
14693    }
14694
14695    pub fn select_next_match_internal(
14696        &mut self,
14697        display_map: &DisplaySnapshot,
14698        replace_newest: bool,
14699        autoscroll: Option<Autoscroll>,
14700        window: &mut Window,
14701        cx: &mut Context<Self>,
14702    ) -> Result<()> {
14703        let buffer = display_map.buffer_snapshot();
14704        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14705        if let Some(mut select_next_state) = self.select_next_state.take() {
14706            let query = &select_next_state.query;
14707            if !select_next_state.done {
14708                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14709                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14710                let mut next_selected_range = None;
14711
14712                let bytes_after_last_selection =
14713                    buffer.bytes_in_range(last_selection.end..buffer.len());
14714                let bytes_before_first_selection =
14715                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14716                let query_matches = query
14717                    .stream_find_iter(bytes_after_last_selection)
14718                    .map(|result| (last_selection.end, result))
14719                    .chain(
14720                        query
14721                            .stream_find_iter(bytes_before_first_selection)
14722                            .map(|result| (MultiBufferOffset(0), result)),
14723                    );
14724
14725                for (start_offset, query_match) in query_matches {
14726                    let query_match = query_match.unwrap(); // can only fail due to I/O
14727                    let offset_range =
14728                        start_offset + query_match.start()..start_offset + query_match.end();
14729
14730                    if !select_next_state.wordwise
14731                        || (!buffer.is_inside_word(offset_range.start, None)
14732                            && !buffer.is_inside_word(offset_range.end, None))
14733                    {
14734                        let idx = selections
14735                            .partition_point(|selection| selection.end <= offset_range.start);
14736                        let overlaps = selections
14737                            .get(idx)
14738                            .map_or(false, |selection| selection.start < offset_range.end);
14739
14740                        if !overlaps {
14741                            next_selected_range = Some(offset_range);
14742                            break;
14743                        }
14744                    }
14745                }
14746
14747                if let Some(next_selected_range) = next_selected_range {
14748                    self.select_match_ranges(
14749                        next_selected_range,
14750                        last_selection.reversed,
14751                        replace_newest,
14752                        autoscroll,
14753                        window,
14754                        cx,
14755                    );
14756                } else {
14757                    select_next_state.done = true;
14758                }
14759            }
14760
14761            self.select_next_state = Some(select_next_state);
14762        } else {
14763            let mut only_carets = true;
14764            let mut same_text_selected = true;
14765            let mut selected_text = None;
14766
14767            let mut selections_iter = selections.iter().peekable();
14768            while let Some(selection) = selections_iter.next() {
14769                if selection.start != selection.end {
14770                    only_carets = false;
14771                }
14772
14773                if same_text_selected {
14774                    if selected_text.is_none() {
14775                        selected_text =
14776                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14777                    }
14778
14779                    if let Some(next_selection) = selections_iter.peek() {
14780                        if next_selection.len() == selection.len() {
14781                            let next_selected_text = buffer
14782                                .text_for_range(next_selection.range())
14783                                .collect::<String>();
14784                            if Some(next_selected_text) != selected_text {
14785                                same_text_selected = false;
14786                                selected_text = None;
14787                            }
14788                        } else {
14789                            same_text_selected = false;
14790                            selected_text = None;
14791                        }
14792                    }
14793                }
14794            }
14795
14796            if only_carets {
14797                for selection in &mut selections {
14798                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14799                    selection.start = word_range.start;
14800                    selection.end = word_range.end;
14801                    selection.goal = SelectionGoal::None;
14802                    selection.reversed = false;
14803                    self.select_match_ranges(
14804                        selection.start..selection.end,
14805                        selection.reversed,
14806                        replace_newest,
14807                        autoscroll,
14808                        window,
14809                        cx,
14810                    );
14811                }
14812
14813                if selections.len() == 1 {
14814                    let selection = selections
14815                        .last()
14816                        .expect("ensured that there's only one selection");
14817                    let query = buffer
14818                        .text_for_range(selection.start..selection.end)
14819                        .collect::<String>();
14820                    let is_empty = query.is_empty();
14821                    let select_state = SelectNextState {
14822                        query: self.build_query(&[query], cx)?,
14823                        wordwise: true,
14824                        done: is_empty,
14825                    };
14826                    self.select_next_state = Some(select_state);
14827                } else {
14828                    self.select_next_state = None;
14829                }
14830            } else if let Some(selected_text) = selected_text {
14831                self.select_next_state = Some(SelectNextState {
14832                    query: self.build_query(&[selected_text], cx)?,
14833                    wordwise: false,
14834                    done: false,
14835                });
14836                self.select_next_match_internal(
14837                    display_map,
14838                    replace_newest,
14839                    autoscroll,
14840                    window,
14841                    cx,
14842                )?;
14843            }
14844        }
14845        Ok(())
14846    }
14847
14848    pub fn select_all_matches(
14849        &mut self,
14850        _action: &SelectAllMatches,
14851        window: &mut Window,
14852        cx: &mut Context<Self>,
14853    ) -> Result<()> {
14854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14855
14856        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14857
14858        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14859        let Some(select_next_state) = self.select_next_state.as_mut() else {
14860            return Ok(());
14861        };
14862        if select_next_state.done {
14863            return Ok(());
14864        }
14865
14866        let mut new_selections = Vec::new();
14867
14868        let reversed = self
14869            .selections
14870            .oldest::<MultiBufferOffset>(&display_map)
14871            .reversed;
14872        let buffer = display_map.buffer_snapshot();
14873        let query_matches = select_next_state
14874            .query
14875            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14876
14877        for query_match in query_matches.into_iter() {
14878            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14879            let offset_range = if reversed {
14880                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14881            } else {
14882                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14883            };
14884
14885            if !select_next_state.wordwise
14886                || (!buffer.is_inside_word(offset_range.start, None)
14887                    && !buffer.is_inside_word(offset_range.end, None))
14888            {
14889                new_selections.push(offset_range.start..offset_range.end);
14890            }
14891        }
14892
14893        select_next_state.done = true;
14894
14895        if new_selections.is_empty() {
14896            log::error!("bug: new_selections is empty in select_all_matches");
14897            return Ok(());
14898        }
14899
14900        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14901        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14902            selections.select_ranges(new_selections)
14903        });
14904
14905        Ok(())
14906    }
14907
14908    pub fn select_next(
14909        &mut self,
14910        action: &SelectNext,
14911        window: &mut Window,
14912        cx: &mut Context<Self>,
14913    ) -> Result<()> {
14914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14916        self.select_next_match_internal(
14917            &display_map,
14918            action.replace_newest,
14919            Some(Autoscroll::newest()),
14920            window,
14921            cx,
14922        )?;
14923        Ok(())
14924    }
14925
14926    pub fn select_previous(
14927        &mut self,
14928        action: &SelectPrevious,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) -> Result<()> {
14932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14934        let buffer = display_map.buffer_snapshot();
14935        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14936        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14937            let query = &select_prev_state.query;
14938            if !select_prev_state.done {
14939                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14940                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14941                let mut next_selected_range = None;
14942                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14943                let bytes_before_last_selection =
14944                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14945                let bytes_after_first_selection =
14946                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14947                let query_matches = query
14948                    .stream_find_iter(bytes_before_last_selection)
14949                    .map(|result| (last_selection.start, result))
14950                    .chain(
14951                        query
14952                            .stream_find_iter(bytes_after_first_selection)
14953                            .map(|result| (buffer.len(), result)),
14954                    );
14955                for (end_offset, query_match) in query_matches {
14956                    let query_match = query_match.unwrap(); // can only fail due to I/O
14957                    let offset_range =
14958                        end_offset - query_match.end()..end_offset - query_match.start();
14959
14960                    if !select_prev_state.wordwise
14961                        || (!buffer.is_inside_word(offset_range.start, None)
14962                            && !buffer.is_inside_word(offset_range.end, None))
14963                    {
14964                        next_selected_range = Some(offset_range);
14965                        break;
14966                    }
14967                }
14968
14969                if let Some(next_selected_range) = next_selected_range {
14970                    self.select_match_ranges(
14971                        next_selected_range,
14972                        last_selection.reversed,
14973                        action.replace_newest,
14974                        Some(Autoscroll::newest()),
14975                        window,
14976                        cx,
14977                    );
14978                } else {
14979                    select_prev_state.done = true;
14980                }
14981            }
14982
14983            self.select_prev_state = Some(select_prev_state);
14984        } else {
14985            let mut only_carets = true;
14986            let mut same_text_selected = true;
14987            let mut selected_text = None;
14988
14989            let mut selections_iter = selections.iter().peekable();
14990            while let Some(selection) = selections_iter.next() {
14991                if selection.start != selection.end {
14992                    only_carets = false;
14993                }
14994
14995                if same_text_selected {
14996                    if selected_text.is_none() {
14997                        selected_text =
14998                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14999                    }
15000
15001                    if let Some(next_selection) = selections_iter.peek() {
15002                        if next_selection.len() == selection.len() {
15003                            let next_selected_text = buffer
15004                                .text_for_range(next_selection.range())
15005                                .collect::<String>();
15006                            if Some(next_selected_text) != selected_text {
15007                                same_text_selected = false;
15008                                selected_text = None;
15009                            }
15010                        } else {
15011                            same_text_selected = false;
15012                            selected_text = None;
15013                        }
15014                    }
15015                }
15016            }
15017
15018            if only_carets {
15019                for selection in &mut selections {
15020                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15021                    selection.start = word_range.start;
15022                    selection.end = word_range.end;
15023                    selection.goal = SelectionGoal::None;
15024                    selection.reversed = false;
15025                    self.select_match_ranges(
15026                        selection.start..selection.end,
15027                        selection.reversed,
15028                        action.replace_newest,
15029                        Some(Autoscroll::newest()),
15030                        window,
15031                        cx,
15032                    );
15033                }
15034                if selections.len() == 1 {
15035                    let selection = selections
15036                        .last()
15037                        .expect("ensured that there's only one selection");
15038                    let query = buffer
15039                        .text_for_range(selection.start..selection.end)
15040                        .collect::<String>();
15041                    let is_empty = query.is_empty();
15042                    let select_state = SelectNextState {
15043                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15044                        wordwise: true,
15045                        done: is_empty,
15046                    };
15047                    self.select_prev_state = Some(select_state);
15048                } else {
15049                    self.select_prev_state = None;
15050                }
15051            } else if let Some(selected_text) = selected_text {
15052                self.select_prev_state = Some(SelectNextState {
15053                    query: self
15054                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15055                    wordwise: false,
15056                    done: false,
15057                });
15058                self.select_previous(action, window, cx)?;
15059            }
15060        }
15061        Ok(())
15062    }
15063
15064    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15065    /// setting the case sensitivity based on the global
15066    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15067    /// editor's settings.
15068    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15069    where
15070        I: IntoIterator<Item = P>,
15071        P: AsRef<[u8]>,
15072    {
15073        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15074            || EditorSettings::get_global(cx).search.case_sensitive,
15075            |value| value,
15076        );
15077
15078        let mut builder = AhoCorasickBuilder::new();
15079        builder.ascii_case_insensitive(!case_sensitive);
15080        builder.build(patterns)
15081    }
15082
15083    pub fn find_next_match(
15084        &mut self,
15085        _: &FindNextMatch,
15086        window: &mut Window,
15087        cx: &mut Context<Self>,
15088    ) -> Result<()> {
15089        let selections = self.selections.disjoint_anchors_arc();
15090        match selections.first() {
15091            Some(first) if selections.len() >= 2 => {
15092                self.change_selections(Default::default(), window, cx, |s| {
15093                    s.select_ranges([first.range()]);
15094                });
15095            }
15096            _ => self.select_next(
15097                &SelectNext {
15098                    replace_newest: true,
15099                },
15100                window,
15101                cx,
15102            )?,
15103        }
15104        Ok(())
15105    }
15106
15107    pub fn find_previous_match(
15108        &mut self,
15109        _: &FindPreviousMatch,
15110        window: &mut Window,
15111        cx: &mut Context<Self>,
15112    ) -> Result<()> {
15113        let selections = self.selections.disjoint_anchors_arc();
15114        match selections.last() {
15115            Some(last) if selections.len() >= 2 => {
15116                self.change_selections(Default::default(), window, cx, |s| {
15117                    s.select_ranges([last.range()]);
15118                });
15119            }
15120            _ => self.select_previous(
15121                &SelectPrevious {
15122                    replace_newest: true,
15123                },
15124                window,
15125                cx,
15126            )?,
15127        }
15128        Ok(())
15129    }
15130
15131    pub fn toggle_comments(
15132        &mut self,
15133        action: &ToggleComments,
15134        window: &mut Window,
15135        cx: &mut Context<Self>,
15136    ) {
15137        if self.read_only(cx) {
15138            return;
15139        }
15140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15141        let text_layout_details = &self.text_layout_details(window);
15142        self.transact(window, cx, |this, window, cx| {
15143            let mut selections = this
15144                .selections
15145                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15146            let mut edits = Vec::new();
15147            let mut selection_edit_ranges = Vec::new();
15148            let mut last_toggled_row = None;
15149            let snapshot = this.buffer.read(cx).read(cx);
15150            let empty_str: Arc<str> = Arc::default();
15151            let mut suffixes_inserted = Vec::new();
15152            let ignore_indent = action.ignore_indent;
15153
15154            fn comment_prefix_range(
15155                snapshot: &MultiBufferSnapshot,
15156                row: MultiBufferRow,
15157                comment_prefix: &str,
15158                comment_prefix_whitespace: &str,
15159                ignore_indent: bool,
15160            ) -> Range<Point> {
15161                let indent_size = if ignore_indent {
15162                    0
15163                } else {
15164                    snapshot.indent_size_for_line(row).len
15165                };
15166
15167                let start = Point::new(row.0, indent_size);
15168
15169                let mut line_bytes = snapshot
15170                    .bytes_in_range(start..snapshot.max_point())
15171                    .flatten()
15172                    .copied();
15173
15174                // If this line currently begins with the line comment prefix, then record
15175                // the range containing the prefix.
15176                if line_bytes
15177                    .by_ref()
15178                    .take(comment_prefix.len())
15179                    .eq(comment_prefix.bytes())
15180                {
15181                    // Include any whitespace that matches the comment prefix.
15182                    let matching_whitespace_len = line_bytes
15183                        .zip(comment_prefix_whitespace.bytes())
15184                        .take_while(|(a, b)| a == b)
15185                        .count() as u32;
15186                    let end = Point::new(
15187                        start.row,
15188                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15189                    );
15190                    start..end
15191                } else {
15192                    start..start
15193                }
15194            }
15195
15196            fn comment_suffix_range(
15197                snapshot: &MultiBufferSnapshot,
15198                row: MultiBufferRow,
15199                comment_suffix: &str,
15200                comment_suffix_has_leading_space: bool,
15201            ) -> Range<Point> {
15202                let end = Point::new(row.0, snapshot.line_len(row));
15203                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15204
15205                let mut line_end_bytes = snapshot
15206                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15207                    .flatten()
15208                    .copied();
15209
15210                let leading_space_len = if suffix_start_column > 0
15211                    && line_end_bytes.next() == Some(b' ')
15212                    && comment_suffix_has_leading_space
15213                {
15214                    1
15215                } else {
15216                    0
15217                };
15218
15219                // If this line currently begins with the line comment prefix, then record
15220                // the range containing the prefix.
15221                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15222                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15223                    start..end
15224                } else {
15225                    end..end
15226                }
15227            }
15228
15229            // TODO: Handle selections that cross excerpts
15230            for selection in &mut selections {
15231                let start_column = snapshot
15232                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15233                    .len;
15234                let language = if let Some(language) =
15235                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15236                {
15237                    language
15238                } else {
15239                    continue;
15240                };
15241
15242                selection_edit_ranges.clear();
15243
15244                // If multiple selections contain a given row, avoid processing that
15245                // row more than once.
15246                let mut start_row = MultiBufferRow(selection.start.row);
15247                if last_toggled_row == Some(start_row) {
15248                    start_row = start_row.next_row();
15249                }
15250                let end_row =
15251                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15252                        MultiBufferRow(selection.end.row - 1)
15253                    } else {
15254                        MultiBufferRow(selection.end.row)
15255                    };
15256                last_toggled_row = Some(end_row);
15257
15258                if start_row > end_row {
15259                    continue;
15260                }
15261
15262                // If the language has line comments, toggle those.
15263                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15264
15265                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15266                if ignore_indent {
15267                    full_comment_prefixes = full_comment_prefixes
15268                        .into_iter()
15269                        .map(|s| Arc::from(s.trim_end()))
15270                        .collect();
15271                }
15272
15273                if !full_comment_prefixes.is_empty() {
15274                    let first_prefix = full_comment_prefixes
15275                        .first()
15276                        .expect("prefixes is non-empty");
15277                    let prefix_trimmed_lengths = full_comment_prefixes
15278                        .iter()
15279                        .map(|p| p.trim_end_matches(' ').len())
15280                        .collect::<SmallVec<[usize; 4]>>();
15281
15282                    let mut all_selection_lines_are_comments = true;
15283
15284                    for row in start_row.0..=end_row.0 {
15285                        let row = MultiBufferRow(row);
15286                        if start_row < end_row && snapshot.is_line_blank(row) {
15287                            continue;
15288                        }
15289
15290                        let prefix_range = full_comment_prefixes
15291                            .iter()
15292                            .zip(prefix_trimmed_lengths.iter().copied())
15293                            .map(|(prefix, trimmed_prefix_len)| {
15294                                comment_prefix_range(
15295                                    snapshot.deref(),
15296                                    row,
15297                                    &prefix[..trimmed_prefix_len],
15298                                    &prefix[trimmed_prefix_len..],
15299                                    ignore_indent,
15300                                )
15301                            })
15302                            .max_by_key(|range| range.end.column - range.start.column)
15303                            .expect("prefixes is non-empty");
15304
15305                        if prefix_range.is_empty() {
15306                            all_selection_lines_are_comments = false;
15307                        }
15308
15309                        selection_edit_ranges.push(prefix_range);
15310                    }
15311
15312                    if all_selection_lines_are_comments {
15313                        edits.extend(
15314                            selection_edit_ranges
15315                                .iter()
15316                                .cloned()
15317                                .map(|range| (range, empty_str.clone())),
15318                        );
15319                    } else {
15320                        let min_column = selection_edit_ranges
15321                            .iter()
15322                            .map(|range| range.start.column)
15323                            .min()
15324                            .unwrap_or(0);
15325                        edits.extend(selection_edit_ranges.iter().map(|range| {
15326                            let position = Point::new(range.start.row, min_column);
15327                            (position..position, first_prefix.clone())
15328                        }));
15329                    }
15330                } else if let Some(BlockCommentConfig {
15331                    start: full_comment_prefix,
15332                    end: comment_suffix,
15333                    ..
15334                }) = language.block_comment()
15335                {
15336                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15337                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15338                    let prefix_range = comment_prefix_range(
15339                        snapshot.deref(),
15340                        start_row,
15341                        comment_prefix,
15342                        comment_prefix_whitespace,
15343                        ignore_indent,
15344                    );
15345                    let suffix_range = comment_suffix_range(
15346                        snapshot.deref(),
15347                        end_row,
15348                        comment_suffix.trim_start_matches(' '),
15349                        comment_suffix.starts_with(' '),
15350                    );
15351
15352                    if prefix_range.is_empty() || suffix_range.is_empty() {
15353                        edits.push((
15354                            prefix_range.start..prefix_range.start,
15355                            full_comment_prefix.clone(),
15356                        ));
15357                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15358                        suffixes_inserted.push((end_row, comment_suffix.len()));
15359                    } else {
15360                        edits.push((prefix_range, empty_str.clone()));
15361                        edits.push((suffix_range, empty_str.clone()));
15362                    }
15363                } else {
15364                    continue;
15365                }
15366            }
15367
15368            drop(snapshot);
15369            this.buffer.update(cx, |buffer, cx| {
15370                buffer.edit(edits, None, cx);
15371            });
15372
15373            // Adjust selections so that they end before any comment suffixes that
15374            // were inserted.
15375            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15376            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15377            let snapshot = this.buffer.read(cx).read(cx);
15378            for selection in &mut selections {
15379                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15380                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15381                        Ordering::Less => {
15382                            suffixes_inserted.next();
15383                            continue;
15384                        }
15385                        Ordering::Greater => break,
15386                        Ordering::Equal => {
15387                            if selection.end.column == snapshot.line_len(row) {
15388                                if selection.is_empty() {
15389                                    selection.start.column -= suffix_len as u32;
15390                                }
15391                                selection.end.column -= suffix_len as u32;
15392                            }
15393                            break;
15394                        }
15395                    }
15396                }
15397            }
15398
15399            drop(snapshot);
15400            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15401
15402            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15403            let selections_on_single_row = selections.windows(2).all(|selections| {
15404                selections[0].start.row == selections[1].start.row
15405                    && selections[0].end.row == selections[1].end.row
15406                    && selections[0].start.row == selections[0].end.row
15407            });
15408            let selections_selecting = selections
15409                .iter()
15410                .any(|selection| selection.start != selection.end);
15411            let advance_downwards = action.advance_downwards
15412                && selections_on_single_row
15413                && !selections_selecting
15414                && !matches!(this.mode, EditorMode::SingleLine);
15415
15416            if advance_downwards {
15417                let snapshot = this.buffer.read(cx).snapshot(cx);
15418
15419                this.change_selections(Default::default(), window, cx, |s| {
15420                    s.move_cursors_with(|display_snapshot, display_point, _| {
15421                        let mut point = display_point.to_point(display_snapshot);
15422                        point.row += 1;
15423                        point = snapshot.clip_point(point, Bias::Left);
15424                        let display_point = point.to_display_point(display_snapshot);
15425                        let goal = SelectionGoal::HorizontalPosition(
15426                            display_snapshot
15427                                .x_for_display_point(display_point, text_layout_details)
15428                                .into(),
15429                        );
15430                        (display_point, goal)
15431                    })
15432                });
15433            }
15434        });
15435    }
15436
15437    pub fn select_enclosing_symbol(
15438        &mut self,
15439        _: &SelectEnclosingSymbol,
15440        window: &mut Window,
15441        cx: &mut Context<Self>,
15442    ) {
15443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15444
15445        let buffer = self.buffer.read(cx).snapshot(cx);
15446        let old_selections = self
15447            .selections
15448            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15449            .into_boxed_slice();
15450
15451        fn update_selection(
15452            selection: &Selection<MultiBufferOffset>,
15453            buffer_snap: &MultiBufferSnapshot,
15454        ) -> Option<Selection<MultiBufferOffset>> {
15455            let cursor = selection.head();
15456            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15457            for symbol in symbols.iter().rev() {
15458                let start = symbol.range.start.to_offset(buffer_snap);
15459                let end = symbol.range.end.to_offset(buffer_snap);
15460                let new_range = start..end;
15461                if start < selection.start || end > selection.end {
15462                    return Some(Selection {
15463                        id: selection.id,
15464                        start: new_range.start,
15465                        end: new_range.end,
15466                        goal: SelectionGoal::None,
15467                        reversed: selection.reversed,
15468                    });
15469                }
15470            }
15471            None
15472        }
15473
15474        let mut selected_larger_symbol = false;
15475        let new_selections = old_selections
15476            .iter()
15477            .map(|selection| match update_selection(selection, &buffer) {
15478                Some(new_selection) => {
15479                    if new_selection.range() != selection.range() {
15480                        selected_larger_symbol = true;
15481                    }
15482                    new_selection
15483                }
15484                None => selection.clone(),
15485            })
15486            .collect::<Vec<_>>();
15487
15488        if selected_larger_symbol {
15489            self.change_selections(Default::default(), window, cx, |s| {
15490                s.select(new_selections);
15491            });
15492        }
15493    }
15494
15495    pub fn select_larger_syntax_node(
15496        &mut self,
15497        _: &SelectLargerSyntaxNode,
15498        window: &mut Window,
15499        cx: &mut Context<Self>,
15500    ) {
15501        let Some(visible_row_count) = self.visible_row_count() else {
15502            return;
15503        };
15504        let old_selections: Box<[_]> = self
15505            .selections
15506            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15507            .into();
15508        if old_selections.is_empty() {
15509            return;
15510        }
15511
15512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15513
15514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15515        let buffer = self.buffer.read(cx).snapshot(cx);
15516
15517        let mut selected_larger_node = false;
15518        let mut new_selections = old_selections
15519            .iter()
15520            .map(|selection| {
15521                let old_range = selection.start..selection.end;
15522
15523                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15524                    // manually select word at selection
15525                    if ["string_content", "inline"].contains(&node.kind()) {
15526                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15527                        // ignore if word is already selected
15528                        if !word_range.is_empty() && old_range != word_range {
15529                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15530                            // only select word if start and end point belongs to same word
15531                            if word_range == last_word_range {
15532                                selected_larger_node = true;
15533                                return Selection {
15534                                    id: selection.id,
15535                                    start: word_range.start,
15536                                    end: word_range.end,
15537                                    goal: SelectionGoal::None,
15538                                    reversed: selection.reversed,
15539                                };
15540                            }
15541                        }
15542                    }
15543                }
15544
15545                let mut new_range = old_range.clone();
15546                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15547                    new_range = range;
15548                    if !node.is_named() {
15549                        continue;
15550                    }
15551                    if !display_map.intersects_fold(new_range.start)
15552                        && !display_map.intersects_fold(new_range.end)
15553                    {
15554                        break;
15555                    }
15556                }
15557
15558                selected_larger_node |= new_range != old_range;
15559                Selection {
15560                    id: selection.id,
15561                    start: new_range.start,
15562                    end: new_range.end,
15563                    goal: SelectionGoal::None,
15564                    reversed: selection.reversed,
15565                }
15566            })
15567            .collect::<Vec<_>>();
15568
15569        if !selected_larger_node {
15570            return; // don't put this call in the history
15571        }
15572
15573        // scroll based on transformation done to the last selection created by the user
15574        let (last_old, last_new) = old_selections
15575            .last()
15576            .zip(new_selections.last().cloned())
15577            .expect("old_selections isn't empty");
15578
15579        // revert selection
15580        let is_selection_reversed = {
15581            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15582            new_selections.last_mut().expect("checked above").reversed =
15583                should_newest_selection_be_reversed;
15584            should_newest_selection_be_reversed
15585        };
15586
15587        if selected_larger_node {
15588            self.select_syntax_node_history.disable_clearing = true;
15589            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15590                s.select(new_selections.clone());
15591            });
15592            self.select_syntax_node_history.disable_clearing = false;
15593        }
15594
15595        let start_row = last_new.start.to_display_point(&display_map).row().0;
15596        let end_row = last_new.end.to_display_point(&display_map).row().0;
15597        let selection_height = end_row - start_row + 1;
15598        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15599
15600        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15601        let scroll_behavior = if fits_on_the_screen {
15602            self.request_autoscroll(Autoscroll::fit(), cx);
15603            SelectSyntaxNodeScrollBehavior::FitSelection
15604        } else if is_selection_reversed {
15605            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15606            SelectSyntaxNodeScrollBehavior::CursorTop
15607        } else {
15608            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15609            SelectSyntaxNodeScrollBehavior::CursorBottom
15610        };
15611
15612        self.select_syntax_node_history.push((
15613            old_selections,
15614            scroll_behavior,
15615            is_selection_reversed,
15616        ));
15617    }
15618
15619    pub fn select_smaller_syntax_node(
15620        &mut self,
15621        _: &SelectSmallerSyntaxNode,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) {
15625        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15626
15627        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15628            self.select_syntax_node_history.pop()
15629        {
15630            if let Some(selection) = selections.last_mut() {
15631                selection.reversed = is_selection_reversed;
15632            }
15633
15634            self.select_syntax_node_history.disable_clearing = true;
15635            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15636                s.select(selections.to_vec());
15637            });
15638            self.select_syntax_node_history.disable_clearing = false;
15639
15640            match scroll_behavior {
15641                SelectSyntaxNodeScrollBehavior::CursorTop => {
15642                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15643                }
15644                SelectSyntaxNodeScrollBehavior::FitSelection => {
15645                    self.request_autoscroll(Autoscroll::fit(), cx);
15646                }
15647                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15648                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15649                }
15650            }
15651        }
15652    }
15653
15654    pub fn unwrap_syntax_node(
15655        &mut self,
15656        _: &UnwrapSyntaxNode,
15657        window: &mut Window,
15658        cx: &mut Context<Self>,
15659    ) {
15660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15661
15662        let buffer = self.buffer.read(cx).snapshot(cx);
15663        let selections = self
15664            .selections
15665            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15666            .into_iter()
15667            // subtracting the offset requires sorting
15668            .sorted_by_key(|i| i.start);
15669
15670        let full_edits = selections
15671            .into_iter()
15672            .filter_map(|selection| {
15673                let child = if selection.is_empty()
15674                    && let Some((_, ancestor_range)) =
15675                        buffer.syntax_ancestor(selection.start..selection.end)
15676                {
15677                    ancestor_range
15678                } else {
15679                    selection.range()
15680                };
15681
15682                let mut parent = child.clone();
15683                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15684                    parent = ancestor_range;
15685                    if parent.start < child.start || parent.end > child.end {
15686                        break;
15687                    }
15688                }
15689
15690                if parent == child {
15691                    return None;
15692                }
15693                let text = buffer.text_for_range(child).collect::<String>();
15694                Some((selection.id, parent, text))
15695            })
15696            .collect::<Vec<_>>();
15697        if full_edits.is_empty() {
15698            return;
15699        }
15700
15701        self.transact(window, cx, |this, window, cx| {
15702            this.buffer.update(cx, |buffer, cx| {
15703                buffer.edit(
15704                    full_edits
15705                        .iter()
15706                        .map(|(_, p, t)| (p.clone(), t.clone()))
15707                        .collect::<Vec<_>>(),
15708                    None,
15709                    cx,
15710                );
15711            });
15712            this.change_selections(Default::default(), window, cx, |s| {
15713                let mut offset = 0;
15714                let mut selections = vec![];
15715                for (id, parent, text) in full_edits {
15716                    let start = parent.start - offset;
15717                    offset += (parent.end - parent.start) - text.len();
15718                    selections.push(Selection {
15719                        id,
15720                        start,
15721                        end: start + text.len(),
15722                        reversed: false,
15723                        goal: Default::default(),
15724                    });
15725                }
15726                s.select(selections);
15727            });
15728        });
15729    }
15730
15731    pub fn select_next_syntax_node(
15732        &mut self,
15733        _: &SelectNextSyntaxNode,
15734        window: &mut Window,
15735        cx: &mut Context<Self>,
15736    ) {
15737        let old_selections: Box<[_]> = self
15738            .selections
15739            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15740            .into();
15741        if old_selections.is_empty() {
15742            return;
15743        }
15744
15745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15746
15747        let buffer = self.buffer.read(cx).snapshot(cx);
15748        let mut selected_sibling = false;
15749
15750        let new_selections = old_selections
15751            .iter()
15752            .map(|selection| {
15753                let old_range = selection.start..selection.end;
15754
15755                let old_range =
15756                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15757                let excerpt = buffer.excerpt_containing(old_range.clone());
15758
15759                if let Some(mut excerpt) = excerpt
15760                    && let Some(node) = excerpt
15761                        .buffer()
15762                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15763                {
15764                    let new_range = excerpt.map_range_from_buffer(
15765                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15766                    );
15767                    selected_sibling = true;
15768                    Selection {
15769                        id: selection.id,
15770                        start: new_range.start,
15771                        end: new_range.end,
15772                        goal: SelectionGoal::None,
15773                        reversed: selection.reversed,
15774                    }
15775                } else {
15776                    selection.clone()
15777                }
15778            })
15779            .collect::<Vec<_>>();
15780
15781        if selected_sibling {
15782            self.change_selections(
15783                SelectionEffects::scroll(Autoscroll::fit()),
15784                window,
15785                cx,
15786                |s| {
15787                    s.select(new_selections);
15788                },
15789            );
15790        }
15791    }
15792
15793    pub fn select_prev_syntax_node(
15794        &mut self,
15795        _: &SelectPreviousSyntaxNode,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        let old_selections: Box<[_]> = self
15800            .selections
15801            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15802            .into();
15803        if old_selections.is_empty() {
15804            return;
15805        }
15806
15807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15808
15809        let buffer = self.buffer.read(cx).snapshot(cx);
15810        let mut selected_sibling = false;
15811
15812        let new_selections = old_selections
15813            .iter()
15814            .map(|selection| {
15815                let old_range = selection.start..selection.end;
15816                let old_range =
15817                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15818                let excerpt = buffer.excerpt_containing(old_range.clone());
15819
15820                if let Some(mut excerpt) = excerpt
15821                    && let Some(node) = excerpt
15822                        .buffer()
15823                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15824                {
15825                    let new_range = excerpt.map_range_from_buffer(
15826                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15827                    );
15828                    selected_sibling = true;
15829                    Selection {
15830                        id: selection.id,
15831                        start: new_range.start,
15832                        end: new_range.end,
15833                        goal: SelectionGoal::None,
15834                        reversed: selection.reversed,
15835                    }
15836                } else {
15837                    selection.clone()
15838                }
15839            })
15840            .collect::<Vec<_>>();
15841
15842        if selected_sibling {
15843            self.change_selections(
15844                SelectionEffects::scroll(Autoscroll::fit()),
15845                window,
15846                cx,
15847                |s| {
15848                    s.select(new_selections);
15849                },
15850            );
15851        }
15852    }
15853
15854    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15855        if !EditorSettings::get_global(cx).gutter.runnables {
15856            self.clear_tasks();
15857            return Task::ready(());
15858        }
15859        let project = self.project().map(Entity::downgrade);
15860        let task_sources = self.lsp_task_sources(cx);
15861        let multi_buffer = self.buffer.downgrade();
15862        cx.spawn_in(window, async move |editor, cx| {
15863            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15864            let Some(project) = project.and_then(|p| p.upgrade()) else {
15865                return;
15866            };
15867            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15868                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15869            }) else {
15870                return;
15871            };
15872
15873            let hide_runnables = project
15874                .update(cx, |project, _| project.is_via_collab())
15875                .unwrap_or(true);
15876            if hide_runnables {
15877                return;
15878            }
15879            let new_rows =
15880                cx.background_spawn({
15881                    let snapshot = display_snapshot.clone();
15882                    async move {
15883                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15884                    }
15885                })
15886                    .await;
15887            let Ok(lsp_tasks) =
15888                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15889            else {
15890                return;
15891            };
15892            let lsp_tasks = lsp_tasks.await;
15893
15894            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15895                lsp_tasks
15896                    .into_iter()
15897                    .flat_map(|(kind, tasks)| {
15898                        tasks.into_iter().filter_map(move |(location, task)| {
15899                            Some((kind.clone(), location?, task))
15900                        })
15901                    })
15902                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15903                        let buffer = location.target.buffer;
15904                        let buffer_snapshot = buffer.read(cx).snapshot();
15905                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15906                            |(excerpt_id, snapshot, _)| {
15907                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15908                                    display_snapshot
15909                                        .buffer_snapshot()
15910                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15911                                } else {
15912                                    None
15913                                }
15914                            },
15915                        );
15916                        if let Some(offset) = offset {
15917                            let task_buffer_range =
15918                                location.target.range.to_point(&buffer_snapshot);
15919                            let context_buffer_range =
15920                                task_buffer_range.to_offset(&buffer_snapshot);
15921                            let context_range = BufferOffset(context_buffer_range.start)
15922                                ..BufferOffset(context_buffer_range.end);
15923
15924                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15925                                .or_insert_with(|| RunnableTasks {
15926                                    templates: Vec::new(),
15927                                    offset,
15928                                    column: task_buffer_range.start.column,
15929                                    extra_variables: HashMap::default(),
15930                                    context_range,
15931                                })
15932                                .templates
15933                                .push((kind, task.original_task().clone()));
15934                        }
15935
15936                        acc
15937                    })
15938            }) else {
15939                return;
15940            };
15941
15942            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15943                buffer.language_settings(cx).tasks.prefer_lsp
15944            }) else {
15945                return;
15946            };
15947
15948            let rows = Self::runnable_rows(
15949                project,
15950                display_snapshot,
15951                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15952                new_rows,
15953                cx.clone(),
15954            )
15955            .await;
15956            editor
15957                .update(cx, |editor, _| {
15958                    editor.clear_tasks();
15959                    for (key, mut value) in rows {
15960                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15961                            value.templates.extend(lsp_tasks.templates);
15962                        }
15963
15964                        editor.insert_tasks(key, value);
15965                    }
15966                    for (key, value) in lsp_tasks_by_rows {
15967                        editor.insert_tasks(key, value);
15968                    }
15969                })
15970                .ok();
15971        })
15972    }
15973    fn fetch_runnable_ranges(
15974        snapshot: &DisplaySnapshot,
15975        range: Range<Anchor>,
15976    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15977        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15978    }
15979
15980    fn runnable_rows(
15981        project: Entity<Project>,
15982        snapshot: DisplaySnapshot,
15983        prefer_lsp: bool,
15984        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15985        cx: AsyncWindowContext,
15986    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15987        cx.spawn(async move |cx| {
15988            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15989            for (run_range, mut runnable) in runnable_ranges {
15990                let Some(tasks) = cx
15991                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15992                    .ok()
15993                else {
15994                    continue;
15995                };
15996                let mut tasks = tasks.await;
15997
15998                if prefer_lsp {
15999                    tasks.retain(|(task_kind, _)| {
16000                        !matches!(task_kind, TaskSourceKind::Language { .. })
16001                    });
16002                }
16003                if tasks.is_empty() {
16004                    continue;
16005                }
16006
16007                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16008                let Some(row) = snapshot
16009                    .buffer_snapshot()
16010                    .buffer_line_for_row(MultiBufferRow(point.row))
16011                    .map(|(_, range)| range.start.row)
16012                else {
16013                    continue;
16014                };
16015
16016                let context_range =
16017                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16018                runnable_rows.push((
16019                    (runnable.buffer_id, row),
16020                    RunnableTasks {
16021                        templates: tasks,
16022                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16023                        context_range,
16024                        column: point.column,
16025                        extra_variables: runnable.extra_captures,
16026                    },
16027                ));
16028            }
16029            runnable_rows
16030        })
16031    }
16032
16033    fn templates_with_tags(
16034        project: &Entity<Project>,
16035        runnable: &mut Runnable,
16036        cx: &mut App,
16037    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16038        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16039            let (worktree_id, file) = project
16040                .buffer_for_id(runnable.buffer, cx)
16041                .and_then(|buffer| buffer.read(cx).file())
16042                .map(|file| (file.worktree_id(cx), file.clone()))
16043                .unzip();
16044
16045            (
16046                project.task_store().read(cx).task_inventory().cloned(),
16047                worktree_id,
16048                file,
16049            )
16050        });
16051
16052        let tags = mem::take(&mut runnable.tags);
16053        let language = runnable.language.clone();
16054        cx.spawn(async move |cx| {
16055            let mut templates_with_tags = Vec::new();
16056            if let Some(inventory) = inventory {
16057                for RunnableTag(tag) in tags {
16058                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16059                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16060                    }) else {
16061                        return templates_with_tags;
16062                    };
16063                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16064                        move |(_, template)| {
16065                            template.tags.iter().any(|source_tag| source_tag == &tag)
16066                        },
16067                    ));
16068                }
16069            }
16070            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16071
16072            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16073                // Strongest source wins; if we have worktree tag binding, prefer that to
16074                // global and language bindings;
16075                // if we have a global binding, prefer that to language binding.
16076                let first_mismatch = templates_with_tags
16077                    .iter()
16078                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16079                if let Some(index) = first_mismatch {
16080                    templates_with_tags.truncate(index);
16081                }
16082            }
16083
16084            templates_with_tags
16085        })
16086    }
16087
16088    pub fn move_to_enclosing_bracket(
16089        &mut self,
16090        _: &MoveToEnclosingBracket,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) {
16094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16095        self.change_selections(Default::default(), window, cx, |s| {
16096            s.move_offsets_with(|snapshot, selection| {
16097                let Some(enclosing_bracket_ranges) =
16098                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16099                else {
16100                    return;
16101                };
16102
16103                let mut best_length = usize::MAX;
16104                let mut best_inside = false;
16105                let mut best_in_bracket_range = false;
16106                let mut best_destination = None;
16107                for (open, close) in enclosing_bracket_ranges {
16108                    let close = close.to_inclusive();
16109                    let length = *close.end() - open.start;
16110                    let inside = selection.start >= open.end && selection.end <= *close.start();
16111                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16112                        || close.contains(&selection.head());
16113
16114                    // If best is next to a bracket and current isn't, skip
16115                    if !in_bracket_range && best_in_bracket_range {
16116                        continue;
16117                    }
16118
16119                    // Prefer smaller lengths unless best is inside and current isn't
16120                    if length > best_length && (best_inside || !inside) {
16121                        continue;
16122                    }
16123
16124                    best_length = length;
16125                    best_inside = inside;
16126                    best_in_bracket_range = in_bracket_range;
16127                    best_destination = Some(
16128                        if close.contains(&selection.start) && close.contains(&selection.end) {
16129                            if inside { open.end } else { open.start }
16130                        } else if inside {
16131                            *close.start()
16132                        } else {
16133                            *close.end()
16134                        },
16135                    );
16136                }
16137
16138                if let Some(destination) = best_destination {
16139                    selection.collapse_to(destination, SelectionGoal::None);
16140                }
16141            })
16142        });
16143    }
16144
16145    pub fn undo_selection(
16146        &mut self,
16147        _: &UndoSelection,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16152        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16153            self.selection_history.mode = SelectionHistoryMode::Undoing;
16154            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16155                this.end_selection(window, cx);
16156                this.change_selections(
16157                    SelectionEffects::scroll(Autoscroll::newest()),
16158                    window,
16159                    cx,
16160                    |s| s.select_anchors(entry.selections.to_vec()),
16161                );
16162            });
16163            self.selection_history.mode = SelectionHistoryMode::Normal;
16164
16165            self.select_next_state = entry.select_next_state;
16166            self.select_prev_state = entry.select_prev_state;
16167            self.add_selections_state = entry.add_selections_state;
16168        }
16169    }
16170
16171    pub fn redo_selection(
16172        &mut self,
16173        _: &RedoSelection,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) {
16177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16178        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16179            self.selection_history.mode = SelectionHistoryMode::Redoing;
16180            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16181                this.end_selection(window, cx);
16182                this.change_selections(
16183                    SelectionEffects::scroll(Autoscroll::newest()),
16184                    window,
16185                    cx,
16186                    |s| s.select_anchors(entry.selections.to_vec()),
16187                );
16188            });
16189            self.selection_history.mode = SelectionHistoryMode::Normal;
16190
16191            self.select_next_state = entry.select_next_state;
16192            self.select_prev_state = entry.select_prev_state;
16193            self.add_selections_state = entry.add_selections_state;
16194        }
16195    }
16196
16197    pub fn expand_excerpts(
16198        &mut self,
16199        action: &ExpandExcerpts,
16200        _: &mut Window,
16201        cx: &mut Context<Self>,
16202    ) {
16203        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16204    }
16205
16206    pub fn expand_excerpts_down(
16207        &mut self,
16208        action: &ExpandExcerptsDown,
16209        _: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16213    }
16214
16215    pub fn expand_excerpts_up(
16216        &mut self,
16217        action: &ExpandExcerptsUp,
16218        _: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16222    }
16223
16224    pub fn expand_excerpts_for_direction(
16225        &mut self,
16226        lines: u32,
16227        direction: ExpandExcerptDirection,
16228
16229        cx: &mut Context<Self>,
16230    ) {
16231        let selections = self.selections.disjoint_anchors_arc();
16232
16233        let lines = if lines == 0 {
16234            EditorSettings::get_global(cx).expand_excerpt_lines
16235        } else {
16236            lines
16237        };
16238
16239        self.buffer.update(cx, |buffer, cx| {
16240            let snapshot = buffer.snapshot(cx);
16241            let mut excerpt_ids = selections
16242                .iter()
16243                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16244                .collect::<Vec<_>>();
16245            excerpt_ids.sort();
16246            excerpt_ids.dedup();
16247            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16248        })
16249    }
16250
16251    pub fn expand_excerpt(
16252        &mut self,
16253        excerpt: ExcerptId,
16254        direction: ExpandExcerptDirection,
16255        window: &mut Window,
16256        cx: &mut Context<Self>,
16257    ) {
16258        let current_scroll_position = self.scroll_position(cx);
16259        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16260        let mut scroll = None;
16261
16262        if direction == ExpandExcerptDirection::Down {
16263            let multi_buffer = self.buffer.read(cx);
16264            let snapshot = multi_buffer.snapshot(cx);
16265            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16266                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16267                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16268            {
16269                let buffer_snapshot = buffer.read(cx).snapshot();
16270                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16271                let last_row = buffer_snapshot.max_point().row;
16272                let lines_below = last_row.saturating_sub(excerpt_end_row);
16273                if lines_below >= lines_to_expand {
16274                    scroll = Some(
16275                        current_scroll_position
16276                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16277                    );
16278                }
16279            }
16280        }
16281        if direction == ExpandExcerptDirection::Up
16282            && self
16283                .buffer
16284                .read(cx)
16285                .snapshot(cx)
16286                .excerpt_before(excerpt)
16287                .is_none()
16288        {
16289            scroll = Some(current_scroll_position);
16290        }
16291
16292        self.buffer.update(cx, |buffer, cx| {
16293            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16294        });
16295
16296        if let Some(new_scroll_position) = scroll {
16297            self.set_scroll_position(new_scroll_position, window, cx);
16298        }
16299    }
16300
16301    pub fn go_to_singleton_buffer_point(
16302        &mut self,
16303        point: Point,
16304        window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) {
16307        self.go_to_singleton_buffer_range(point..point, window, cx);
16308    }
16309
16310    pub fn go_to_singleton_buffer_range(
16311        &mut self,
16312        range: Range<Point>,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        let multibuffer = self.buffer().read(cx);
16317        let Some(buffer) = multibuffer.as_singleton() else {
16318            return;
16319        };
16320        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16321            return;
16322        };
16323        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16324            return;
16325        };
16326        self.change_selections(
16327            SelectionEffects::default().nav_history(true),
16328            window,
16329            cx,
16330            |s| s.select_anchor_ranges([start..end]),
16331        );
16332    }
16333
16334    pub fn go_to_diagnostic(
16335        &mut self,
16336        action: &GoToDiagnostic,
16337        window: &mut Window,
16338        cx: &mut Context<Self>,
16339    ) {
16340        if !self.diagnostics_enabled() {
16341            return;
16342        }
16343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16344        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16345    }
16346
16347    pub fn go_to_prev_diagnostic(
16348        &mut self,
16349        action: &GoToPreviousDiagnostic,
16350        window: &mut Window,
16351        cx: &mut Context<Self>,
16352    ) {
16353        if !self.diagnostics_enabled() {
16354            return;
16355        }
16356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16357        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16358    }
16359
16360    pub fn go_to_diagnostic_impl(
16361        &mut self,
16362        direction: Direction,
16363        severity: GoToDiagnosticSeverityFilter,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) {
16367        let buffer = self.buffer.read(cx).snapshot(cx);
16368        let selection = self
16369            .selections
16370            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16371
16372        let mut active_group_id = None;
16373        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16374            && active_group.active_range.start.to_offset(&buffer) == selection.start
16375        {
16376            active_group_id = Some(active_group.group_id);
16377        }
16378
16379        fn filtered<'a>(
16380            severity: GoToDiagnosticSeverityFilter,
16381            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16382        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16383            diagnostics
16384                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16385                .filter(|entry| entry.range.start != entry.range.end)
16386                .filter(|entry| !entry.diagnostic.is_unnecessary)
16387        }
16388
16389        let before = filtered(
16390            severity,
16391            buffer
16392                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16393                .filter(|entry| entry.range.start <= selection.start),
16394        );
16395        let after = filtered(
16396            severity,
16397            buffer
16398                .diagnostics_in_range(selection.start..buffer.len())
16399                .filter(|entry| entry.range.start >= selection.start),
16400        );
16401
16402        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16403        if direction == Direction::Prev {
16404            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16405            {
16406                for diagnostic in prev_diagnostics.into_iter().rev() {
16407                    if diagnostic.range.start != selection.start
16408                        || active_group_id
16409                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16410                    {
16411                        found = Some(diagnostic);
16412                        break 'outer;
16413                    }
16414                }
16415            }
16416        } else {
16417            for diagnostic in after.chain(before) {
16418                if diagnostic.range.start != selection.start
16419                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16420                {
16421                    found = Some(diagnostic);
16422                    break;
16423                }
16424            }
16425        }
16426        let Some(next_diagnostic) = found else {
16427            return;
16428        };
16429
16430        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16431        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16432            return;
16433        };
16434        let snapshot = self.snapshot(window, cx);
16435        if snapshot.intersects_fold(next_diagnostic.range.start) {
16436            self.unfold_ranges(
16437                std::slice::from_ref(&next_diagnostic.range),
16438                true,
16439                false,
16440                cx,
16441            );
16442        }
16443        self.change_selections(Default::default(), window, cx, |s| {
16444            s.select_ranges(vec![
16445                next_diagnostic.range.start..next_diagnostic.range.start,
16446            ])
16447        });
16448        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16449        self.refresh_edit_prediction(false, true, window, cx);
16450    }
16451
16452    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16454        let snapshot = self.snapshot(window, cx);
16455        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16456        self.go_to_hunk_before_or_after_position(
16457            &snapshot,
16458            selection.head(),
16459            Direction::Next,
16460            window,
16461            cx,
16462        );
16463    }
16464
16465    pub fn go_to_hunk_before_or_after_position(
16466        &mut self,
16467        snapshot: &EditorSnapshot,
16468        position: Point,
16469        direction: Direction,
16470        window: &mut Window,
16471        cx: &mut Context<Editor>,
16472    ) {
16473        let row = if direction == Direction::Next {
16474            self.hunk_after_position(snapshot, position)
16475                .map(|hunk| hunk.row_range.start)
16476        } else {
16477            self.hunk_before_position(snapshot, position)
16478        };
16479
16480        if let Some(row) = row {
16481            let destination = Point::new(row.0, 0);
16482            let autoscroll = Autoscroll::center();
16483
16484            self.unfold_ranges(&[destination..destination], false, false, cx);
16485            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16486                s.select_ranges([destination..destination]);
16487            });
16488        }
16489    }
16490
16491    fn hunk_after_position(
16492        &mut self,
16493        snapshot: &EditorSnapshot,
16494        position: Point,
16495    ) -> Option<MultiBufferDiffHunk> {
16496        snapshot
16497            .buffer_snapshot()
16498            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16499            .find(|hunk| hunk.row_range.start.0 > position.row)
16500            .or_else(|| {
16501                snapshot
16502                    .buffer_snapshot()
16503                    .diff_hunks_in_range(Point::zero()..position)
16504                    .find(|hunk| hunk.row_range.end.0 < position.row)
16505            })
16506    }
16507
16508    fn go_to_prev_hunk(
16509        &mut self,
16510        _: &GoToPreviousHunk,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) {
16514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16515        let snapshot = self.snapshot(window, cx);
16516        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16517        self.go_to_hunk_before_or_after_position(
16518            &snapshot,
16519            selection.head(),
16520            Direction::Prev,
16521            window,
16522            cx,
16523        );
16524    }
16525
16526    fn hunk_before_position(
16527        &mut self,
16528        snapshot: &EditorSnapshot,
16529        position: Point,
16530    ) -> Option<MultiBufferRow> {
16531        snapshot
16532            .buffer_snapshot()
16533            .diff_hunk_before(position)
16534            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16535    }
16536
16537    fn go_to_next_change(
16538        &mut self,
16539        _: &GoToNextChange,
16540        window: &mut Window,
16541        cx: &mut Context<Self>,
16542    ) {
16543        if let Some(selections) = self
16544            .change_list
16545            .next_change(1, Direction::Next)
16546            .map(|s| s.to_vec())
16547        {
16548            self.change_selections(Default::default(), window, cx, |s| {
16549                let map = s.display_snapshot();
16550                s.select_display_ranges(selections.iter().map(|a| {
16551                    let point = a.to_display_point(&map);
16552                    point..point
16553                }))
16554            })
16555        }
16556    }
16557
16558    fn go_to_previous_change(
16559        &mut self,
16560        _: &GoToPreviousChange,
16561        window: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) {
16564        if let Some(selections) = self
16565            .change_list
16566            .next_change(1, Direction::Prev)
16567            .map(|s| s.to_vec())
16568        {
16569            self.change_selections(Default::default(), window, cx, |s| {
16570                let map = s.display_snapshot();
16571                s.select_display_ranges(selections.iter().map(|a| {
16572                    let point = a.to_display_point(&map);
16573                    point..point
16574                }))
16575            })
16576        }
16577    }
16578
16579    pub fn go_to_next_document_highlight(
16580        &mut self,
16581        _: &GoToNextDocumentHighlight,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16586    }
16587
16588    pub fn go_to_prev_document_highlight(
16589        &mut self,
16590        _: &GoToPreviousDocumentHighlight,
16591        window: &mut Window,
16592        cx: &mut Context<Self>,
16593    ) {
16594        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16595    }
16596
16597    pub fn go_to_document_highlight_before_or_after_position(
16598        &mut self,
16599        direction: Direction,
16600        window: &mut Window,
16601        cx: &mut Context<Editor>,
16602    ) {
16603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16604        let snapshot = self.snapshot(window, cx);
16605        let buffer = &snapshot.buffer_snapshot();
16606        let position = self
16607            .selections
16608            .newest::<Point>(&snapshot.display_snapshot)
16609            .head();
16610        let anchor_position = buffer.anchor_after(position);
16611
16612        // Get all document highlights (both read and write)
16613        let mut all_highlights = Vec::new();
16614
16615        if let Some((_, read_highlights)) = self
16616            .background_highlights
16617            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16618        {
16619            all_highlights.extend(read_highlights.iter());
16620        }
16621
16622        if let Some((_, write_highlights)) = self
16623            .background_highlights
16624            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16625        {
16626            all_highlights.extend(write_highlights.iter());
16627        }
16628
16629        if all_highlights.is_empty() {
16630            return;
16631        }
16632
16633        // Sort highlights by position
16634        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16635
16636        let target_highlight = match direction {
16637            Direction::Next => {
16638                // Find the first highlight after the current position
16639                all_highlights
16640                    .iter()
16641                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16642            }
16643            Direction::Prev => {
16644                // Find the last highlight before the current position
16645                all_highlights
16646                    .iter()
16647                    .rev()
16648                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16649            }
16650        };
16651
16652        if let Some(highlight) = target_highlight {
16653            let destination = highlight.start.to_point(buffer);
16654            let autoscroll = Autoscroll::center();
16655
16656            self.unfold_ranges(&[destination..destination], false, false, cx);
16657            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16658                s.select_ranges([destination..destination]);
16659            });
16660        }
16661    }
16662
16663    fn go_to_line<T: 'static>(
16664        &mut self,
16665        position: Anchor,
16666        highlight_color: Option<Hsla>,
16667        window: &mut Window,
16668        cx: &mut Context<Self>,
16669    ) {
16670        let snapshot = self.snapshot(window, cx).display_snapshot;
16671        let position = position.to_point(&snapshot.buffer_snapshot());
16672        let start = snapshot
16673            .buffer_snapshot()
16674            .clip_point(Point::new(position.row, 0), Bias::Left);
16675        let end = start + Point::new(1, 0);
16676        let start = snapshot.buffer_snapshot().anchor_before(start);
16677        let end = snapshot.buffer_snapshot().anchor_before(end);
16678
16679        self.highlight_rows::<T>(
16680            start..end,
16681            highlight_color
16682                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16683            Default::default(),
16684            cx,
16685        );
16686
16687        if self.buffer.read(cx).is_singleton() {
16688            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16689        }
16690    }
16691
16692    pub fn go_to_definition(
16693        &mut self,
16694        _: &GoToDefinition,
16695        window: &mut Window,
16696        cx: &mut Context<Self>,
16697    ) -> Task<Result<Navigated>> {
16698        let definition =
16699            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16700        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16701        cx.spawn_in(window, async move |editor, cx| {
16702            if definition.await? == Navigated::Yes {
16703                return Ok(Navigated::Yes);
16704            }
16705            match fallback_strategy {
16706                GoToDefinitionFallback::None => Ok(Navigated::No),
16707                GoToDefinitionFallback::FindAllReferences => {
16708                    match editor.update_in(cx, |editor, window, cx| {
16709                        editor.find_all_references(&FindAllReferences, window, cx)
16710                    })? {
16711                        Some(references) => references.await,
16712                        None => Ok(Navigated::No),
16713                    }
16714                }
16715            }
16716        })
16717    }
16718
16719    pub fn go_to_declaration(
16720        &mut self,
16721        _: &GoToDeclaration,
16722        window: &mut Window,
16723        cx: &mut Context<Self>,
16724    ) -> Task<Result<Navigated>> {
16725        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16726    }
16727
16728    pub fn go_to_declaration_split(
16729        &mut self,
16730        _: &GoToDeclaration,
16731        window: &mut Window,
16732        cx: &mut Context<Self>,
16733    ) -> Task<Result<Navigated>> {
16734        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16735    }
16736
16737    pub fn go_to_implementation(
16738        &mut self,
16739        _: &GoToImplementation,
16740        window: &mut Window,
16741        cx: &mut Context<Self>,
16742    ) -> Task<Result<Navigated>> {
16743        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16744    }
16745
16746    pub fn go_to_implementation_split(
16747        &mut self,
16748        _: &GoToImplementationSplit,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) -> Task<Result<Navigated>> {
16752        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16753    }
16754
16755    pub fn go_to_type_definition(
16756        &mut self,
16757        _: &GoToTypeDefinition,
16758        window: &mut Window,
16759        cx: &mut Context<Self>,
16760    ) -> Task<Result<Navigated>> {
16761        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16762    }
16763
16764    pub fn go_to_definition_split(
16765        &mut self,
16766        _: &GoToDefinitionSplit,
16767        window: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) -> Task<Result<Navigated>> {
16770        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16771    }
16772
16773    pub fn go_to_type_definition_split(
16774        &mut self,
16775        _: &GoToTypeDefinitionSplit,
16776        window: &mut Window,
16777        cx: &mut Context<Self>,
16778    ) -> Task<Result<Navigated>> {
16779        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16780    }
16781
16782    fn go_to_definition_of_kind(
16783        &mut self,
16784        kind: GotoDefinitionKind,
16785        split: bool,
16786        window: &mut Window,
16787        cx: &mut Context<Self>,
16788    ) -> Task<Result<Navigated>> {
16789        let Some(provider) = self.semantics_provider.clone() else {
16790            return Task::ready(Ok(Navigated::No));
16791        };
16792        let head = self
16793            .selections
16794            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16795            .head();
16796        let buffer = self.buffer.read(cx);
16797        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16798            return Task::ready(Ok(Navigated::No));
16799        };
16800        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16801            return Task::ready(Ok(Navigated::No));
16802        };
16803
16804        cx.spawn_in(window, async move |editor, cx| {
16805            let Some(definitions) = definitions.await? else {
16806                return Ok(Navigated::No);
16807            };
16808            let navigated = editor
16809                .update_in(cx, |editor, window, cx| {
16810                    editor.navigate_to_hover_links(
16811                        Some(kind),
16812                        definitions
16813                            .into_iter()
16814                            .filter(|location| {
16815                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16816                            })
16817                            .map(HoverLink::Text)
16818                            .collect::<Vec<_>>(),
16819                        split,
16820                        window,
16821                        cx,
16822                    )
16823                })?
16824                .await?;
16825            anyhow::Ok(navigated)
16826        })
16827    }
16828
16829    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16830        let selection = self.selections.newest_anchor();
16831        let head = selection.head();
16832        let tail = selection.tail();
16833
16834        let Some((buffer, start_position)) =
16835            self.buffer.read(cx).text_anchor_for_position(head, cx)
16836        else {
16837            return;
16838        };
16839
16840        let end_position = if head != tail {
16841            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16842                return;
16843            };
16844            Some(pos)
16845        } else {
16846            None
16847        };
16848
16849        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16850            let url = if let Some(end_pos) = end_position {
16851                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16852            } else {
16853                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16854            };
16855
16856            if let Some(url) = url {
16857                cx.update(|window, cx| {
16858                    if parse_zed_link(&url, cx).is_some() {
16859                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16860                    } else {
16861                        cx.open_url(&url);
16862                    }
16863                })?;
16864            }
16865
16866            anyhow::Ok(())
16867        });
16868
16869        url_finder.detach();
16870    }
16871
16872    pub fn open_selected_filename(
16873        &mut self,
16874        _: &OpenSelectedFilename,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        let Some(workspace) = self.workspace() else {
16879            return;
16880        };
16881
16882        let position = self.selections.newest_anchor().head();
16883
16884        let Some((buffer, buffer_position)) =
16885            self.buffer.read(cx).text_anchor_for_position(position, cx)
16886        else {
16887            return;
16888        };
16889
16890        let project = self.project.clone();
16891
16892        cx.spawn_in(window, async move |_, cx| {
16893            let result = find_file(&buffer, project, buffer_position, cx).await;
16894
16895            if let Some((_, path)) = result {
16896                workspace
16897                    .update_in(cx, |workspace, window, cx| {
16898                        workspace.open_resolved_path(path, window, cx)
16899                    })?
16900                    .await?;
16901            }
16902            anyhow::Ok(())
16903        })
16904        .detach();
16905    }
16906
16907    pub(crate) fn navigate_to_hover_links(
16908        &mut self,
16909        kind: Option<GotoDefinitionKind>,
16910        definitions: Vec<HoverLink>,
16911        split: bool,
16912        window: &mut Window,
16913        cx: &mut Context<Editor>,
16914    ) -> Task<Result<Navigated>> {
16915        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16916        let mut first_url_or_file = None;
16917        let definitions: Vec<_> = definitions
16918            .into_iter()
16919            .filter_map(|def| match def {
16920                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16921                HoverLink::InlayHint(lsp_location, server_id) => {
16922                    let computation =
16923                        self.compute_target_location(lsp_location, server_id, window, cx);
16924                    Some(cx.background_spawn(computation))
16925                }
16926                HoverLink::Url(url) => {
16927                    first_url_or_file = Some(Either::Left(url));
16928                    None
16929                }
16930                HoverLink::File(path) => {
16931                    first_url_or_file = Some(Either::Right(path));
16932                    None
16933                }
16934            })
16935            .collect();
16936
16937        let workspace = self.workspace();
16938
16939        cx.spawn_in(window, async move |editor, cx| {
16940            let locations: Vec<Location> = future::join_all(definitions)
16941                .await
16942                .into_iter()
16943                .filter_map(|location| location.transpose())
16944                .collect::<Result<_>>()
16945                .context("location tasks")?;
16946            let mut locations = cx.update(|_, cx| {
16947                locations
16948                    .into_iter()
16949                    .map(|location| {
16950                        let buffer = location.buffer.read(cx);
16951                        (location.buffer, location.range.to_point(buffer))
16952                    })
16953                    .into_group_map()
16954            })?;
16955            let mut num_locations = 0;
16956            for ranges in locations.values_mut() {
16957                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16958                ranges.dedup();
16959                num_locations += ranges.len();
16960            }
16961
16962            if num_locations > 1 {
16963                let Some(workspace) = workspace else {
16964                    return Ok(Navigated::No);
16965                };
16966
16967                let tab_kind = match kind {
16968                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16969                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16970                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16971                    Some(GotoDefinitionKind::Type) => "Types",
16972                };
16973                let title = editor
16974                    .update_in(cx, |_, _, cx| {
16975                        let target = locations
16976                            .iter()
16977                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16978                            .map(|(buffer, location)| {
16979                                buffer
16980                                    .read(cx)
16981                                    .text_for_range(location.clone())
16982                                    .collect::<String>()
16983                            })
16984                            .filter(|text| !text.contains('\n'))
16985                            .unique()
16986                            .take(3)
16987                            .join(", ");
16988                        if target.is_empty() {
16989                            tab_kind.to_owned()
16990                        } else {
16991                            format!("{tab_kind} for {target}")
16992                        }
16993                    })
16994                    .context("buffer title")?;
16995
16996                let opened = workspace
16997                    .update_in(cx, |workspace, window, cx| {
16998                        Self::open_locations_in_multibuffer(
16999                            workspace,
17000                            locations,
17001                            title,
17002                            split,
17003                            MultibufferSelectionMode::First,
17004                            window,
17005                            cx,
17006                        )
17007                    })
17008                    .is_ok();
17009
17010                anyhow::Ok(Navigated::from_bool(opened))
17011            } else if num_locations == 0 {
17012                // If there is one url or file, open it directly
17013                match first_url_or_file {
17014                    Some(Either::Left(url)) => {
17015                        cx.update(|_, cx| cx.open_url(&url))?;
17016                        Ok(Navigated::Yes)
17017                    }
17018                    Some(Either::Right(path)) => {
17019                        let Some(workspace) = workspace else {
17020                            return Ok(Navigated::No);
17021                        };
17022
17023                        workspace
17024                            .update_in(cx, |workspace, window, cx| {
17025                                workspace.open_resolved_path(path, window, cx)
17026                            })?
17027                            .await?;
17028                        Ok(Navigated::Yes)
17029                    }
17030                    None => Ok(Navigated::No),
17031                }
17032            } else {
17033                let Some(workspace) = workspace else {
17034                    return Ok(Navigated::No);
17035                };
17036
17037                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17038                let target_range = target_ranges.first().unwrap().clone();
17039
17040                editor.update_in(cx, |editor, window, cx| {
17041                    let range = target_range.to_point(target_buffer.read(cx));
17042                    let range = editor.range_for_match(&range);
17043                    let range = collapse_multiline_range(range);
17044
17045                    if !split
17046                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17047                    {
17048                        editor.go_to_singleton_buffer_range(range, window, cx);
17049                    } else {
17050                        let pane = workspace.read(cx).active_pane().clone();
17051                        window.defer(cx, move |window, cx| {
17052                            let target_editor: Entity<Self> =
17053                                workspace.update(cx, |workspace, cx| {
17054                                    let pane = if split {
17055                                        workspace.adjacent_pane(window, cx)
17056                                    } else {
17057                                        workspace.active_pane().clone()
17058                                    };
17059
17060                                    workspace.open_project_item(
17061                                        pane,
17062                                        target_buffer.clone(),
17063                                        true,
17064                                        true,
17065                                        window,
17066                                        cx,
17067                                    )
17068                                });
17069                            target_editor.update(cx, |target_editor, cx| {
17070                                // When selecting a definition in a different buffer, disable the nav history
17071                                // to avoid creating a history entry at the previous cursor location.
17072                                pane.update(cx, |pane, _| pane.disable_history());
17073                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17074                                pane.update(cx, |pane, _| pane.enable_history());
17075                            });
17076                        });
17077                    }
17078                    Navigated::Yes
17079                })
17080            }
17081        })
17082    }
17083
17084    fn compute_target_location(
17085        &self,
17086        lsp_location: lsp::Location,
17087        server_id: LanguageServerId,
17088        window: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) -> Task<anyhow::Result<Option<Location>>> {
17091        let Some(project) = self.project.clone() else {
17092            return Task::ready(Ok(None));
17093        };
17094
17095        cx.spawn_in(window, async move |editor, cx| {
17096            let location_task = editor.update(cx, |_, cx| {
17097                project.update(cx, |project, cx| {
17098                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17099                })
17100            })?;
17101            let location = Some({
17102                let target_buffer_handle = location_task.await.context("open local buffer")?;
17103                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17104                    let target_start = target_buffer
17105                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17106                    let target_end = target_buffer
17107                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17108                    target_buffer.anchor_after(target_start)
17109                        ..target_buffer.anchor_before(target_end)
17110                })?;
17111                Location {
17112                    buffer: target_buffer_handle,
17113                    range,
17114                }
17115            });
17116            Ok(location)
17117        })
17118    }
17119
17120    fn go_to_next_reference(
17121        &mut self,
17122        _: &GoToNextReference,
17123        window: &mut Window,
17124        cx: &mut Context<Self>,
17125    ) {
17126        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17127        if let Some(task) = task {
17128            task.detach();
17129        };
17130    }
17131
17132    fn go_to_prev_reference(
17133        &mut self,
17134        _: &GoToPreviousReference,
17135        window: &mut Window,
17136        cx: &mut Context<Self>,
17137    ) {
17138        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17139        if let Some(task) = task {
17140            task.detach();
17141        };
17142    }
17143
17144    pub fn go_to_reference_before_or_after_position(
17145        &mut self,
17146        direction: Direction,
17147        count: usize,
17148        window: &mut Window,
17149        cx: &mut Context<Self>,
17150    ) -> Option<Task<Result<()>>> {
17151        let selection = self.selections.newest_anchor();
17152        let head = selection.head();
17153
17154        let multi_buffer = self.buffer.read(cx);
17155
17156        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17157        let workspace = self.workspace()?;
17158        let project = workspace.read(cx).project().clone();
17159        let references =
17160            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17161        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17162            let Some(locations) = references.await? else {
17163                return Ok(());
17164            };
17165
17166            if locations.is_empty() {
17167                // totally normal - the cursor may be on something which is not
17168                // a symbol (e.g. a keyword)
17169                log::info!("no references found under cursor");
17170                return Ok(());
17171            }
17172
17173            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17174
17175            let (locations, current_location_index) =
17176                multi_buffer.update(cx, |multi_buffer, cx| {
17177                    let mut locations = locations
17178                        .into_iter()
17179                        .filter_map(|loc| {
17180                            let start = multi_buffer.buffer_anchor_to_anchor(
17181                                &loc.buffer,
17182                                loc.range.start,
17183                                cx,
17184                            )?;
17185                            let end = multi_buffer.buffer_anchor_to_anchor(
17186                                &loc.buffer,
17187                                loc.range.end,
17188                                cx,
17189                            )?;
17190                            Some(start..end)
17191                        })
17192                        .collect::<Vec<_>>();
17193
17194                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17195                    // There is an O(n) implementation, but given this list will be
17196                    // small (usually <100 items), the extra O(log(n)) factor isn't
17197                    // worth the (surprisingly large amount of) extra complexity.
17198                    locations
17199                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17200
17201                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17202
17203                    let current_location_index = locations.iter().position(|loc| {
17204                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17205                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17206                    });
17207
17208                    (locations, current_location_index)
17209                })?;
17210
17211            let Some(current_location_index) = current_location_index else {
17212                // This indicates something has gone wrong, because we already
17213                // handle the "no references" case above
17214                log::error!(
17215                    "failed to find current reference under cursor. Total references: {}",
17216                    locations.len()
17217                );
17218                return Ok(());
17219            };
17220
17221            let destination_location_index = match direction {
17222                Direction::Next => (current_location_index + count) % locations.len(),
17223                Direction::Prev => {
17224                    (current_location_index + locations.len() - count % locations.len())
17225                        % locations.len()
17226                }
17227            };
17228
17229            // TODO(cameron): is this needed?
17230            // the thinking is to avoid "jumping to the current location" (avoid
17231            // polluting "jumplist" in vim terms)
17232            if current_location_index == destination_location_index {
17233                return Ok(());
17234            }
17235
17236            let Range { start, end } = locations[destination_location_index];
17237
17238            editor.update_in(cx, |editor, window, cx| {
17239                let effects = SelectionEffects::default();
17240
17241                editor.unfold_ranges(&[start..end], false, false, cx);
17242                editor.change_selections(effects, window, cx, |s| {
17243                    s.select_ranges([start..start]);
17244                });
17245            })?;
17246
17247            Ok(())
17248        }))
17249    }
17250
17251    pub fn find_all_references(
17252        &mut self,
17253        _: &FindAllReferences,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) -> Option<Task<Result<Navigated>>> {
17257        let selection = self
17258            .selections
17259            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17260        let multi_buffer = self.buffer.read(cx);
17261        let head = selection.head();
17262
17263        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17264        let head_anchor = multi_buffer_snapshot.anchor_at(
17265            head,
17266            if head < selection.tail() {
17267                Bias::Right
17268            } else {
17269                Bias::Left
17270            },
17271        );
17272
17273        match self
17274            .find_all_references_task_sources
17275            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17276        {
17277            Ok(_) => {
17278                log::info!(
17279                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17280                );
17281                return None;
17282            }
17283            Err(i) => {
17284                self.find_all_references_task_sources.insert(i, head_anchor);
17285            }
17286        }
17287
17288        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17289        let workspace = self.workspace()?;
17290        let project = workspace.read(cx).project().clone();
17291        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17292        Some(cx.spawn_in(window, async move |editor, cx| {
17293            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17294                if let Ok(i) = editor
17295                    .find_all_references_task_sources
17296                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17297                {
17298                    editor.find_all_references_task_sources.remove(i);
17299                }
17300            });
17301
17302            let Some(locations) = references.await? else {
17303                return anyhow::Ok(Navigated::No);
17304            };
17305            let mut locations = cx.update(|_, cx| {
17306                locations
17307                    .into_iter()
17308                    .map(|location| {
17309                        let buffer = location.buffer.read(cx);
17310                        (location.buffer, location.range.to_point(buffer))
17311                    })
17312                    .into_group_map()
17313            })?;
17314            if locations.is_empty() {
17315                return anyhow::Ok(Navigated::No);
17316            }
17317            for ranges in locations.values_mut() {
17318                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17319                ranges.dedup();
17320            }
17321
17322            workspace.update_in(cx, |workspace, window, cx| {
17323                let target = locations
17324                    .iter()
17325                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17326                    .map(|(buffer, location)| {
17327                        buffer
17328                            .read(cx)
17329                            .text_for_range(location.clone())
17330                            .collect::<String>()
17331                    })
17332                    .filter(|text| !text.contains('\n'))
17333                    .unique()
17334                    .take(3)
17335                    .join(", ");
17336                let title = if target.is_empty() {
17337                    "References".to_owned()
17338                } else {
17339                    format!("References to {target}")
17340                };
17341                Self::open_locations_in_multibuffer(
17342                    workspace,
17343                    locations,
17344                    title,
17345                    false,
17346                    MultibufferSelectionMode::First,
17347                    window,
17348                    cx,
17349                );
17350                Navigated::Yes
17351            })
17352        }))
17353    }
17354
17355    /// Opens a multibuffer with the given project locations in it
17356    pub fn open_locations_in_multibuffer(
17357        workspace: &mut Workspace,
17358        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17359        title: String,
17360        split: bool,
17361        multibuffer_selection_mode: MultibufferSelectionMode,
17362        window: &mut Window,
17363        cx: &mut Context<Workspace>,
17364    ) {
17365        if locations.is_empty() {
17366            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17367            return;
17368        }
17369
17370        let capability = workspace.project().read(cx).capability();
17371        let mut ranges = <Vec<Range<Anchor>>>::new();
17372
17373        // a key to find existing multibuffer editors with the same set of locations
17374        // to prevent us from opening more and more multibuffer tabs for searches and the like
17375        let mut key = (title.clone(), vec![]);
17376        let excerpt_buffer = cx.new(|cx| {
17377            let key = &mut key.1;
17378            let mut multibuffer = MultiBuffer::new(capability);
17379            for (buffer, mut ranges_for_buffer) in locations {
17380                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17381                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17382                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17383                    PathKey::for_buffer(&buffer, cx),
17384                    buffer.clone(),
17385                    ranges_for_buffer,
17386                    multibuffer_context_lines(cx),
17387                    cx,
17388                );
17389                ranges.extend(new_ranges)
17390            }
17391
17392            multibuffer.with_title(title)
17393        });
17394        let existing = workspace.active_pane().update(cx, |pane, cx| {
17395            pane.items()
17396                .filter_map(|item| item.downcast::<Editor>())
17397                .find(|editor| {
17398                    editor
17399                        .read(cx)
17400                        .lookup_key
17401                        .as_ref()
17402                        .and_then(|it| {
17403                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17404                        })
17405                        .is_some_and(|it| *it == key)
17406                })
17407        });
17408        let editor = existing.unwrap_or_else(|| {
17409            cx.new(|cx| {
17410                let mut editor = Editor::for_multibuffer(
17411                    excerpt_buffer,
17412                    Some(workspace.project().clone()),
17413                    window,
17414                    cx,
17415                );
17416                editor.lookup_key = Some(Box::new(key));
17417                editor
17418            })
17419        });
17420        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17421            MultibufferSelectionMode::First => {
17422                if let Some(first_range) = ranges.first() {
17423                    editor.change_selections(
17424                        SelectionEffects::no_scroll(),
17425                        window,
17426                        cx,
17427                        |selections| {
17428                            selections.clear_disjoint();
17429                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17430                        },
17431                    );
17432                }
17433                editor.highlight_background::<Self>(
17434                    &ranges,
17435                    |theme| theme.colors().editor_highlighted_line_background,
17436                    cx,
17437                );
17438            }
17439            MultibufferSelectionMode::All => {
17440                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17441                    selections.clear_disjoint();
17442                    selections.select_anchor_ranges(ranges);
17443                });
17444            }
17445        });
17446
17447        let item = Box::new(editor);
17448        let item_id = item.item_id();
17449
17450        if split {
17451            let pane = workspace.adjacent_pane(window, cx);
17452            workspace.add_item(pane, item, None, true, true, window, cx);
17453        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17454            let (preview_item_id, preview_item_idx) =
17455                workspace.active_pane().read_with(cx, |pane, _| {
17456                    (pane.preview_item_id(), pane.preview_item_idx())
17457                });
17458
17459            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17460
17461            if let Some(preview_item_id) = preview_item_id {
17462                workspace.active_pane().update(cx, |pane, cx| {
17463                    pane.remove_item(preview_item_id, false, false, window, cx);
17464                });
17465            }
17466        } else {
17467            workspace.add_item_to_active_pane(item, None, true, window, cx);
17468        }
17469        workspace.active_pane().update(cx, |pane, cx| {
17470            pane.set_preview_item_id(Some(item_id), cx);
17471        });
17472    }
17473
17474    pub fn rename(
17475        &mut self,
17476        _: &Rename,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) -> Option<Task<Result<()>>> {
17480        use language::ToOffset as _;
17481
17482        let provider = self.semantics_provider.clone()?;
17483        let selection = self.selections.newest_anchor().clone();
17484        let (cursor_buffer, cursor_buffer_position) = self
17485            .buffer
17486            .read(cx)
17487            .text_anchor_for_position(selection.head(), cx)?;
17488        let (tail_buffer, cursor_buffer_position_end) = self
17489            .buffer
17490            .read(cx)
17491            .text_anchor_for_position(selection.tail(), cx)?;
17492        if tail_buffer != cursor_buffer {
17493            return None;
17494        }
17495
17496        let snapshot = cursor_buffer.read(cx).snapshot();
17497        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17498        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17499        let prepare_rename = provider
17500            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17501            .unwrap_or_else(|| Task::ready(Ok(None)));
17502        drop(snapshot);
17503
17504        Some(cx.spawn_in(window, async move |this, cx| {
17505            let rename_range = if let Some(range) = prepare_rename.await? {
17506                Some(range)
17507            } else {
17508                this.update(cx, |this, cx| {
17509                    let buffer = this.buffer.read(cx).snapshot(cx);
17510                    let mut buffer_highlights = this
17511                        .document_highlights_for_position(selection.head(), &buffer)
17512                        .filter(|highlight| {
17513                            highlight.start.excerpt_id == selection.head().excerpt_id
17514                                && highlight.end.excerpt_id == selection.head().excerpt_id
17515                        });
17516                    buffer_highlights
17517                        .next()
17518                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17519                })?
17520            };
17521            if let Some(rename_range) = rename_range {
17522                this.update_in(cx, |this, window, cx| {
17523                    let snapshot = cursor_buffer.read(cx).snapshot();
17524                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17525                    let cursor_offset_in_rename_range =
17526                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17527                    let cursor_offset_in_rename_range_end =
17528                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17529
17530                    this.take_rename(false, window, cx);
17531                    let buffer = this.buffer.read(cx).read(cx);
17532                    let cursor_offset = selection.head().to_offset(&buffer);
17533                    let rename_start =
17534                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17535                    let rename_end = rename_start + rename_buffer_range.len();
17536                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17537                    let mut old_highlight_id = None;
17538                    let old_name: Arc<str> = buffer
17539                        .chunks(rename_start..rename_end, true)
17540                        .map(|chunk| {
17541                            if old_highlight_id.is_none() {
17542                                old_highlight_id = chunk.syntax_highlight_id;
17543                            }
17544                            chunk.text
17545                        })
17546                        .collect::<String>()
17547                        .into();
17548
17549                    drop(buffer);
17550
17551                    // Position the selection in the rename editor so that it matches the current selection.
17552                    this.show_local_selections = false;
17553                    let rename_editor = cx.new(|cx| {
17554                        let mut editor = Editor::single_line(window, cx);
17555                        editor.buffer.update(cx, |buffer, cx| {
17556                            buffer.edit(
17557                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17558                                None,
17559                                cx,
17560                            )
17561                        });
17562                        let cursor_offset_in_rename_range =
17563                            MultiBufferOffset(cursor_offset_in_rename_range);
17564                        let cursor_offset_in_rename_range_end =
17565                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17566                        let rename_selection_range = match cursor_offset_in_rename_range
17567                            .cmp(&cursor_offset_in_rename_range_end)
17568                        {
17569                            Ordering::Equal => {
17570                                editor.select_all(&SelectAll, window, cx);
17571                                return editor;
17572                            }
17573                            Ordering::Less => {
17574                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17575                            }
17576                            Ordering::Greater => {
17577                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17578                            }
17579                        };
17580                        if rename_selection_range.end.0 > old_name.len() {
17581                            editor.select_all(&SelectAll, window, cx);
17582                        } else {
17583                            editor.change_selections(Default::default(), window, cx, |s| {
17584                                s.select_ranges([rename_selection_range]);
17585                            });
17586                        }
17587                        editor
17588                    });
17589                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17590                        if e == &EditorEvent::Focused {
17591                            cx.emit(EditorEvent::FocusedIn)
17592                        }
17593                    })
17594                    .detach();
17595
17596                    let write_highlights =
17597                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17598                    let read_highlights =
17599                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17600                    let ranges = write_highlights
17601                        .iter()
17602                        .flat_map(|(_, ranges)| ranges.iter())
17603                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17604                        .cloned()
17605                        .collect();
17606
17607                    this.highlight_text::<Rename>(
17608                        ranges,
17609                        HighlightStyle {
17610                            fade_out: Some(0.6),
17611                            ..Default::default()
17612                        },
17613                        cx,
17614                    );
17615                    let rename_focus_handle = rename_editor.focus_handle(cx);
17616                    window.focus(&rename_focus_handle);
17617                    let block_id = this.insert_blocks(
17618                        [BlockProperties {
17619                            style: BlockStyle::Flex,
17620                            placement: BlockPlacement::Below(range.start),
17621                            height: Some(1),
17622                            render: Arc::new({
17623                                let rename_editor = rename_editor.clone();
17624                                move |cx: &mut BlockContext| {
17625                                    let mut text_style = cx.editor_style.text.clone();
17626                                    if let Some(highlight_style) = old_highlight_id
17627                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17628                                    {
17629                                        text_style = text_style.highlight(highlight_style);
17630                                    }
17631                                    div()
17632                                        .block_mouse_except_scroll()
17633                                        .pl(cx.anchor_x)
17634                                        .child(EditorElement::new(
17635                                            &rename_editor,
17636                                            EditorStyle {
17637                                                background: cx.theme().system().transparent,
17638                                                local_player: cx.editor_style.local_player,
17639                                                text: text_style,
17640                                                scrollbar_width: cx.editor_style.scrollbar_width,
17641                                                syntax: cx.editor_style.syntax.clone(),
17642                                                status: cx.editor_style.status.clone(),
17643                                                inlay_hints_style: HighlightStyle {
17644                                                    font_weight: Some(FontWeight::BOLD),
17645                                                    ..make_inlay_hints_style(cx.app)
17646                                                },
17647                                                edit_prediction_styles: make_suggestion_styles(
17648                                                    cx.app,
17649                                                ),
17650                                                ..EditorStyle::default()
17651                                            },
17652                                        ))
17653                                        .into_any_element()
17654                                }
17655                            }),
17656                            priority: 0,
17657                        }],
17658                        Some(Autoscroll::fit()),
17659                        cx,
17660                    )[0];
17661                    this.pending_rename = Some(RenameState {
17662                        range,
17663                        old_name,
17664                        editor: rename_editor,
17665                        block_id,
17666                    });
17667                })?;
17668            }
17669
17670            Ok(())
17671        }))
17672    }
17673
17674    pub fn confirm_rename(
17675        &mut self,
17676        _: &ConfirmRename,
17677        window: &mut Window,
17678        cx: &mut Context<Self>,
17679    ) -> Option<Task<Result<()>>> {
17680        let rename = self.take_rename(false, window, cx)?;
17681        let workspace = self.workspace()?.downgrade();
17682        let (buffer, start) = self
17683            .buffer
17684            .read(cx)
17685            .text_anchor_for_position(rename.range.start, cx)?;
17686        let (end_buffer, _) = self
17687            .buffer
17688            .read(cx)
17689            .text_anchor_for_position(rename.range.end, cx)?;
17690        if buffer != end_buffer {
17691            return None;
17692        }
17693
17694        let old_name = rename.old_name;
17695        let new_name = rename.editor.read(cx).text(cx);
17696
17697        let rename = self.semantics_provider.as_ref()?.perform_rename(
17698            &buffer,
17699            start,
17700            new_name.clone(),
17701            cx,
17702        )?;
17703
17704        Some(cx.spawn_in(window, async move |editor, cx| {
17705            let project_transaction = rename.await?;
17706            Self::open_project_transaction(
17707                &editor,
17708                workspace,
17709                project_transaction,
17710                format!("Rename: {}{}", old_name, new_name),
17711                cx,
17712            )
17713            .await?;
17714
17715            editor.update(cx, |editor, cx| {
17716                editor.refresh_document_highlights(cx);
17717            })?;
17718            Ok(())
17719        }))
17720    }
17721
17722    fn take_rename(
17723        &mut self,
17724        moving_cursor: bool,
17725        window: &mut Window,
17726        cx: &mut Context<Self>,
17727    ) -> Option<RenameState> {
17728        let rename = self.pending_rename.take()?;
17729        if rename.editor.focus_handle(cx).is_focused(window) {
17730            window.focus(&self.focus_handle);
17731        }
17732
17733        self.remove_blocks(
17734            [rename.block_id].into_iter().collect(),
17735            Some(Autoscroll::fit()),
17736            cx,
17737        );
17738        self.clear_highlights::<Rename>(cx);
17739        self.show_local_selections = true;
17740
17741        if moving_cursor {
17742            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17743                editor
17744                    .selections
17745                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17746                    .head()
17747            });
17748
17749            // Update the selection to match the position of the selection inside
17750            // the rename editor.
17751            let snapshot = self.buffer.read(cx).read(cx);
17752            let rename_range = rename.range.to_offset(&snapshot);
17753            let cursor_in_editor = snapshot
17754                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17755                .min(rename_range.end);
17756            drop(snapshot);
17757
17758            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17759                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17760            });
17761        } else {
17762            self.refresh_document_highlights(cx);
17763        }
17764
17765        Some(rename)
17766    }
17767
17768    pub fn pending_rename(&self) -> Option<&RenameState> {
17769        self.pending_rename.as_ref()
17770    }
17771
17772    fn format(
17773        &mut self,
17774        _: &Format,
17775        window: &mut Window,
17776        cx: &mut Context<Self>,
17777    ) -> Option<Task<Result<()>>> {
17778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17779
17780        let project = match &self.project {
17781            Some(project) => project.clone(),
17782            None => return None,
17783        };
17784
17785        Some(self.perform_format(
17786            project,
17787            FormatTrigger::Manual,
17788            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17789            window,
17790            cx,
17791        ))
17792    }
17793
17794    fn format_selections(
17795        &mut self,
17796        _: &FormatSelections,
17797        window: &mut Window,
17798        cx: &mut Context<Self>,
17799    ) -> Option<Task<Result<()>>> {
17800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17801
17802        let project = match &self.project {
17803            Some(project) => project.clone(),
17804            None => return None,
17805        };
17806
17807        let ranges = self
17808            .selections
17809            .all_adjusted(&self.display_snapshot(cx))
17810            .into_iter()
17811            .map(|selection| selection.range())
17812            .collect_vec();
17813
17814        Some(self.perform_format(
17815            project,
17816            FormatTrigger::Manual,
17817            FormatTarget::Ranges(ranges),
17818            window,
17819            cx,
17820        ))
17821    }
17822
17823    fn perform_format(
17824        &mut self,
17825        project: Entity<Project>,
17826        trigger: FormatTrigger,
17827        target: FormatTarget,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) -> Task<Result<()>> {
17831        let buffer = self.buffer.clone();
17832        let (buffers, target) = match target {
17833            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17834            FormatTarget::Ranges(selection_ranges) => {
17835                let multi_buffer = buffer.read(cx);
17836                let snapshot = multi_buffer.read(cx);
17837                let mut buffers = HashSet::default();
17838                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17839                    BTreeMap::new();
17840                for selection_range in selection_ranges {
17841                    for (buffer, buffer_range, _) in
17842                        snapshot.range_to_buffer_ranges(selection_range)
17843                    {
17844                        let buffer_id = buffer.remote_id();
17845                        let start = buffer.anchor_before(buffer_range.start);
17846                        let end = buffer.anchor_after(buffer_range.end);
17847                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17848                        buffer_id_to_ranges
17849                            .entry(buffer_id)
17850                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17851                            .or_insert_with(|| vec![start..end]);
17852                    }
17853                }
17854                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17855            }
17856        };
17857
17858        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17859        let selections_prev = transaction_id_prev
17860            .and_then(|transaction_id_prev| {
17861                // default to selections as they were after the last edit, if we have them,
17862                // instead of how they are now.
17863                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17864                // will take you back to where you made the last edit, instead of staying where you scrolled
17865                self.selection_history
17866                    .transaction(transaction_id_prev)
17867                    .map(|t| t.0.clone())
17868            })
17869            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17870
17871        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17872        let format = project.update(cx, |project, cx| {
17873            project.format(buffers, target, true, trigger, cx)
17874        });
17875
17876        cx.spawn_in(window, async move |editor, cx| {
17877            let transaction = futures::select_biased! {
17878                transaction = format.log_err().fuse() => transaction,
17879                () = timeout => {
17880                    log::warn!("timed out waiting for formatting");
17881                    None
17882                }
17883            };
17884
17885            buffer
17886                .update(cx, |buffer, cx| {
17887                    if let Some(transaction) = transaction
17888                        && !buffer.is_singleton()
17889                    {
17890                        buffer.push_transaction(&transaction.0, cx);
17891                    }
17892                    cx.notify();
17893                })
17894                .ok();
17895
17896            if let Some(transaction_id_now) =
17897                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17898            {
17899                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17900                if has_new_transaction {
17901                    _ = editor.update(cx, |editor, _| {
17902                        editor
17903                            .selection_history
17904                            .insert_transaction(transaction_id_now, selections_prev);
17905                    });
17906                }
17907            }
17908
17909            Ok(())
17910        })
17911    }
17912
17913    fn organize_imports(
17914        &mut self,
17915        _: &OrganizeImports,
17916        window: &mut Window,
17917        cx: &mut Context<Self>,
17918    ) -> Option<Task<Result<()>>> {
17919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17920        let project = match &self.project {
17921            Some(project) => project.clone(),
17922            None => return None,
17923        };
17924        Some(self.perform_code_action_kind(
17925            project,
17926            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17927            window,
17928            cx,
17929        ))
17930    }
17931
17932    fn perform_code_action_kind(
17933        &mut self,
17934        project: Entity<Project>,
17935        kind: CodeActionKind,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) -> Task<Result<()>> {
17939        let buffer = self.buffer.clone();
17940        let buffers = buffer.read(cx).all_buffers();
17941        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17942        let apply_action = project.update(cx, |project, cx| {
17943            project.apply_code_action_kind(buffers, kind, true, cx)
17944        });
17945        cx.spawn_in(window, async move |_, cx| {
17946            let transaction = futures::select_biased! {
17947                () = timeout => {
17948                    log::warn!("timed out waiting for executing code action");
17949                    None
17950                }
17951                transaction = apply_action.log_err().fuse() => transaction,
17952            };
17953            buffer
17954                .update(cx, |buffer, cx| {
17955                    // check if we need this
17956                    if let Some(transaction) = transaction
17957                        && !buffer.is_singleton()
17958                    {
17959                        buffer.push_transaction(&transaction.0, cx);
17960                    }
17961                    cx.notify();
17962                })
17963                .ok();
17964            Ok(())
17965        })
17966    }
17967
17968    pub fn restart_language_server(
17969        &mut self,
17970        _: &RestartLanguageServer,
17971        _: &mut Window,
17972        cx: &mut Context<Self>,
17973    ) {
17974        if let Some(project) = self.project.clone() {
17975            self.buffer.update(cx, |multi_buffer, cx| {
17976                project.update(cx, |project, cx| {
17977                    project.restart_language_servers_for_buffers(
17978                        multi_buffer.all_buffers().into_iter().collect(),
17979                        HashSet::default(),
17980                        cx,
17981                    );
17982                });
17983            })
17984        }
17985    }
17986
17987    pub fn stop_language_server(
17988        &mut self,
17989        _: &StopLanguageServer,
17990        _: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) {
17993        if let Some(project) = self.project.clone() {
17994            self.buffer.update(cx, |multi_buffer, cx| {
17995                project.update(cx, |project, cx| {
17996                    project.stop_language_servers_for_buffers(
17997                        multi_buffer.all_buffers().into_iter().collect(),
17998                        HashSet::default(),
17999                        cx,
18000                    );
18001                });
18002            });
18003            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18004        }
18005    }
18006
18007    fn cancel_language_server_work(
18008        workspace: &mut Workspace,
18009        _: &actions::CancelLanguageServerWork,
18010        _: &mut Window,
18011        cx: &mut Context<Workspace>,
18012    ) {
18013        let project = workspace.project();
18014        let buffers = workspace
18015            .active_item(cx)
18016            .and_then(|item| item.act_as::<Editor>(cx))
18017            .map_or(HashSet::default(), |editor| {
18018                editor.read(cx).buffer.read(cx).all_buffers()
18019            });
18020        project.update(cx, |project, cx| {
18021            project.cancel_language_server_work_for_buffers(buffers, cx);
18022        });
18023    }
18024
18025    fn show_character_palette(
18026        &mut self,
18027        _: &ShowCharacterPalette,
18028        window: &mut Window,
18029        _: &mut Context<Self>,
18030    ) {
18031        window.show_character_palette();
18032    }
18033
18034    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18035        if !self.diagnostics_enabled() {
18036            return;
18037        }
18038
18039        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18040            let buffer = self.buffer.read(cx).snapshot(cx);
18041            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18042            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18043            let is_valid = buffer
18044                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18045                .any(|entry| {
18046                    entry.diagnostic.is_primary
18047                        && !entry.range.is_empty()
18048                        && entry.range.start == primary_range_start
18049                        && entry.diagnostic.message == active_diagnostics.active_message
18050                });
18051
18052            if !is_valid {
18053                self.dismiss_diagnostics(cx);
18054            }
18055        }
18056    }
18057
18058    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18059        match &self.active_diagnostics {
18060            ActiveDiagnostic::Group(group) => Some(group),
18061            _ => None,
18062        }
18063    }
18064
18065    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18066        if !self.diagnostics_enabled() {
18067            return;
18068        }
18069        self.dismiss_diagnostics(cx);
18070        self.active_diagnostics = ActiveDiagnostic::All;
18071    }
18072
18073    fn activate_diagnostics(
18074        &mut self,
18075        buffer_id: BufferId,
18076        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18077        window: &mut Window,
18078        cx: &mut Context<Self>,
18079    ) {
18080        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18081            return;
18082        }
18083        self.dismiss_diagnostics(cx);
18084        let snapshot = self.snapshot(window, cx);
18085        let buffer = self.buffer.read(cx).snapshot(cx);
18086        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18087            return;
18088        };
18089
18090        let diagnostic_group = buffer
18091            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18092            .collect::<Vec<_>>();
18093
18094        let language_registry = self
18095            .project()
18096            .map(|project| project.read(cx).languages().clone());
18097
18098        let blocks = renderer.render_group(
18099            diagnostic_group,
18100            buffer_id,
18101            snapshot,
18102            cx.weak_entity(),
18103            language_registry,
18104            cx,
18105        );
18106
18107        let blocks = self.display_map.update(cx, |display_map, cx| {
18108            display_map.insert_blocks(blocks, cx).into_iter().collect()
18109        });
18110        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18111            active_range: buffer.anchor_before(diagnostic.range.start)
18112                ..buffer.anchor_after(diagnostic.range.end),
18113            active_message: diagnostic.diagnostic.message.clone(),
18114            group_id: diagnostic.diagnostic.group_id,
18115            blocks,
18116        });
18117        cx.notify();
18118    }
18119
18120    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18121        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18122            return;
18123        };
18124
18125        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18126        if let ActiveDiagnostic::Group(group) = prev {
18127            self.display_map.update(cx, |display_map, cx| {
18128                display_map.remove_blocks(group.blocks, cx);
18129            });
18130            cx.notify();
18131        }
18132    }
18133
18134    /// Disable inline diagnostics rendering for this editor.
18135    pub fn disable_inline_diagnostics(&mut self) {
18136        self.inline_diagnostics_enabled = false;
18137        self.inline_diagnostics_update = Task::ready(());
18138        self.inline_diagnostics.clear();
18139    }
18140
18141    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18142        self.diagnostics_enabled = false;
18143        self.dismiss_diagnostics(cx);
18144        self.inline_diagnostics_update = Task::ready(());
18145        self.inline_diagnostics.clear();
18146    }
18147
18148    pub fn disable_word_completions(&mut self) {
18149        self.word_completions_enabled = false;
18150    }
18151
18152    pub fn diagnostics_enabled(&self) -> bool {
18153        self.diagnostics_enabled && self.mode.is_full()
18154    }
18155
18156    pub fn inline_diagnostics_enabled(&self) -> bool {
18157        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18158    }
18159
18160    pub fn show_inline_diagnostics(&self) -> bool {
18161        self.show_inline_diagnostics
18162    }
18163
18164    pub fn toggle_inline_diagnostics(
18165        &mut self,
18166        _: &ToggleInlineDiagnostics,
18167        window: &mut Window,
18168        cx: &mut Context<Editor>,
18169    ) {
18170        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18171        self.refresh_inline_diagnostics(false, window, cx);
18172    }
18173
18174    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18175        self.diagnostics_max_severity = severity;
18176        self.display_map.update(cx, |display_map, _| {
18177            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18178        });
18179    }
18180
18181    pub fn toggle_diagnostics(
18182        &mut self,
18183        _: &ToggleDiagnostics,
18184        window: &mut Window,
18185        cx: &mut Context<Editor>,
18186    ) {
18187        if !self.diagnostics_enabled() {
18188            return;
18189        }
18190
18191        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18192            EditorSettings::get_global(cx)
18193                .diagnostics_max_severity
18194                .filter(|severity| severity != &DiagnosticSeverity::Off)
18195                .unwrap_or(DiagnosticSeverity::Hint)
18196        } else {
18197            DiagnosticSeverity::Off
18198        };
18199        self.set_max_diagnostics_severity(new_severity, cx);
18200        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18201            self.active_diagnostics = ActiveDiagnostic::None;
18202            self.inline_diagnostics_update = Task::ready(());
18203            self.inline_diagnostics.clear();
18204        } else {
18205            self.refresh_inline_diagnostics(false, window, cx);
18206        }
18207
18208        cx.notify();
18209    }
18210
18211    pub fn toggle_minimap(
18212        &mut self,
18213        _: &ToggleMinimap,
18214        window: &mut Window,
18215        cx: &mut Context<Editor>,
18216    ) {
18217        if self.supports_minimap(cx) {
18218            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18219        }
18220    }
18221
18222    fn refresh_inline_diagnostics(
18223        &mut self,
18224        debounce: bool,
18225        window: &mut Window,
18226        cx: &mut Context<Self>,
18227    ) {
18228        let max_severity = ProjectSettings::get_global(cx)
18229            .diagnostics
18230            .inline
18231            .max_severity
18232            .unwrap_or(self.diagnostics_max_severity);
18233
18234        if !self.inline_diagnostics_enabled()
18235            || !self.diagnostics_enabled()
18236            || !self.show_inline_diagnostics
18237            || max_severity == DiagnosticSeverity::Off
18238        {
18239            self.inline_diagnostics_update = Task::ready(());
18240            self.inline_diagnostics.clear();
18241            return;
18242        }
18243
18244        let debounce_ms = ProjectSettings::get_global(cx)
18245            .diagnostics
18246            .inline
18247            .update_debounce_ms;
18248        let debounce = if debounce && debounce_ms > 0 {
18249            Some(Duration::from_millis(debounce_ms))
18250        } else {
18251            None
18252        };
18253        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18254            if let Some(debounce) = debounce {
18255                cx.background_executor().timer(debounce).await;
18256            }
18257            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18258                editor
18259                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18260                    .ok()
18261            }) else {
18262                return;
18263            };
18264
18265            let new_inline_diagnostics = cx
18266                .background_spawn(async move {
18267                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18268                    for diagnostic_entry in
18269                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18270                    {
18271                        let message = diagnostic_entry
18272                            .diagnostic
18273                            .message
18274                            .split_once('\n')
18275                            .map(|(line, _)| line)
18276                            .map(SharedString::new)
18277                            .unwrap_or_else(|| {
18278                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18279                            });
18280                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18281                        let (Ok(i) | Err(i)) = inline_diagnostics
18282                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18283                        inline_diagnostics.insert(
18284                            i,
18285                            (
18286                                start_anchor,
18287                                InlineDiagnostic {
18288                                    message,
18289                                    group_id: diagnostic_entry.diagnostic.group_id,
18290                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18291                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18292                                    severity: diagnostic_entry.diagnostic.severity,
18293                                },
18294                            ),
18295                        );
18296                    }
18297                    inline_diagnostics
18298                })
18299                .await;
18300
18301            editor
18302                .update(cx, |editor, cx| {
18303                    editor.inline_diagnostics = new_inline_diagnostics;
18304                    cx.notify();
18305                })
18306                .ok();
18307        });
18308    }
18309
18310    fn pull_diagnostics(
18311        &mut self,
18312        buffer_id: Option<BufferId>,
18313        window: &Window,
18314        cx: &mut Context<Self>,
18315    ) -> Option<()> {
18316        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18317            return None;
18318        }
18319        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18320            .diagnostics
18321            .lsp_pull_diagnostics;
18322        if !pull_diagnostics_settings.enabled {
18323            return None;
18324        }
18325        let project = self.project()?.downgrade();
18326        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18327        let mut buffers = self.buffer.read(cx).all_buffers();
18328        buffers.retain(|buffer| {
18329            let buffer_id_to_retain = buffer.read(cx).remote_id();
18330            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18331                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18332        });
18333        if buffers.is_empty() {
18334            self.pull_diagnostics_task = Task::ready(());
18335            return None;
18336        }
18337
18338        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18339            cx.background_executor().timer(debounce).await;
18340
18341            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18342                buffers
18343                    .into_iter()
18344                    .filter_map(|buffer| {
18345                        project
18346                            .update(cx, |project, cx| {
18347                                project.lsp_store().update(cx, |lsp_store, cx| {
18348                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18349                                })
18350                            })
18351                            .ok()
18352                    })
18353                    .collect::<FuturesUnordered<_>>()
18354            }) else {
18355                return;
18356            };
18357
18358            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18359                match pull_task {
18360                    Ok(()) => {
18361                        if editor
18362                            .update_in(cx, |editor, window, cx| {
18363                                editor.update_diagnostics_state(window, cx);
18364                            })
18365                            .is_err()
18366                        {
18367                            return;
18368                        }
18369                    }
18370                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18371                }
18372            }
18373        });
18374
18375        Some(())
18376    }
18377
18378    pub fn set_selections_from_remote(
18379        &mut self,
18380        selections: Vec<Selection<Anchor>>,
18381        pending_selection: Option<Selection<Anchor>>,
18382        window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        let old_cursor_position = self.selections.newest_anchor().head();
18386        self.selections
18387            .change_with(&self.display_snapshot(cx), |s| {
18388                s.select_anchors(selections);
18389                if let Some(pending_selection) = pending_selection {
18390                    s.set_pending(pending_selection, SelectMode::Character);
18391                } else {
18392                    s.clear_pending();
18393                }
18394            });
18395        self.selections_did_change(
18396            false,
18397            &old_cursor_position,
18398            SelectionEffects::default(),
18399            window,
18400            cx,
18401        );
18402    }
18403
18404    pub fn transact(
18405        &mut self,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18409    ) -> Option<TransactionId> {
18410        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18411            this.start_transaction_at(Instant::now(), window, cx);
18412            update(this, window, cx);
18413            this.end_transaction_at(Instant::now(), cx)
18414        })
18415    }
18416
18417    pub fn start_transaction_at(
18418        &mut self,
18419        now: Instant,
18420        window: &mut Window,
18421        cx: &mut Context<Self>,
18422    ) -> Option<TransactionId> {
18423        self.end_selection(window, cx);
18424        if let Some(tx_id) = self
18425            .buffer
18426            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18427        {
18428            self.selection_history
18429                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18430            cx.emit(EditorEvent::TransactionBegun {
18431                transaction_id: tx_id,
18432            });
18433            Some(tx_id)
18434        } else {
18435            None
18436        }
18437    }
18438
18439    pub fn end_transaction_at(
18440        &mut self,
18441        now: Instant,
18442        cx: &mut Context<Self>,
18443    ) -> Option<TransactionId> {
18444        if let Some(transaction_id) = self
18445            .buffer
18446            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18447        {
18448            if let Some((_, end_selections)) =
18449                self.selection_history.transaction_mut(transaction_id)
18450            {
18451                *end_selections = Some(self.selections.disjoint_anchors_arc());
18452            } else {
18453                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18454            }
18455
18456            cx.emit(EditorEvent::Edited { transaction_id });
18457            Some(transaction_id)
18458        } else {
18459            None
18460        }
18461    }
18462
18463    pub fn modify_transaction_selection_history(
18464        &mut self,
18465        transaction_id: TransactionId,
18466        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18467    ) -> bool {
18468        self.selection_history
18469            .transaction_mut(transaction_id)
18470            .map(modify)
18471            .is_some()
18472    }
18473
18474    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18475        if self.selection_mark_mode {
18476            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18477                s.move_with(|_, sel| {
18478                    sel.collapse_to(sel.head(), SelectionGoal::None);
18479                });
18480            })
18481        }
18482        self.selection_mark_mode = true;
18483        cx.notify();
18484    }
18485
18486    pub fn swap_selection_ends(
18487        &mut self,
18488        _: &actions::SwapSelectionEnds,
18489        window: &mut Window,
18490        cx: &mut Context<Self>,
18491    ) {
18492        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18493            s.move_with(|_, sel| {
18494                if sel.start != sel.end {
18495                    sel.reversed = !sel.reversed
18496                }
18497            });
18498        });
18499        self.request_autoscroll(Autoscroll::newest(), cx);
18500        cx.notify();
18501    }
18502
18503    pub fn toggle_focus(
18504        workspace: &mut Workspace,
18505        _: &actions::ToggleFocus,
18506        window: &mut Window,
18507        cx: &mut Context<Workspace>,
18508    ) {
18509        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18510            return;
18511        };
18512        workspace.activate_item(&item, true, true, window, cx);
18513    }
18514
18515    pub fn toggle_fold(
18516        &mut self,
18517        _: &actions::ToggleFold,
18518        window: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18522            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18523            let selection = self.selections.newest::<Point>(&display_map);
18524
18525            let range = if selection.is_empty() {
18526                let point = selection.head().to_display_point(&display_map);
18527                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18528                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18529                    .to_point(&display_map);
18530                start..end
18531            } else {
18532                selection.range()
18533            };
18534            if display_map.folds_in_range(range).next().is_some() {
18535                self.unfold_lines(&Default::default(), window, cx)
18536            } else {
18537                self.fold(&Default::default(), window, cx)
18538            }
18539        } else {
18540            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18541            let buffer_ids: HashSet<_> = self
18542                .selections
18543                .disjoint_anchor_ranges()
18544                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18545                .collect();
18546
18547            let should_unfold = buffer_ids
18548                .iter()
18549                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18550
18551            for buffer_id in buffer_ids {
18552                if should_unfold {
18553                    self.unfold_buffer(buffer_id, cx);
18554                } else {
18555                    self.fold_buffer(buffer_id, cx);
18556                }
18557            }
18558        }
18559    }
18560
18561    pub fn toggle_fold_recursive(
18562        &mut self,
18563        _: &actions::ToggleFoldRecursive,
18564        window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18568
18569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18570        let range = if selection.is_empty() {
18571            let point = selection.head().to_display_point(&display_map);
18572            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18573            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18574                .to_point(&display_map);
18575            start..end
18576        } else {
18577            selection.range()
18578        };
18579        if display_map.folds_in_range(range).next().is_some() {
18580            self.unfold_recursive(&Default::default(), window, cx)
18581        } else {
18582            self.fold_recursive(&Default::default(), window, cx)
18583        }
18584    }
18585
18586    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18587        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18588            let mut to_fold = Vec::new();
18589            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18590            let selections = self.selections.all_adjusted(&display_map);
18591
18592            for selection in selections {
18593                let range = selection.range().sorted();
18594                let buffer_start_row = range.start.row;
18595
18596                if range.start.row != range.end.row {
18597                    let mut found = false;
18598                    let mut row = range.start.row;
18599                    while row <= range.end.row {
18600                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18601                        {
18602                            found = true;
18603                            row = crease.range().end.row + 1;
18604                            to_fold.push(crease);
18605                        } else {
18606                            row += 1
18607                        }
18608                    }
18609                    if found {
18610                        continue;
18611                    }
18612                }
18613
18614                for row in (0..=range.start.row).rev() {
18615                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18616                        && crease.range().end.row >= buffer_start_row
18617                    {
18618                        to_fold.push(crease);
18619                        if row <= range.start.row {
18620                            break;
18621                        }
18622                    }
18623                }
18624            }
18625
18626            self.fold_creases(to_fold, true, window, cx);
18627        } else {
18628            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18629            let buffer_ids = self
18630                .selections
18631                .disjoint_anchor_ranges()
18632                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18633                .collect::<HashSet<_>>();
18634            for buffer_id in buffer_ids {
18635                self.fold_buffer(buffer_id, cx);
18636            }
18637        }
18638    }
18639
18640    pub fn toggle_fold_all(
18641        &mut self,
18642        _: &actions::ToggleFoldAll,
18643        window: &mut Window,
18644        cx: &mut Context<Self>,
18645    ) {
18646        if self.buffer.read(cx).is_singleton() {
18647            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18648            let has_folds = display_map
18649                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18650                .next()
18651                .is_some();
18652
18653            if has_folds {
18654                self.unfold_all(&actions::UnfoldAll, window, cx);
18655            } else {
18656                self.fold_all(&actions::FoldAll, window, cx);
18657            }
18658        } else {
18659            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18660            let should_unfold = buffer_ids
18661                .iter()
18662                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18663
18664            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18665                editor
18666                    .update_in(cx, |editor, _, cx| {
18667                        for buffer_id in buffer_ids {
18668                            if should_unfold {
18669                                editor.unfold_buffer(buffer_id, cx);
18670                            } else {
18671                                editor.fold_buffer(buffer_id, cx);
18672                            }
18673                        }
18674                    })
18675                    .ok();
18676            });
18677        }
18678    }
18679
18680    fn fold_at_level(
18681        &mut self,
18682        fold_at: &FoldAtLevel,
18683        window: &mut Window,
18684        cx: &mut Context<Self>,
18685    ) {
18686        if !self.buffer.read(cx).is_singleton() {
18687            return;
18688        }
18689
18690        let fold_at_level = fold_at.0;
18691        let snapshot = self.buffer.read(cx).snapshot(cx);
18692        let mut to_fold = Vec::new();
18693        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18694
18695        let row_ranges_to_keep: Vec<Range<u32>> = self
18696            .selections
18697            .all::<Point>(&self.display_snapshot(cx))
18698            .into_iter()
18699            .map(|sel| sel.start.row..sel.end.row)
18700            .collect();
18701
18702        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18703            while start_row < end_row {
18704                match self
18705                    .snapshot(window, cx)
18706                    .crease_for_buffer_row(MultiBufferRow(start_row))
18707                {
18708                    Some(crease) => {
18709                        let nested_start_row = crease.range().start.row + 1;
18710                        let nested_end_row = crease.range().end.row;
18711
18712                        if current_level < fold_at_level {
18713                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18714                        } else if current_level == fold_at_level {
18715                            // Fold iff there is no selection completely contained within the fold region
18716                            if !row_ranges_to_keep.iter().any(|selection| {
18717                                selection.end >= nested_start_row
18718                                    && selection.start <= nested_end_row
18719                            }) {
18720                                to_fold.push(crease);
18721                            }
18722                        }
18723
18724                        start_row = nested_end_row + 1;
18725                    }
18726                    None => start_row += 1,
18727                }
18728            }
18729        }
18730
18731        self.fold_creases(to_fold, true, window, cx);
18732    }
18733
18734    pub fn fold_at_level_1(
18735        &mut self,
18736        _: &actions::FoldAtLevel1,
18737        window: &mut Window,
18738        cx: &mut Context<Self>,
18739    ) {
18740        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18741    }
18742
18743    pub fn fold_at_level_2(
18744        &mut self,
18745        _: &actions::FoldAtLevel2,
18746        window: &mut Window,
18747        cx: &mut Context<Self>,
18748    ) {
18749        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18750    }
18751
18752    pub fn fold_at_level_3(
18753        &mut self,
18754        _: &actions::FoldAtLevel3,
18755        window: &mut Window,
18756        cx: &mut Context<Self>,
18757    ) {
18758        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18759    }
18760
18761    pub fn fold_at_level_4(
18762        &mut self,
18763        _: &actions::FoldAtLevel4,
18764        window: &mut Window,
18765        cx: &mut Context<Self>,
18766    ) {
18767        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18768    }
18769
18770    pub fn fold_at_level_5(
18771        &mut self,
18772        _: &actions::FoldAtLevel5,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18777    }
18778
18779    pub fn fold_at_level_6(
18780        &mut self,
18781        _: &actions::FoldAtLevel6,
18782        window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18786    }
18787
18788    pub fn fold_at_level_7(
18789        &mut self,
18790        _: &actions::FoldAtLevel7,
18791        window: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18795    }
18796
18797    pub fn fold_at_level_8(
18798        &mut self,
18799        _: &actions::FoldAtLevel8,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18804    }
18805
18806    pub fn fold_at_level_9(
18807        &mut self,
18808        _: &actions::FoldAtLevel9,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18813    }
18814
18815    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18816        if self.buffer.read(cx).is_singleton() {
18817            let mut fold_ranges = Vec::new();
18818            let snapshot = self.buffer.read(cx).snapshot(cx);
18819
18820            for row in 0..snapshot.max_row().0 {
18821                if let Some(foldable_range) = self
18822                    .snapshot(window, cx)
18823                    .crease_for_buffer_row(MultiBufferRow(row))
18824                {
18825                    fold_ranges.push(foldable_range);
18826                }
18827            }
18828
18829            self.fold_creases(fold_ranges, true, window, cx);
18830        } else {
18831            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18832                editor
18833                    .update_in(cx, |editor, _, cx| {
18834                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18835                            editor.fold_buffer(buffer_id, cx);
18836                        }
18837                    })
18838                    .ok();
18839            });
18840        }
18841    }
18842
18843    pub fn fold_function_bodies(
18844        &mut self,
18845        _: &actions::FoldFunctionBodies,
18846        window: &mut Window,
18847        cx: &mut Context<Self>,
18848    ) {
18849        let snapshot = self.buffer.read(cx).snapshot(cx);
18850
18851        let ranges = snapshot
18852            .text_object_ranges(
18853                MultiBufferOffset(0)..snapshot.len(),
18854                TreeSitterOptions::default(),
18855            )
18856            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18857            .collect::<Vec<_>>();
18858
18859        let creases = ranges
18860            .into_iter()
18861            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18862            .collect();
18863
18864        self.fold_creases(creases, true, window, cx);
18865    }
18866
18867    pub fn fold_recursive(
18868        &mut self,
18869        _: &actions::FoldRecursive,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        let mut to_fold = Vec::new();
18874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18875        let selections = self.selections.all_adjusted(&display_map);
18876
18877        for selection in selections {
18878            let range = selection.range().sorted();
18879            let buffer_start_row = range.start.row;
18880
18881            if range.start.row != range.end.row {
18882                let mut found = false;
18883                for row in range.start.row..=range.end.row {
18884                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18885                        found = true;
18886                        to_fold.push(crease);
18887                    }
18888                }
18889                if found {
18890                    continue;
18891                }
18892            }
18893
18894            for row in (0..=range.start.row).rev() {
18895                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18896                    if crease.range().end.row >= buffer_start_row {
18897                        to_fold.push(crease);
18898                    } else {
18899                        break;
18900                    }
18901                }
18902            }
18903        }
18904
18905        self.fold_creases(to_fold, true, window, cx);
18906    }
18907
18908    pub fn fold_at(
18909        &mut self,
18910        buffer_row: MultiBufferRow,
18911        window: &mut Window,
18912        cx: &mut Context<Self>,
18913    ) {
18914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18915
18916        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18917            let autoscroll = self
18918                .selections
18919                .all::<Point>(&display_map)
18920                .iter()
18921                .any(|selection| crease.range().overlaps(&selection.range()));
18922
18923            self.fold_creases(vec![crease], autoscroll, window, cx);
18924        }
18925    }
18926
18927    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18928        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18929            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18930            let buffer = display_map.buffer_snapshot();
18931            let selections = self.selections.all::<Point>(&display_map);
18932            let ranges = selections
18933                .iter()
18934                .map(|s| {
18935                    let range = s.display_range(&display_map).sorted();
18936                    let mut start = range.start.to_point(&display_map);
18937                    let mut end = range.end.to_point(&display_map);
18938                    start.column = 0;
18939                    end.column = buffer.line_len(MultiBufferRow(end.row));
18940                    start..end
18941                })
18942                .collect::<Vec<_>>();
18943
18944            self.unfold_ranges(&ranges, true, true, cx);
18945        } else {
18946            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18947            let buffer_ids = self
18948                .selections
18949                .disjoint_anchor_ranges()
18950                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18951                .collect::<HashSet<_>>();
18952            for buffer_id in buffer_ids {
18953                self.unfold_buffer(buffer_id, cx);
18954            }
18955        }
18956    }
18957
18958    pub fn unfold_recursive(
18959        &mut self,
18960        _: &UnfoldRecursive,
18961        _window: &mut Window,
18962        cx: &mut Context<Self>,
18963    ) {
18964        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18965        let selections = self.selections.all::<Point>(&display_map);
18966        let ranges = selections
18967            .iter()
18968            .map(|s| {
18969                let mut range = s.display_range(&display_map).sorted();
18970                *range.start.column_mut() = 0;
18971                *range.end.column_mut() = display_map.line_len(range.end.row());
18972                let start = range.start.to_point(&display_map);
18973                let end = range.end.to_point(&display_map);
18974                start..end
18975            })
18976            .collect::<Vec<_>>();
18977
18978        self.unfold_ranges(&ranges, true, true, cx);
18979    }
18980
18981    pub fn unfold_at(
18982        &mut self,
18983        buffer_row: MultiBufferRow,
18984        _window: &mut Window,
18985        cx: &mut Context<Self>,
18986    ) {
18987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18988
18989        let intersection_range = Point::new(buffer_row.0, 0)
18990            ..Point::new(
18991                buffer_row.0,
18992                display_map.buffer_snapshot().line_len(buffer_row),
18993            );
18994
18995        let autoscroll = self
18996            .selections
18997            .all::<Point>(&display_map)
18998            .iter()
18999            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19000
19001        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19002    }
19003
19004    pub fn unfold_all(
19005        &mut self,
19006        _: &actions::UnfoldAll,
19007        _window: &mut Window,
19008        cx: &mut Context<Self>,
19009    ) {
19010        if self.buffer.read(cx).is_singleton() {
19011            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19012            self.unfold_ranges(
19013                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19014                true,
19015                true,
19016                cx,
19017            );
19018        } else {
19019            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19020                editor
19021                    .update(cx, |editor, cx| {
19022                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19023                            editor.unfold_buffer(buffer_id, cx);
19024                        }
19025                    })
19026                    .ok();
19027            });
19028        }
19029    }
19030
19031    pub fn fold_selected_ranges(
19032        &mut self,
19033        _: &FoldSelectedRanges,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19038        let selections = self.selections.all_adjusted(&display_map);
19039        let ranges = selections
19040            .into_iter()
19041            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19042            .collect::<Vec<_>>();
19043        self.fold_creases(ranges, true, window, cx);
19044    }
19045
19046    pub fn fold_ranges<T: ToOffset + Clone>(
19047        &mut self,
19048        ranges: Vec<Range<T>>,
19049        auto_scroll: bool,
19050        window: &mut Window,
19051        cx: &mut Context<Self>,
19052    ) {
19053        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19054        let ranges = ranges
19055            .into_iter()
19056            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19057            .collect::<Vec<_>>();
19058        self.fold_creases(ranges, auto_scroll, window, cx);
19059    }
19060
19061    pub fn fold_creases<T: ToOffset + Clone>(
19062        &mut self,
19063        creases: Vec<Crease<T>>,
19064        auto_scroll: bool,
19065        _window: &mut Window,
19066        cx: &mut Context<Self>,
19067    ) {
19068        if creases.is_empty() {
19069            return;
19070        }
19071
19072        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19073
19074        if auto_scroll {
19075            self.request_autoscroll(Autoscroll::fit(), cx);
19076        }
19077
19078        cx.notify();
19079
19080        self.scrollbar_marker_state.dirty = true;
19081        self.folds_did_change(cx);
19082    }
19083
19084    /// Removes any folds whose ranges intersect any of the given ranges.
19085    pub fn unfold_ranges<T: ToOffset + Clone>(
19086        &mut self,
19087        ranges: &[Range<T>],
19088        inclusive: bool,
19089        auto_scroll: bool,
19090        cx: &mut Context<Self>,
19091    ) {
19092        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19093            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19094        });
19095        self.folds_did_change(cx);
19096    }
19097
19098    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19099        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19100            return;
19101        }
19102
19103        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19104        self.display_map.update(cx, |display_map, cx| {
19105            display_map.fold_buffers([buffer_id], cx)
19106        });
19107
19108        let snapshot = self.display_snapshot(cx);
19109        self.selections.change_with(&snapshot, |selections| {
19110            selections.remove_selections_from_buffer(buffer_id);
19111        });
19112
19113        cx.emit(EditorEvent::BufferFoldToggled {
19114            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19115            folded: true,
19116        });
19117        cx.notify();
19118    }
19119
19120    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19121        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19122            return;
19123        }
19124        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19125        self.display_map.update(cx, |display_map, cx| {
19126            display_map.unfold_buffers([buffer_id], cx);
19127        });
19128        cx.emit(EditorEvent::BufferFoldToggled {
19129            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19130            folded: false,
19131        });
19132        cx.notify();
19133    }
19134
19135    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19136        self.display_map.read(cx).is_buffer_folded(buffer)
19137    }
19138
19139    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19140        self.display_map.read(cx).folded_buffers()
19141    }
19142
19143    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19144        self.display_map.update(cx, |display_map, cx| {
19145            display_map.disable_header_for_buffer(buffer_id, cx);
19146        });
19147        cx.notify();
19148    }
19149
19150    /// Removes any folds with the given ranges.
19151    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19152        &mut self,
19153        ranges: &[Range<T>],
19154        type_id: TypeId,
19155        auto_scroll: bool,
19156        cx: &mut Context<Self>,
19157    ) {
19158        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19159            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19160        });
19161        self.folds_did_change(cx);
19162    }
19163
19164    fn remove_folds_with<T: ToOffset + Clone>(
19165        &mut self,
19166        ranges: &[Range<T>],
19167        auto_scroll: bool,
19168        cx: &mut Context<Self>,
19169        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19170    ) {
19171        if ranges.is_empty() {
19172            return;
19173        }
19174
19175        let mut buffers_affected = HashSet::default();
19176        let multi_buffer = self.buffer().read(cx);
19177        for range in ranges {
19178            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19179                buffers_affected.insert(buffer.read(cx).remote_id());
19180            };
19181        }
19182
19183        self.display_map.update(cx, update);
19184
19185        if auto_scroll {
19186            self.request_autoscroll(Autoscroll::fit(), cx);
19187        }
19188
19189        cx.notify();
19190        self.scrollbar_marker_state.dirty = true;
19191        self.active_indent_guides_state.dirty = true;
19192    }
19193
19194    pub fn update_renderer_widths(
19195        &mut self,
19196        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19197        cx: &mut Context<Self>,
19198    ) -> bool {
19199        self.display_map
19200            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19201    }
19202
19203    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19204        self.display_map.read(cx).fold_placeholder.clone()
19205    }
19206
19207    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19208        self.buffer.update(cx, |buffer, cx| {
19209            buffer.set_all_diff_hunks_expanded(cx);
19210        });
19211    }
19212
19213    pub fn expand_all_diff_hunks(
19214        &mut self,
19215        _: &ExpandAllDiffHunks,
19216        _window: &mut Window,
19217        cx: &mut Context<Self>,
19218    ) {
19219        self.buffer.update(cx, |buffer, cx| {
19220            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19221        });
19222    }
19223
19224    pub fn collapse_all_diff_hunks(
19225        &mut self,
19226        _: &CollapseAllDiffHunks,
19227        _window: &mut Window,
19228        cx: &mut Context<Self>,
19229    ) {
19230        self.buffer.update(cx, |buffer, cx| {
19231            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19232        });
19233    }
19234
19235    pub fn toggle_selected_diff_hunks(
19236        &mut self,
19237        _: &ToggleSelectedDiffHunks,
19238        _window: &mut Window,
19239        cx: &mut Context<Self>,
19240    ) {
19241        let ranges: Vec<_> = self
19242            .selections
19243            .disjoint_anchors()
19244            .iter()
19245            .map(|s| s.range())
19246            .collect();
19247        self.toggle_diff_hunks_in_ranges(ranges, cx);
19248    }
19249
19250    pub fn diff_hunks_in_ranges<'a>(
19251        &'a self,
19252        ranges: &'a [Range<Anchor>],
19253        buffer: &'a MultiBufferSnapshot,
19254    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19255        ranges.iter().flat_map(move |range| {
19256            let end_excerpt_id = range.end.excerpt_id;
19257            let range = range.to_point(buffer);
19258            let mut peek_end = range.end;
19259            if range.end.row < buffer.max_row().0 {
19260                peek_end = Point::new(range.end.row + 1, 0);
19261            }
19262            buffer
19263                .diff_hunks_in_range(range.start..peek_end)
19264                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19265        })
19266    }
19267
19268    pub fn has_stageable_diff_hunks_in_ranges(
19269        &self,
19270        ranges: &[Range<Anchor>],
19271        snapshot: &MultiBufferSnapshot,
19272    ) -> bool {
19273        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19274        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19275    }
19276
19277    pub fn toggle_staged_selected_diff_hunks(
19278        &mut self,
19279        _: &::git::ToggleStaged,
19280        _: &mut Window,
19281        cx: &mut Context<Self>,
19282    ) {
19283        let snapshot = self.buffer.read(cx).snapshot(cx);
19284        let ranges: Vec<_> = self
19285            .selections
19286            .disjoint_anchors()
19287            .iter()
19288            .map(|s| s.range())
19289            .collect();
19290        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19291        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19292    }
19293
19294    pub fn set_render_diff_hunk_controls(
19295        &mut self,
19296        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19297        cx: &mut Context<Self>,
19298    ) {
19299        self.render_diff_hunk_controls = render_diff_hunk_controls;
19300        cx.notify();
19301    }
19302
19303    pub fn stage_and_next(
19304        &mut self,
19305        _: &::git::StageAndNext,
19306        window: &mut Window,
19307        cx: &mut Context<Self>,
19308    ) {
19309        self.do_stage_or_unstage_and_next(true, window, cx);
19310    }
19311
19312    pub fn unstage_and_next(
19313        &mut self,
19314        _: &::git::UnstageAndNext,
19315        window: &mut Window,
19316        cx: &mut Context<Self>,
19317    ) {
19318        self.do_stage_or_unstage_and_next(false, window, cx);
19319    }
19320
19321    pub fn stage_or_unstage_diff_hunks(
19322        &mut self,
19323        stage: bool,
19324        ranges: Vec<Range<Anchor>>,
19325        cx: &mut Context<Self>,
19326    ) {
19327        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19328        cx.spawn(async move |this, cx| {
19329            task.await?;
19330            this.update(cx, |this, cx| {
19331                let snapshot = this.buffer.read(cx).snapshot(cx);
19332                let chunk_by = this
19333                    .diff_hunks_in_ranges(&ranges, &snapshot)
19334                    .chunk_by(|hunk| hunk.buffer_id);
19335                for (buffer_id, hunks) in &chunk_by {
19336                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19337                }
19338            })
19339        })
19340        .detach_and_log_err(cx);
19341    }
19342
19343    fn save_buffers_for_ranges_if_needed(
19344        &mut self,
19345        ranges: &[Range<Anchor>],
19346        cx: &mut Context<Editor>,
19347    ) -> Task<Result<()>> {
19348        let multibuffer = self.buffer.read(cx);
19349        let snapshot = multibuffer.read(cx);
19350        let buffer_ids: HashSet<_> = ranges
19351            .iter()
19352            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19353            .collect();
19354        drop(snapshot);
19355
19356        let mut buffers = HashSet::default();
19357        for buffer_id in buffer_ids {
19358            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19359                let buffer = buffer_entity.read(cx);
19360                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19361                {
19362                    buffers.insert(buffer_entity);
19363                }
19364            }
19365        }
19366
19367        if let Some(project) = &self.project {
19368            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19369        } else {
19370            Task::ready(Ok(()))
19371        }
19372    }
19373
19374    fn do_stage_or_unstage_and_next(
19375        &mut self,
19376        stage: bool,
19377        window: &mut Window,
19378        cx: &mut Context<Self>,
19379    ) {
19380        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19381
19382        if ranges.iter().any(|range| range.start != range.end) {
19383            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19384            return;
19385        }
19386
19387        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19388        let snapshot = self.snapshot(window, cx);
19389        let position = self
19390            .selections
19391            .newest::<Point>(&snapshot.display_snapshot)
19392            .head();
19393        let mut row = snapshot
19394            .buffer_snapshot()
19395            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19396            .find(|hunk| hunk.row_range.start.0 > position.row)
19397            .map(|hunk| hunk.row_range.start);
19398
19399        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19400        // Outside of the project diff editor, wrap around to the beginning.
19401        if !all_diff_hunks_expanded {
19402            row = row.or_else(|| {
19403                snapshot
19404                    .buffer_snapshot()
19405                    .diff_hunks_in_range(Point::zero()..position)
19406                    .find(|hunk| hunk.row_range.end.0 < position.row)
19407                    .map(|hunk| hunk.row_range.start)
19408            });
19409        }
19410
19411        if let Some(row) = row {
19412            let destination = Point::new(row.0, 0);
19413            let autoscroll = Autoscroll::center();
19414
19415            self.unfold_ranges(&[destination..destination], false, false, cx);
19416            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19417                s.select_ranges([destination..destination]);
19418            });
19419        }
19420    }
19421
19422    fn do_stage_or_unstage(
19423        &self,
19424        stage: bool,
19425        buffer_id: BufferId,
19426        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19427        cx: &mut App,
19428    ) -> Option<()> {
19429        let project = self.project()?;
19430        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19431        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19432        let buffer_snapshot = buffer.read(cx).snapshot();
19433        let file_exists = buffer_snapshot
19434            .file()
19435            .is_some_and(|file| file.disk_state().exists());
19436        diff.update(cx, |diff, cx| {
19437            diff.stage_or_unstage_hunks(
19438                stage,
19439                &hunks
19440                    .map(|hunk| buffer_diff::DiffHunk {
19441                        buffer_range: hunk.buffer_range,
19442                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19443                            ..hunk.diff_base_byte_range.end.0,
19444                        secondary_status: hunk.secondary_status,
19445                        range: Point::zero()..Point::zero(), // unused
19446                    })
19447                    .collect::<Vec<_>>(),
19448                &buffer_snapshot,
19449                file_exists,
19450                cx,
19451            )
19452        });
19453        None
19454    }
19455
19456    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19457        let ranges: Vec<_> = self
19458            .selections
19459            .disjoint_anchors()
19460            .iter()
19461            .map(|s| s.range())
19462            .collect();
19463        self.buffer
19464            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19465    }
19466
19467    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19468        self.buffer.update(cx, |buffer, cx| {
19469            let ranges = vec![Anchor::min()..Anchor::max()];
19470            if !buffer.all_diff_hunks_expanded()
19471                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19472            {
19473                buffer.collapse_diff_hunks(ranges, cx);
19474                true
19475            } else {
19476                false
19477            }
19478        })
19479    }
19480
19481    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19482        if self.buffer.read(cx).all_diff_hunks_expanded() {
19483            return true;
19484        }
19485        let ranges = vec![Anchor::min()..Anchor::max()];
19486        self.buffer
19487            .read(cx)
19488            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19489    }
19490
19491    fn toggle_diff_hunks_in_ranges(
19492        &mut self,
19493        ranges: Vec<Range<Anchor>>,
19494        cx: &mut Context<Editor>,
19495    ) {
19496        self.buffer.update(cx, |buffer, cx| {
19497            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19498            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19499        })
19500    }
19501
19502    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19503        self.buffer.update(cx, |buffer, cx| {
19504            let snapshot = buffer.snapshot(cx);
19505            let excerpt_id = range.end.excerpt_id;
19506            let point_range = range.to_point(&snapshot);
19507            let expand = !buffer.single_hunk_is_expanded(range, cx);
19508            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19509        })
19510    }
19511
19512    pub(crate) fn apply_all_diff_hunks(
19513        &mut self,
19514        _: &ApplyAllDiffHunks,
19515        window: &mut Window,
19516        cx: &mut Context<Self>,
19517    ) {
19518        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19519
19520        let buffers = self.buffer.read(cx).all_buffers();
19521        for branch_buffer in buffers {
19522            branch_buffer.update(cx, |branch_buffer, cx| {
19523                branch_buffer.merge_into_base(Vec::new(), cx);
19524            });
19525        }
19526
19527        if let Some(project) = self.project.clone() {
19528            self.save(
19529                SaveOptions {
19530                    format: true,
19531                    autosave: false,
19532                },
19533                project,
19534                window,
19535                cx,
19536            )
19537            .detach_and_log_err(cx);
19538        }
19539    }
19540
19541    pub(crate) fn apply_selected_diff_hunks(
19542        &mut self,
19543        _: &ApplyDiffHunk,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19548        let snapshot = self.snapshot(window, cx);
19549        let hunks = snapshot.hunks_for_ranges(
19550            self.selections
19551                .all(&snapshot.display_snapshot)
19552                .into_iter()
19553                .map(|selection| selection.range()),
19554        );
19555        let mut ranges_by_buffer = HashMap::default();
19556        self.transact(window, cx, |editor, _window, cx| {
19557            for hunk in hunks {
19558                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19559                    ranges_by_buffer
19560                        .entry(buffer.clone())
19561                        .or_insert_with(Vec::new)
19562                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19563                }
19564            }
19565
19566            for (buffer, ranges) in ranges_by_buffer {
19567                buffer.update(cx, |buffer, cx| {
19568                    buffer.merge_into_base(ranges, cx);
19569                });
19570            }
19571        });
19572
19573        if let Some(project) = self.project.clone() {
19574            self.save(
19575                SaveOptions {
19576                    format: true,
19577                    autosave: false,
19578                },
19579                project,
19580                window,
19581                cx,
19582            )
19583            .detach_and_log_err(cx);
19584        }
19585    }
19586
19587    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19588        if hovered != self.gutter_hovered {
19589            self.gutter_hovered = hovered;
19590            cx.notify();
19591        }
19592    }
19593
19594    pub fn insert_blocks(
19595        &mut self,
19596        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19597        autoscroll: Option<Autoscroll>,
19598        cx: &mut Context<Self>,
19599    ) -> Vec<CustomBlockId> {
19600        let blocks = self
19601            .display_map
19602            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19603        if let Some(autoscroll) = autoscroll {
19604            self.request_autoscroll(autoscroll, cx);
19605        }
19606        cx.notify();
19607        blocks
19608    }
19609
19610    pub fn resize_blocks(
19611        &mut self,
19612        heights: HashMap<CustomBlockId, u32>,
19613        autoscroll: Option<Autoscroll>,
19614        cx: &mut Context<Self>,
19615    ) {
19616        self.display_map
19617            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19618        if let Some(autoscroll) = autoscroll {
19619            self.request_autoscroll(autoscroll, cx);
19620        }
19621        cx.notify();
19622    }
19623
19624    pub fn replace_blocks(
19625        &mut self,
19626        renderers: HashMap<CustomBlockId, RenderBlock>,
19627        autoscroll: Option<Autoscroll>,
19628        cx: &mut Context<Self>,
19629    ) {
19630        self.display_map
19631            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19632        if let Some(autoscroll) = autoscroll {
19633            self.request_autoscroll(autoscroll, cx);
19634        }
19635        cx.notify();
19636    }
19637
19638    pub fn remove_blocks(
19639        &mut self,
19640        block_ids: HashSet<CustomBlockId>,
19641        autoscroll: Option<Autoscroll>,
19642        cx: &mut Context<Self>,
19643    ) {
19644        self.display_map.update(cx, |display_map, cx| {
19645            display_map.remove_blocks(block_ids, cx)
19646        });
19647        if let Some(autoscroll) = autoscroll {
19648            self.request_autoscroll(autoscroll, cx);
19649        }
19650        cx.notify();
19651    }
19652
19653    pub fn row_for_block(
19654        &self,
19655        block_id: CustomBlockId,
19656        cx: &mut Context<Self>,
19657    ) -> Option<DisplayRow> {
19658        self.display_map
19659            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19660    }
19661
19662    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19663        self.focused_block = Some(focused_block);
19664    }
19665
19666    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19667        self.focused_block.take()
19668    }
19669
19670    pub fn insert_creases(
19671        &mut self,
19672        creases: impl IntoIterator<Item = Crease<Anchor>>,
19673        cx: &mut Context<Self>,
19674    ) -> Vec<CreaseId> {
19675        self.display_map
19676            .update(cx, |map, cx| map.insert_creases(creases, cx))
19677    }
19678
19679    pub fn remove_creases(
19680        &mut self,
19681        ids: impl IntoIterator<Item = CreaseId>,
19682        cx: &mut Context<Self>,
19683    ) -> Vec<(CreaseId, Range<Anchor>)> {
19684        self.display_map
19685            .update(cx, |map, cx| map.remove_creases(ids, cx))
19686    }
19687
19688    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19689        self.display_map
19690            .update(cx, |map, cx| map.snapshot(cx))
19691            .longest_row()
19692    }
19693
19694    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19695        self.display_map
19696            .update(cx, |map, cx| map.snapshot(cx))
19697            .max_point()
19698    }
19699
19700    pub fn text(&self, cx: &App) -> String {
19701        self.buffer.read(cx).read(cx).text()
19702    }
19703
19704    pub fn is_empty(&self, cx: &App) -> bool {
19705        self.buffer.read(cx).read(cx).is_empty()
19706    }
19707
19708    pub fn text_option(&self, cx: &App) -> Option<String> {
19709        let text = self.text(cx);
19710        let text = text.trim();
19711
19712        if text.is_empty() {
19713            return None;
19714        }
19715
19716        Some(text.to_string())
19717    }
19718
19719    pub fn set_text(
19720        &mut self,
19721        text: impl Into<Arc<str>>,
19722        window: &mut Window,
19723        cx: &mut Context<Self>,
19724    ) {
19725        self.transact(window, cx, |this, _, cx| {
19726            this.buffer
19727                .read(cx)
19728                .as_singleton()
19729                .expect("you can only call set_text on editors for singleton buffers")
19730                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19731        });
19732    }
19733
19734    pub fn display_text(&self, cx: &mut App) -> String {
19735        self.display_map
19736            .update(cx, |map, cx| map.snapshot(cx))
19737            .text()
19738    }
19739
19740    fn create_minimap(
19741        &self,
19742        minimap_settings: MinimapSettings,
19743        window: &mut Window,
19744        cx: &mut Context<Self>,
19745    ) -> Option<Entity<Self>> {
19746        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19747            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19748    }
19749
19750    fn initialize_new_minimap(
19751        &self,
19752        minimap_settings: MinimapSettings,
19753        window: &mut Window,
19754        cx: &mut Context<Self>,
19755    ) -> Entity<Self> {
19756        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19757
19758        let mut minimap = Editor::new_internal(
19759            EditorMode::Minimap {
19760                parent: cx.weak_entity(),
19761            },
19762            self.buffer.clone(),
19763            None,
19764            Some(self.display_map.clone()),
19765            window,
19766            cx,
19767        );
19768        minimap.scroll_manager.clone_state(&self.scroll_manager);
19769        minimap.set_text_style_refinement(TextStyleRefinement {
19770            font_size: Some(MINIMAP_FONT_SIZE),
19771            font_weight: Some(MINIMAP_FONT_WEIGHT),
19772            ..Default::default()
19773        });
19774        minimap.update_minimap_configuration(minimap_settings, cx);
19775        cx.new(|_| minimap)
19776    }
19777
19778    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19779        let current_line_highlight = minimap_settings
19780            .current_line_highlight
19781            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19782        self.set_current_line_highlight(Some(current_line_highlight));
19783    }
19784
19785    pub fn minimap(&self) -> Option<&Entity<Self>> {
19786        self.minimap
19787            .as_ref()
19788            .filter(|_| self.minimap_visibility.visible())
19789    }
19790
19791    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19792        let mut wrap_guides = smallvec![];
19793
19794        if self.show_wrap_guides == Some(false) {
19795            return wrap_guides;
19796        }
19797
19798        let settings = self.buffer.read(cx).language_settings(cx);
19799        if settings.show_wrap_guides {
19800            match self.soft_wrap_mode(cx) {
19801                SoftWrap::Column(soft_wrap) => {
19802                    wrap_guides.push((soft_wrap as usize, true));
19803                }
19804                SoftWrap::Bounded(soft_wrap) => {
19805                    wrap_guides.push((soft_wrap as usize, true));
19806                }
19807                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19808            }
19809            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19810        }
19811
19812        wrap_guides
19813    }
19814
19815    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19816        let settings = self.buffer.read(cx).language_settings(cx);
19817        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19818        match mode {
19819            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19820                SoftWrap::None
19821            }
19822            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19823            language_settings::SoftWrap::PreferredLineLength => {
19824                SoftWrap::Column(settings.preferred_line_length)
19825            }
19826            language_settings::SoftWrap::Bounded => {
19827                SoftWrap::Bounded(settings.preferred_line_length)
19828            }
19829        }
19830    }
19831
19832    pub fn set_soft_wrap_mode(
19833        &mut self,
19834        mode: language_settings::SoftWrap,
19835
19836        cx: &mut Context<Self>,
19837    ) {
19838        self.soft_wrap_mode_override = Some(mode);
19839        cx.notify();
19840    }
19841
19842    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19843        self.hard_wrap = hard_wrap;
19844        cx.notify();
19845    }
19846
19847    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19848        self.text_style_refinement = Some(style);
19849    }
19850
19851    /// called by the Element so we know what style we were most recently rendered with.
19852    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19853        // We intentionally do not inform the display map about the minimap style
19854        // so that wrapping is not recalculated and stays consistent for the editor
19855        // and its linked minimap.
19856        if !self.mode.is_minimap() {
19857            let font = style.text.font();
19858            let font_size = style.text.font_size.to_pixels(window.rem_size());
19859            let display_map = self
19860                .placeholder_display_map
19861                .as_ref()
19862                .filter(|_| self.is_empty(cx))
19863                .unwrap_or(&self.display_map);
19864
19865            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19866        }
19867        self.style = Some(style);
19868    }
19869
19870    pub fn style(&self) -> Option<&EditorStyle> {
19871        self.style.as_ref()
19872    }
19873
19874    // Called by the element. This method is not designed to be called outside of the editor
19875    // element's layout code because it does not notify when rewrapping is computed synchronously.
19876    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19877        if self.is_empty(cx) {
19878            self.placeholder_display_map
19879                .as_ref()
19880                .map_or(false, |display_map| {
19881                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19882                })
19883        } else {
19884            self.display_map
19885                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19886        }
19887    }
19888
19889    pub fn set_soft_wrap(&mut self) {
19890        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19891    }
19892
19893    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19894        if self.soft_wrap_mode_override.is_some() {
19895            self.soft_wrap_mode_override.take();
19896        } else {
19897            let soft_wrap = match self.soft_wrap_mode(cx) {
19898                SoftWrap::GitDiff => return,
19899                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19900                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19901                    language_settings::SoftWrap::None
19902                }
19903            };
19904            self.soft_wrap_mode_override = Some(soft_wrap);
19905        }
19906        cx.notify();
19907    }
19908
19909    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19910        let Some(workspace) = self.workspace() else {
19911            return;
19912        };
19913        let fs = workspace.read(cx).app_state().fs.clone();
19914        let current_show = TabBarSettings::get_global(cx).show;
19915        update_settings_file(fs, cx, move |setting, _| {
19916            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19917        });
19918    }
19919
19920    pub fn toggle_indent_guides(
19921        &mut self,
19922        _: &ToggleIndentGuides,
19923        _: &mut Window,
19924        cx: &mut Context<Self>,
19925    ) {
19926        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19927            self.buffer
19928                .read(cx)
19929                .language_settings(cx)
19930                .indent_guides
19931                .enabled
19932        });
19933        self.show_indent_guides = Some(!currently_enabled);
19934        cx.notify();
19935    }
19936
19937    fn should_show_indent_guides(&self) -> Option<bool> {
19938        self.show_indent_guides
19939    }
19940
19941    pub fn toggle_line_numbers(
19942        &mut self,
19943        _: &ToggleLineNumbers,
19944        _: &mut Window,
19945        cx: &mut Context<Self>,
19946    ) {
19947        let mut editor_settings = EditorSettings::get_global(cx).clone();
19948        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19949        EditorSettings::override_global(editor_settings, cx);
19950    }
19951
19952    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19953        if let Some(show_line_numbers) = self.show_line_numbers {
19954            return show_line_numbers;
19955        }
19956        EditorSettings::get_global(cx).gutter.line_numbers
19957    }
19958
19959    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19960        match (
19961            self.use_relative_line_numbers,
19962            EditorSettings::get_global(cx).relative_line_numbers,
19963        ) {
19964            (None, setting) => setting,
19965            (Some(false), _) => RelativeLineNumbers::Disabled,
19966            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19967            (Some(true), _) => RelativeLineNumbers::Enabled,
19968        }
19969    }
19970
19971    pub fn toggle_relative_line_numbers(
19972        &mut self,
19973        _: &ToggleRelativeLineNumbers,
19974        _: &mut Window,
19975        cx: &mut Context<Self>,
19976    ) {
19977        let is_relative = self.relative_line_numbers(cx);
19978        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19979    }
19980
19981    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19982        self.use_relative_line_numbers = is_relative;
19983        cx.notify();
19984    }
19985
19986    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19987        self.show_gutter = show_gutter;
19988        cx.notify();
19989    }
19990
19991    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19992        self.show_scrollbars = ScrollbarAxes {
19993            horizontal: show,
19994            vertical: show,
19995        };
19996        cx.notify();
19997    }
19998
19999    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20000        self.show_scrollbars.vertical = show;
20001        cx.notify();
20002    }
20003
20004    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20005        self.show_scrollbars.horizontal = show;
20006        cx.notify();
20007    }
20008
20009    pub fn set_minimap_visibility(
20010        &mut self,
20011        minimap_visibility: MinimapVisibility,
20012        window: &mut Window,
20013        cx: &mut Context<Self>,
20014    ) {
20015        if self.minimap_visibility != minimap_visibility {
20016            if minimap_visibility.visible() && self.minimap.is_none() {
20017                let minimap_settings = EditorSettings::get_global(cx).minimap;
20018                self.minimap =
20019                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20020            }
20021            self.minimap_visibility = minimap_visibility;
20022            cx.notify();
20023        }
20024    }
20025
20026    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20027        self.set_show_scrollbars(false, cx);
20028        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20029    }
20030
20031    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20032        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20033    }
20034
20035    /// Normally the text in full mode and auto height editors is padded on the
20036    /// left side by roughly half a character width for improved hit testing.
20037    ///
20038    /// Use this method to disable this for cases where this is not wanted (e.g.
20039    /// if you want to align the editor text with some other text above or below)
20040    /// or if you want to add this padding to single-line editors.
20041    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20042        self.offset_content = offset_content;
20043        cx.notify();
20044    }
20045
20046    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20047        self.show_line_numbers = Some(show_line_numbers);
20048        cx.notify();
20049    }
20050
20051    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20052        self.disable_expand_excerpt_buttons = true;
20053        cx.notify();
20054    }
20055
20056    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20057        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20058        cx.notify();
20059    }
20060
20061    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20062        self.show_code_actions = Some(show_code_actions);
20063        cx.notify();
20064    }
20065
20066    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20067        self.show_runnables = Some(show_runnables);
20068        cx.notify();
20069    }
20070
20071    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20072        self.show_breakpoints = Some(show_breakpoints);
20073        cx.notify();
20074    }
20075
20076    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20077        if self.display_map.read(cx).masked != masked {
20078            self.display_map.update(cx, |map, _| map.masked = masked);
20079        }
20080        cx.notify()
20081    }
20082
20083    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20084        self.show_wrap_guides = Some(show_wrap_guides);
20085        cx.notify();
20086    }
20087
20088    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20089        self.show_indent_guides = Some(show_indent_guides);
20090        cx.notify();
20091    }
20092
20093    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20094        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20095            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20096                && let Some(dir) = file.abs_path(cx).parent()
20097            {
20098                return Some(dir.to_owned());
20099            }
20100        }
20101
20102        None
20103    }
20104
20105    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20106        self.active_excerpt(cx)?
20107            .1
20108            .read(cx)
20109            .file()
20110            .and_then(|f| f.as_local())
20111    }
20112
20113    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20114        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20115            let buffer = buffer.read(cx);
20116            if let Some(project_path) = buffer.project_path(cx) {
20117                let project = self.project()?.read(cx);
20118                project.absolute_path(&project_path, cx)
20119            } else {
20120                buffer
20121                    .file()
20122                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20123            }
20124        })
20125    }
20126
20127    pub fn reveal_in_finder(
20128        &mut self,
20129        _: &RevealInFileManager,
20130        _window: &mut Window,
20131        cx: &mut Context<Self>,
20132    ) {
20133        if let Some(target) = self.target_file(cx) {
20134            cx.reveal_path(&target.abs_path(cx));
20135        }
20136    }
20137
20138    pub fn copy_path(
20139        &mut self,
20140        _: &zed_actions::workspace::CopyPath,
20141        _window: &mut Window,
20142        cx: &mut Context<Self>,
20143    ) {
20144        if let Some(path) = self.target_file_abs_path(cx)
20145            && let Some(path) = path.to_str()
20146        {
20147            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20148        } else {
20149            cx.propagate();
20150        }
20151    }
20152
20153    pub fn copy_relative_path(
20154        &mut self,
20155        _: &zed_actions::workspace::CopyRelativePath,
20156        _window: &mut Window,
20157        cx: &mut Context<Self>,
20158    ) {
20159        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20160            let project = self.project()?.read(cx);
20161            let path = buffer.read(cx).file()?.path();
20162            let path = path.display(project.path_style(cx));
20163            Some(path)
20164        }) {
20165            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20166        } else {
20167            cx.propagate();
20168        }
20169    }
20170
20171    /// Returns the project path for the editor's buffer, if any buffer is
20172    /// opened in the editor.
20173    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20174        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20175            buffer.read(cx).project_path(cx)
20176        } else {
20177            None
20178        }
20179    }
20180
20181    // Returns true if the editor handled a go-to-line request
20182    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20183        maybe!({
20184            let breakpoint_store = self.breakpoint_store.as_ref()?;
20185
20186            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20187            else {
20188                self.clear_row_highlights::<ActiveDebugLine>();
20189                return None;
20190            };
20191
20192            let position = active_stack_frame.position;
20193            let buffer_id = position.buffer_id?;
20194            let snapshot = self
20195                .project
20196                .as_ref()?
20197                .read(cx)
20198                .buffer_for_id(buffer_id, cx)?
20199                .read(cx)
20200                .snapshot();
20201
20202            let mut handled = false;
20203            for (id, ExcerptRange { context, .. }) in
20204                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20205            {
20206                if context.start.cmp(&position, &snapshot).is_ge()
20207                    || context.end.cmp(&position, &snapshot).is_lt()
20208                {
20209                    continue;
20210                }
20211                let snapshot = self.buffer.read(cx).snapshot(cx);
20212                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20213
20214                handled = true;
20215                self.clear_row_highlights::<ActiveDebugLine>();
20216
20217                self.go_to_line::<ActiveDebugLine>(
20218                    multibuffer_anchor,
20219                    Some(cx.theme().colors().editor_debugger_active_line_background),
20220                    window,
20221                    cx,
20222                );
20223
20224                cx.notify();
20225            }
20226
20227            handled.then_some(())
20228        })
20229        .is_some()
20230    }
20231
20232    pub fn copy_file_name_without_extension(
20233        &mut self,
20234        _: &CopyFileNameWithoutExtension,
20235        _: &mut Window,
20236        cx: &mut Context<Self>,
20237    ) {
20238        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20239            let file = buffer.read(cx).file()?;
20240            file.path().file_stem()
20241        }) {
20242            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20243        }
20244    }
20245
20246    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20247        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20248            let file = buffer.read(cx).file()?;
20249            Some(file.file_name(cx))
20250        }) {
20251            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20252        }
20253    }
20254
20255    pub fn toggle_git_blame(
20256        &mut self,
20257        _: &::git::Blame,
20258        window: &mut Window,
20259        cx: &mut Context<Self>,
20260    ) {
20261        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20262
20263        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20264            self.start_git_blame(true, window, cx);
20265        }
20266
20267        cx.notify();
20268    }
20269
20270    pub fn toggle_git_blame_inline(
20271        &mut self,
20272        _: &ToggleGitBlameInline,
20273        window: &mut Window,
20274        cx: &mut Context<Self>,
20275    ) {
20276        self.toggle_git_blame_inline_internal(true, window, cx);
20277        cx.notify();
20278    }
20279
20280    pub fn open_git_blame_commit(
20281        &mut self,
20282        _: &OpenGitBlameCommit,
20283        window: &mut Window,
20284        cx: &mut Context<Self>,
20285    ) {
20286        self.open_git_blame_commit_internal(window, cx);
20287    }
20288
20289    fn open_git_blame_commit_internal(
20290        &mut self,
20291        window: &mut Window,
20292        cx: &mut Context<Self>,
20293    ) -> Option<()> {
20294        let blame = self.blame.as_ref()?;
20295        let snapshot = self.snapshot(window, cx);
20296        let cursor = self
20297            .selections
20298            .newest::<Point>(&snapshot.display_snapshot)
20299            .head();
20300        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20301        let (_, blame_entry) = blame
20302            .update(cx, |blame, cx| {
20303                blame
20304                    .blame_for_rows(
20305                        &[RowInfo {
20306                            buffer_id: Some(buffer.remote_id()),
20307                            buffer_row: Some(point.row),
20308                            ..Default::default()
20309                        }],
20310                        cx,
20311                    )
20312                    .next()
20313            })
20314            .flatten()?;
20315        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20316        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20317        let workspace = self.workspace()?.downgrade();
20318        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20319        None
20320    }
20321
20322    pub fn git_blame_inline_enabled(&self) -> bool {
20323        self.git_blame_inline_enabled
20324    }
20325
20326    pub fn toggle_selection_menu(
20327        &mut self,
20328        _: &ToggleSelectionMenu,
20329        _: &mut Window,
20330        cx: &mut Context<Self>,
20331    ) {
20332        self.show_selection_menu = self
20333            .show_selection_menu
20334            .map(|show_selections_menu| !show_selections_menu)
20335            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20336
20337        cx.notify();
20338    }
20339
20340    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20341        self.show_selection_menu
20342            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20343    }
20344
20345    fn start_git_blame(
20346        &mut self,
20347        user_triggered: bool,
20348        window: &mut Window,
20349        cx: &mut Context<Self>,
20350    ) {
20351        if let Some(project) = self.project() {
20352            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20353                && buffer.read(cx).file().is_none()
20354            {
20355                return;
20356            }
20357
20358            let focused = self.focus_handle(cx).contains_focused(window, cx);
20359
20360            let project = project.clone();
20361            let blame = cx
20362                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20363            self.blame_subscription =
20364                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20365            self.blame = Some(blame);
20366        }
20367    }
20368
20369    fn toggle_git_blame_inline_internal(
20370        &mut self,
20371        user_triggered: bool,
20372        window: &mut Window,
20373        cx: &mut Context<Self>,
20374    ) {
20375        if self.git_blame_inline_enabled {
20376            self.git_blame_inline_enabled = false;
20377            self.show_git_blame_inline = false;
20378            self.show_git_blame_inline_delay_task.take();
20379        } else {
20380            self.git_blame_inline_enabled = true;
20381            self.start_git_blame_inline(user_triggered, window, cx);
20382        }
20383
20384        cx.notify();
20385    }
20386
20387    fn start_git_blame_inline(
20388        &mut self,
20389        user_triggered: bool,
20390        window: &mut Window,
20391        cx: &mut Context<Self>,
20392    ) {
20393        self.start_git_blame(user_triggered, window, cx);
20394
20395        if ProjectSettings::get_global(cx)
20396            .git
20397            .inline_blame_delay()
20398            .is_some()
20399        {
20400            self.start_inline_blame_timer(window, cx);
20401        } else {
20402            self.show_git_blame_inline = true
20403        }
20404    }
20405
20406    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20407        self.blame.as_ref()
20408    }
20409
20410    pub fn show_git_blame_gutter(&self) -> bool {
20411        self.show_git_blame_gutter
20412    }
20413
20414    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20415        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20416    }
20417
20418    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20419        self.show_git_blame_inline
20420            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20421            && !self.newest_selection_head_on_empty_line(cx)
20422            && self.has_blame_entries(cx)
20423    }
20424
20425    fn has_blame_entries(&self, cx: &App) -> bool {
20426        self.blame()
20427            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20428    }
20429
20430    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20431        let cursor_anchor = self.selections.newest_anchor().head();
20432
20433        let snapshot = self.buffer.read(cx).snapshot(cx);
20434        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20435
20436        snapshot.line_len(buffer_row) == 0
20437    }
20438
20439    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20440        let buffer_and_selection = maybe!({
20441            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20442            let selection_range = selection.range();
20443
20444            let multi_buffer = self.buffer().read(cx);
20445            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20446            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20447
20448            let (buffer, range, _) = if selection.reversed {
20449                buffer_ranges.first()
20450            } else {
20451                buffer_ranges.last()
20452            }?;
20453
20454            let selection = text::ToPoint::to_point(&range.start, buffer).row
20455                ..text::ToPoint::to_point(&range.end, buffer).row;
20456            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20457        });
20458
20459        let Some((buffer, selection)) = buffer_and_selection else {
20460            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20461        };
20462
20463        let Some(project) = self.project() else {
20464            return Task::ready(Err(anyhow!("editor does not have project")));
20465        };
20466
20467        project.update(cx, |project, cx| {
20468            project.get_permalink_to_line(&buffer, selection, cx)
20469        })
20470    }
20471
20472    pub fn copy_permalink_to_line(
20473        &mut self,
20474        _: &CopyPermalinkToLine,
20475        window: &mut Window,
20476        cx: &mut Context<Self>,
20477    ) {
20478        let permalink_task = self.get_permalink_to_line(cx);
20479        let workspace = self.workspace();
20480
20481        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20482            Ok(permalink) => {
20483                cx.update(|_, cx| {
20484                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20485                })
20486                .ok();
20487            }
20488            Err(err) => {
20489                let message = format!("Failed to copy permalink: {err}");
20490
20491                anyhow::Result::<()>::Err(err).log_err();
20492
20493                if let Some(workspace) = workspace {
20494                    workspace
20495                        .update_in(cx, |workspace, _, cx| {
20496                            struct CopyPermalinkToLine;
20497
20498                            workspace.show_toast(
20499                                Toast::new(
20500                                    NotificationId::unique::<CopyPermalinkToLine>(),
20501                                    message,
20502                                ),
20503                                cx,
20504                            )
20505                        })
20506                        .ok();
20507                }
20508            }
20509        })
20510        .detach();
20511    }
20512
20513    pub fn copy_file_location(
20514        &mut self,
20515        _: &CopyFileLocation,
20516        _: &mut Window,
20517        cx: &mut Context<Self>,
20518    ) {
20519        let selection = self
20520            .selections
20521            .newest::<Point>(&self.display_snapshot(cx))
20522            .start
20523            .row
20524            + 1;
20525        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20526            let project = self.project()?.read(cx);
20527            let file = buffer.read(cx).file()?;
20528            let path = file.path().display(project.path_style(cx));
20529
20530            Some(format!("{path}:{selection}"))
20531        }) {
20532            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20533        }
20534    }
20535
20536    pub fn open_permalink_to_line(
20537        &mut self,
20538        _: &OpenPermalinkToLine,
20539        window: &mut Window,
20540        cx: &mut Context<Self>,
20541    ) {
20542        let permalink_task = self.get_permalink_to_line(cx);
20543        let workspace = self.workspace();
20544
20545        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20546            Ok(permalink) => {
20547                cx.update(|_, cx| {
20548                    cx.open_url(permalink.as_ref());
20549                })
20550                .ok();
20551            }
20552            Err(err) => {
20553                let message = format!("Failed to open permalink: {err}");
20554
20555                anyhow::Result::<()>::Err(err).log_err();
20556
20557                if let Some(workspace) = workspace {
20558                    workspace
20559                        .update(cx, |workspace, cx| {
20560                            struct OpenPermalinkToLine;
20561
20562                            workspace.show_toast(
20563                                Toast::new(
20564                                    NotificationId::unique::<OpenPermalinkToLine>(),
20565                                    message,
20566                                ),
20567                                cx,
20568                            )
20569                        })
20570                        .ok();
20571                }
20572            }
20573        })
20574        .detach();
20575    }
20576
20577    pub fn insert_uuid_v4(
20578        &mut self,
20579        _: &InsertUuidV4,
20580        window: &mut Window,
20581        cx: &mut Context<Self>,
20582    ) {
20583        self.insert_uuid(UuidVersion::V4, window, cx);
20584    }
20585
20586    pub fn insert_uuid_v7(
20587        &mut self,
20588        _: &InsertUuidV7,
20589        window: &mut Window,
20590        cx: &mut Context<Self>,
20591    ) {
20592        self.insert_uuid(UuidVersion::V7, window, cx);
20593    }
20594
20595    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20597        self.transact(window, cx, |this, window, cx| {
20598            let edits = this
20599                .selections
20600                .all::<Point>(&this.display_snapshot(cx))
20601                .into_iter()
20602                .map(|selection| {
20603                    let uuid = match version {
20604                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20605                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20606                    };
20607
20608                    (selection.range(), uuid.to_string())
20609                });
20610            this.edit(edits, cx);
20611            this.refresh_edit_prediction(true, false, window, cx);
20612        });
20613    }
20614
20615    pub fn open_selections_in_multibuffer(
20616        &mut self,
20617        _: &OpenSelectionsInMultibuffer,
20618        window: &mut Window,
20619        cx: &mut Context<Self>,
20620    ) {
20621        let multibuffer = self.buffer.read(cx);
20622
20623        let Some(buffer) = multibuffer.as_singleton() else {
20624            return;
20625        };
20626
20627        let Some(workspace) = self.workspace() else {
20628            return;
20629        };
20630
20631        let title = multibuffer.title(cx).to_string();
20632
20633        let locations = self
20634            .selections
20635            .all_anchors(&self.display_snapshot(cx))
20636            .iter()
20637            .map(|selection| {
20638                (
20639                    buffer.clone(),
20640                    (selection.start.text_anchor..selection.end.text_anchor)
20641                        .to_point(buffer.read(cx)),
20642                )
20643            })
20644            .into_group_map();
20645
20646        cx.spawn_in(window, async move |_, cx| {
20647            workspace.update_in(cx, |workspace, window, cx| {
20648                Self::open_locations_in_multibuffer(
20649                    workspace,
20650                    locations,
20651                    format!("Selections for '{title}'"),
20652                    false,
20653                    MultibufferSelectionMode::All,
20654                    window,
20655                    cx,
20656                );
20657            })
20658        })
20659        .detach();
20660    }
20661
20662    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20663    /// last highlight added will be used.
20664    ///
20665    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20666    pub fn highlight_rows<T: 'static>(
20667        &mut self,
20668        range: Range<Anchor>,
20669        color: Hsla,
20670        options: RowHighlightOptions,
20671        cx: &mut Context<Self>,
20672    ) {
20673        let snapshot = self.buffer().read(cx).snapshot(cx);
20674        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20675        let ix = row_highlights.binary_search_by(|highlight| {
20676            Ordering::Equal
20677                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20678                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20679        });
20680
20681        if let Err(mut ix) = ix {
20682            let index = post_inc(&mut self.highlight_order);
20683
20684            // If this range intersects with the preceding highlight, then merge it with
20685            // the preceding highlight. Otherwise insert a new highlight.
20686            let mut merged = false;
20687            if ix > 0 {
20688                let prev_highlight = &mut row_highlights[ix - 1];
20689                if prev_highlight
20690                    .range
20691                    .end
20692                    .cmp(&range.start, &snapshot)
20693                    .is_ge()
20694                {
20695                    ix -= 1;
20696                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20697                        prev_highlight.range.end = range.end;
20698                    }
20699                    merged = true;
20700                    prev_highlight.index = index;
20701                    prev_highlight.color = color;
20702                    prev_highlight.options = options;
20703                }
20704            }
20705
20706            if !merged {
20707                row_highlights.insert(
20708                    ix,
20709                    RowHighlight {
20710                        range,
20711                        index,
20712                        color,
20713                        options,
20714                        type_id: TypeId::of::<T>(),
20715                    },
20716                );
20717            }
20718
20719            // If any of the following highlights intersect with this one, merge them.
20720            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20721                let highlight = &row_highlights[ix];
20722                if next_highlight
20723                    .range
20724                    .start
20725                    .cmp(&highlight.range.end, &snapshot)
20726                    .is_le()
20727                {
20728                    if next_highlight
20729                        .range
20730                        .end
20731                        .cmp(&highlight.range.end, &snapshot)
20732                        .is_gt()
20733                    {
20734                        row_highlights[ix].range.end = next_highlight.range.end;
20735                    }
20736                    row_highlights.remove(ix + 1);
20737                } else {
20738                    break;
20739                }
20740            }
20741        }
20742    }
20743
20744    /// Remove any highlighted row ranges of the given type that intersect the
20745    /// given ranges.
20746    pub fn remove_highlighted_rows<T: 'static>(
20747        &mut self,
20748        ranges_to_remove: Vec<Range<Anchor>>,
20749        cx: &mut Context<Self>,
20750    ) {
20751        let snapshot = self.buffer().read(cx).snapshot(cx);
20752        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20753        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20754        row_highlights.retain(|highlight| {
20755            while let Some(range_to_remove) = ranges_to_remove.peek() {
20756                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20757                    Ordering::Less | Ordering::Equal => {
20758                        ranges_to_remove.next();
20759                    }
20760                    Ordering::Greater => {
20761                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20762                            Ordering::Less | Ordering::Equal => {
20763                                return false;
20764                            }
20765                            Ordering::Greater => break,
20766                        }
20767                    }
20768                }
20769            }
20770
20771            true
20772        })
20773    }
20774
20775    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20776    pub fn clear_row_highlights<T: 'static>(&mut self) {
20777        self.highlighted_rows.remove(&TypeId::of::<T>());
20778    }
20779
20780    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20781    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20782        self.highlighted_rows
20783            .get(&TypeId::of::<T>())
20784            .map_or(&[] as &[_], |vec| vec.as_slice())
20785            .iter()
20786            .map(|highlight| (highlight.range.clone(), highlight.color))
20787    }
20788
20789    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20790    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20791    /// Allows to ignore certain kinds of highlights.
20792    pub fn highlighted_display_rows(
20793        &self,
20794        window: &mut Window,
20795        cx: &mut App,
20796    ) -> BTreeMap<DisplayRow, LineHighlight> {
20797        let snapshot = self.snapshot(window, cx);
20798        let mut used_highlight_orders = HashMap::default();
20799        self.highlighted_rows
20800            .iter()
20801            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20802            .fold(
20803                BTreeMap::<DisplayRow, LineHighlight>::new(),
20804                |mut unique_rows, highlight| {
20805                    let start = highlight.range.start.to_display_point(&snapshot);
20806                    let end = highlight.range.end.to_display_point(&snapshot);
20807                    let start_row = start.row().0;
20808                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20809                    {
20810                        end.row().0.saturating_sub(1)
20811                    } else {
20812                        end.row().0
20813                    };
20814                    for row in start_row..=end_row {
20815                        let used_index =
20816                            used_highlight_orders.entry(row).or_insert(highlight.index);
20817                        if highlight.index >= *used_index {
20818                            *used_index = highlight.index;
20819                            unique_rows.insert(
20820                                DisplayRow(row),
20821                                LineHighlight {
20822                                    include_gutter: highlight.options.include_gutter,
20823                                    border: None,
20824                                    background: highlight.color.into(),
20825                                    type_id: Some(highlight.type_id),
20826                                },
20827                            );
20828                        }
20829                    }
20830                    unique_rows
20831                },
20832            )
20833    }
20834
20835    pub fn highlighted_display_row_for_autoscroll(
20836        &self,
20837        snapshot: &DisplaySnapshot,
20838    ) -> Option<DisplayRow> {
20839        self.highlighted_rows
20840            .values()
20841            .flat_map(|highlighted_rows| highlighted_rows.iter())
20842            .filter_map(|highlight| {
20843                if highlight.options.autoscroll {
20844                    Some(highlight.range.start.to_display_point(snapshot).row())
20845                } else {
20846                    None
20847                }
20848            })
20849            .min()
20850    }
20851
20852    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20853        self.highlight_background::<SearchWithinRange>(
20854            ranges,
20855            |colors| colors.colors().editor_document_highlight_read_background,
20856            cx,
20857        )
20858    }
20859
20860    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20861        self.breadcrumb_header = Some(new_header);
20862    }
20863
20864    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20865        self.clear_background_highlights::<SearchWithinRange>(cx);
20866    }
20867
20868    pub fn highlight_background<T: 'static>(
20869        &mut self,
20870        ranges: &[Range<Anchor>],
20871        color_fetcher: fn(&Theme) -> Hsla,
20872        cx: &mut Context<Self>,
20873    ) {
20874        self.background_highlights.insert(
20875            HighlightKey::Type(TypeId::of::<T>()),
20876            (color_fetcher, Arc::from(ranges)),
20877        );
20878        self.scrollbar_marker_state.dirty = true;
20879        cx.notify();
20880    }
20881
20882    pub fn highlight_background_key<T: 'static>(
20883        &mut self,
20884        key: usize,
20885        ranges: &[Range<Anchor>],
20886        color_fetcher: fn(&Theme) -> Hsla,
20887        cx: &mut Context<Self>,
20888    ) {
20889        self.background_highlights.insert(
20890            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20891            (color_fetcher, Arc::from(ranges)),
20892        );
20893        self.scrollbar_marker_state.dirty = true;
20894        cx.notify();
20895    }
20896
20897    pub fn clear_background_highlights<T: 'static>(
20898        &mut self,
20899        cx: &mut Context<Self>,
20900    ) -> Option<BackgroundHighlight> {
20901        let text_highlights = self
20902            .background_highlights
20903            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20904        if !text_highlights.1.is_empty() {
20905            self.scrollbar_marker_state.dirty = true;
20906            cx.notify();
20907        }
20908        Some(text_highlights)
20909    }
20910
20911    pub fn highlight_gutter<T: 'static>(
20912        &mut self,
20913        ranges: impl Into<Vec<Range<Anchor>>>,
20914        color_fetcher: fn(&App) -> Hsla,
20915        cx: &mut Context<Self>,
20916    ) {
20917        self.gutter_highlights
20918            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20919        cx.notify();
20920    }
20921
20922    pub fn clear_gutter_highlights<T: 'static>(
20923        &mut self,
20924        cx: &mut Context<Self>,
20925    ) -> Option<GutterHighlight> {
20926        cx.notify();
20927        self.gutter_highlights.remove(&TypeId::of::<T>())
20928    }
20929
20930    pub fn insert_gutter_highlight<T: 'static>(
20931        &mut self,
20932        range: Range<Anchor>,
20933        color_fetcher: fn(&App) -> Hsla,
20934        cx: &mut Context<Self>,
20935    ) {
20936        let snapshot = self.buffer().read(cx).snapshot(cx);
20937        let mut highlights = self
20938            .gutter_highlights
20939            .remove(&TypeId::of::<T>())
20940            .map(|(_, highlights)| highlights)
20941            .unwrap_or_default();
20942        let ix = highlights.binary_search_by(|highlight| {
20943            Ordering::Equal
20944                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20945                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20946        });
20947        if let Err(ix) = ix {
20948            highlights.insert(ix, range);
20949        }
20950        self.gutter_highlights
20951            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20952    }
20953
20954    pub fn remove_gutter_highlights<T: 'static>(
20955        &mut self,
20956        ranges_to_remove: Vec<Range<Anchor>>,
20957        cx: &mut Context<Self>,
20958    ) {
20959        let snapshot = self.buffer().read(cx).snapshot(cx);
20960        let Some((color_fetcher, mut gutter_highlights)) =
20961            self.gutter_highlights.remove(&TypeId::of::<T>())
20962        else {
20963            return;
20964        };
20965        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20966        gutter_highlights.retain(|highlight| {
20967            while let Some(range_to_remove) = ranges_to_remove.peek() {
20968                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20969                    Ordering::Less | Ordering::Equal => {
20970                        ranges_to_remove.next();
20971                    }
20972                    Ordering::Greater => {
20973                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20974                            Ordering::Less | Ordering::Equal => {
20975                                return false;
20976                            }
20977                            Ordering::Greater => break,
20978                        }
20979                    }
20980                }
20981            }
20982
20983            true
20984        });
20985        self.gutter_highlights
20986            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20987    }
20988
20989    #[cfg(feature = "test-support")]
20990    pub fn all_text_highlights(
20991        &self,
20992        window: &mut Window,
20993        cx: &mut Context<Self>,
20994    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20995        let snapshot = self.snapshot(window, cx);
20996        self.display_map.update(cx, |display_map, _| {
20997            display_map
20998                .all_text_highlights()
20999                .map(|highlight| {
21000                    let (style, ranges) = highlight.as_ref();
21001                    (
21002                        *style,
21003                        ranges
21004                            .iter()
21005                            .map(|range| range.clone().to_display_points(&snapshot))
21006                            .collect(),
21007                    )
21008                })
21009                .collect()
21010        })
21011    }
21012
21013    #[cfg(feature = "test-support")]
21014    pub fn all_text_background_highlights(
21015        &self,
21016        window: &mut Window,
21017        cx: &mut Context<Self>,
21018    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21019        let snapshot = self.snapshot(window, cx);
21020        let buffer = &snapshot.buffer_snapshot();
21021        let start = buffer.anchor_before(MultiBufferOffset(0));
21022        let end = buffer.anchor_after(buffer.len());
21023        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21024    }
21025
21026    #[cfg(any(test, feature = "test-support"))]
21027    pub fn sorted_background_highlights_in_range(
21028        &self,
21029        search_range: Range<Anchor>,
21030        display_snapshot: &DisplaySnapshot,
21031        theme: &Theme,
21032    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21033        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21034        res.sort_by(|a, b| {
21035            a.0.start
21036                .cmp(&b.0.start)
21037                .then_with(|| a.0.end.cmp(&b.0.end))
21038                .then_with(|| a.1.cmp(&b.1))
21039        });
21040        res
21041    }
21042
21043    #[cfg(feature = "test-support")]
21044    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21045        let snapshot = self.buffer().read(cx).snapshot(cx);
21046
21047        let highlights = self
21048            .background_highlights
21049            .get(&HighlightKey::Type(TypeId::of::<
21050                items::BufferSearchHighlights,
21051            >()));
21052
21053        if let Some((_color, ranges)) = highlights {
21054            ranges
21055                .iter()
21056                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21057                .collect_vec()
21058        } else {
21059            vec![]
21060        }
21061    }
21062
21063    fn document_highlights_for_position<'a>(
21064        &'a self,
21065        position: Anchor,
21066        buffer: &'a MultiBufferSnapshot,
21067    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21068        let read_highlights = self
21069            .background_highlights
21070            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21071            .map(|h| &h.1);
21072        let write_highlights = self
21073            .background_highlights
21074            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21075            .map(|h| &h.1);
21076        let left_position = position.bias_left(buffer);
21077        let right_position = position.bias_right(buffer);
21078        read_highlights
21079            .into_iter()
21080            .chain(write_highlights)
21081            .flat_map(move |ranges| {
21082                let start_ix = match ranges.binary_search_by(|probe| {
21083                    let cmp = probe.end.cmp(&left_position, buffer);
21084                    if cmp.is_ge() {
21085                        Ordering::Greater
21086                    } else {
21087                        Ordering::Less
21088                    }
21089                }) {
21090                    Ok(i) | Err(i) => i,
21091                };
21092
21093                ranges[start_ix..]
21094                    .iter()
21095                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21096            })
21097    }
21098
21099    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21100        self.background_highlights
21101            .get(&HighlightKey::Type(TypeId::of::<T>()))
21102            .is_some_and(|(_, highlights)| !highlights.is_empty())
21103    }
21104
21105    /// Returns all background highlights for a given range.
21106    ///
21107    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21108    pub fn background_highlights_in_range(
21109        &self,
21110        search_range: Range<Anchor>,
21111        display_snapshot: &DisplaySnapshot,
21112        theme: &Theme,
21113    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21114        let mut results = Vec::new();
21115        for (color_fetcher, ranges) in self.background_highlights.values() {
21116            let color = color_fetcher(theme);
21117            let start_ix = match ranges.binary_search_by(|probe| {
21118                let cmp = probe
21119                    .end
21120                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21121                if cmp.is_gt() {
21122                    Ordering::Greater
21123                } else {
21124                    Ordering::Less
21125                }
21126            }) {
21127                Ok(i) | Err(i) => i,
21128            };
21129            for range in &ranges[start_ix..] {
21130                if range
21131                    .start
21132                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21133                    .is_ge()
21134                {
21135                    break;
21136                }
21137
21138                let start = range.start.to_display_point(display_snapshot);
21139                let end = range.end.to_display_point(display_snapshot);
21140                results.push((start..end, color))
21141            }
21142        }
21143        results
21144    }
21145
21146    pub fn gutter_highlights_in_range(
21147        &self,
21148        search_range: Range<Anchor>,
21149        display_snapshot: &DisplaySnapshot,
21150        cx: &App,
21151    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21152        let mut results = Vec::new();
21153        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21154            let color = color_fetcher(cx);
21155            let start_ix = match ranges.binary_search_by(|probe| {
21156                let cmp = probe
21157                    .end
21158                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21159                if cmp.is_gt() {
21160                    Ordering::Greater
21161                } else {
21162                    Ordering::Less
21163                }
21164            }) {
21165                Ok(i) | Err(i) => i,
21166            };
21167            for range in &ranges[start_ix..] {
21168                if range
21169                    .start
21170                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21171                    .is_ge()
21172                {
21173                    break;
21174                }
21175
21176                let start = range.start.to_display_point(display_snapshot);
21177                let end = range.end.to_display_point(display_snapshot);
21178                results.push((start..end, color))
21179            }
21180        }
21181        results
21182    }
21183
21184    /// Get the text ranges corresponding to the redaction query
21185    pub fn redacted_ranges(
21186        &self,
21187        search_range: Range<Anchor>,
21188        display_snapshot: &DisplaySnapshot,
21189        cx: &App,
21190    ) -> Vec<Range<DisplayPoint>> {
21191        display_snapshot
21192            .buffer_snapshot()
21193            .redacted_ranges(search_range, |file| {
21194                if let Some(file) = file {
21195                    file.is_private()
21196                        && EditorSettings::get(
21197                            Some(SettingsLocation {
21198                                worktree_id: file.worktree_id(cx),
21199                                path: file.path().as_ref(),
21200                            }),
21201                            cx,
21202                        )
21203                        .redact_private_values
21204                } else {
21205                    false
21206                }
21207            })
21208            .map(|range| {
21209                range.start.to_display_point(display_snapshot)
21210                    ..range.end.to_display_point(display_snapshot)
21211            })
21212            .collect()
21213    }
21214
21215    pub fn highlight_text_key<T: 'static>(
21216        &mut self,
21217        key: usize,
21218        ranges: Vec<Range<Anchor>>,
21219        style: HighlightStyle,
21220        merge: bool,
21221        cx: &mut Context<Self>,
21222    ) {
21223        self.display_map.update(cx, |map, cx| {
21224            map.highlight_text(
21225                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21226                ranges,
21227                style,
21228                merge,
21229                cx,
21230            );
21231        });
21232        cx.notify();
21233    }
21234
21235    pub fn highlight_text<T: 'static>(
21236        &mut self,
21237        ranges: Vec<Range<Anchor>>,
21238        style: HighlightStyle,
21239        cx: &mut Context<Self>,
21240    ) {
21241        self.display_map.update(cx, |map, cx| {
21242            map.highlight_text(
21243                HighlightKey::Type(TypeId::of::<T>()),
21244                ranges,
21245                style,
21246                false,
21247                cx,
21248            )
21249        });
21250        cx.notify();
21251    }
21252
21253    pub fn text_highlights<'a, T: 'static>(
21254        &'a self,
21255        cx: &'a App,
21256    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21257        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21258    }
21259
21260    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21261        let cleared = self
21262            .display_map
21263            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21264        if cleared {
21265            cx.notify();
21266        }
21267    }
21268
21269    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21270        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21271            && self.focus_handle.is_focused(window)
21272    }
21273
21274    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21275        self.show_cursor_when_unfocused = is_enabled;
21276        cx.notify();
21277    }
21278
21279    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21280        cx.notify();
21281    }
21282
21283    fn on_debug_session_event(
21284        &mut self,
21285        _session: Entity<Session>,
21286        event: &SessionEvent,
21287        cx: &mut Context<Self>,
21288    ) {
21289        if let SessionEvent::InvalidateInlineValue = event {
21290            self.refresh_inline_values(cx);
21291        }
21292    }
21293
21294    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21295        let Some(project) = self.project.clone() else {
21296            return;
21297        };
21298
21299        if !self.inline_value_cache.enabled {
21300            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21301            self.splice_inlays(&inlays, Vec::new(), cx);
21302            return;
21303        }
21304
21305        let current_execution_position = self
21306            .highlighted_rows
21307            .get(&TypeId::of::<ActiveDebugLine>())
21308            .and_then(|lines| lines.last().map(|line| line.range.end));
21309
21310        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21311            let inline_values = editor
21312                .update(cx, |editor, cx| {
21313                    let Some(current_execution_position) = current_execution_position else {
21314                        return Some(Task::ready(Ok(Vec::new())));
21315                    };
21316
21317                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21318                        let snapshot = buffer.snapshot(cx);
21319
21320                        let excerpt = snapshot.excerpt_containing(
21321                            current_execution_position..current_execution_position,
21322                        )?;
21323
21324                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21325                    })?;
21326
21327                    let range =
21328                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21329
21330                    project.inline_values(buffer, range, cx)
21331                })
21332                .ok()
21333                .flatten()?
21334                .await
21335                .context("refreshing debugger inlays")
21336                .log_err()?;
21337
21338            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21339
21340            for (buffer_id, inline_value) in inline_values
21341                .into_iter()
21342                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21343            {
21344                buffer_inline_values
21345                    .entry(buffer_id)
21346                    .or_default()
21347                    .push(inline_value);
21348            }
21349
21350            editor
21351                .update(cx, |editor, cx| {
21352                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21353                    let mut new_inlays = Vec::default();
21354
21355                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21356                        let buffer_id = buffer_snapshot.remote_id();
21357                        buffer_inline_values
21358                            .get(&buffer_id)
21359                            .into_iter()
21360                            .flatten()
21361                            .for_each(|hint| {
21362                                let inlay = Inlay::debugger(
21363                                    post_inc(&mut editor.next_inlay_id),
21364                                    Anchor::in_buffer(excerpt_id, hint.position),
21365                                    hint.text(),
21366                                );
21367                                if !inlay.text().chars().contains(&'\n') {
21368                                    new_inlays.push(inlay);
21369                                }
21370                            });
21371                    }
21372
21373                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21374                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21375
21376                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21377                })
21378                .ok()?;
21379            Some(())
21380        });
21381    }
21382
21383    fn on_buffer_event(
21384        &mut self,
21385        multibuffer: &Entity<MultiBuffer>,
21386        event: &multi_buffer::Event,
21387        window: &mut Window,
21388        cx: &mut Context<Self>,
21389    ) {
21390        match event {
21391            multi_buffer::Event::Edited { edited_buffer } => {
21392                self.scrollbar_marker_state.dirty = true;
21393                self.active_indent_guides_state.dirty = true;
21394                self.refresh_active_diagnostics(cx);
21395                self.refresh_code_actions(window, cx);
21396                self.refresh_single_line_folds(window, cx);
21397                self.refresh_matching_bracket_highlights(window, cx);
21398                if self.has_active_edit_prediction() {
21399                    self.update_visible_edit_prediction(window, cx);
21400                }
21401
21402                if let Some(buffer) = edited_buffer {
21403                    if buffer.read(cx).file().is_none() {
21404                        cx.emit(EditorEvent::TitleChanged);
21405                    }
21406
21407                    if self.project.is_some() {
21408                        let buffer_id = buffer.read(cx).remote_id();
21409                        self.register_buffer(buffer_id, cx);
21410                        self.update_lsp_data(Some(buffer_id), window, cx);
21411                        self.refresh_inlay_hints(
21412                            InlayHintRefreshReason::BufferEdited(buffer_id),
21413                            cx,
21414                        );
21415                    }
21416                }
21417
21418                cx.emit(EditorEvent::BufferEdited);
21419                cx.emit(SearchEvent::MatchesInvalidated);
21420
21421                let Some(project) = &self.project else { return };
21422                let (telemetry, is_via_ssh) = {
21423                    let project = project.read(cx);
21424                    let telemetry = project.client().telemetry().clone();
21425                    let is_via_ssh = project.is_via_remote_server();
21426                    (telemetry, is_via_ssh)
21427                };
21428                telemetry.log_edit_event("editor", is_via_ssh);
21429            }
21430            multi_buffer::Event::ExcerptsAdded {
21431                buffer,
21432                predecessor,
21433                excerpts,
21434            } => {
21435                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21436                let buffer_id = buffer.read(cx).remote_id();
21437                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21438                    && let Some(project) = &self.project
21439                {
21440                    update_uncommitted_diff_for_buffer(
21441                        cx.entity(),
21442                        project,
21443                        [buffer.clone()],
21444                        self.buffer.clone(),
21445                        cx,
21446                    )
21447                    .detach();
21448                }
21449                self.update_lsp_data(Some(buffer_id), window, cx);
21450                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21451                self.colorize_brackets(false, cx);
21452                cx.emit(EditorEvent::ExcerptsAdded {
21453                    buffer: buffer.clone(),
21454                    predecessor: *predecessor,
21455                    excerpts: excerpts.clone(),
21456                });
21457            }
21458            multi_buffer::Event::ExcerptsRemoved {
21459                ids,
21460                removed_buffer_ids,
21461            } => {
21462                if let Some(inlay_hints) = &mut self.inlay_hints {
21463                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21464                }
21465                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21466                for buffer_id in removed_buffer_ids {
21467                    self.registered_buffers.remove(buffer_id);
21468                }
21469                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21470                cx.emit(EditorEvent::ExcerptsRemoved {
21471                    ids: ids.clone(),
21472                    removed_buffer_ids: removed_buffer_ids.clone(),
21473                });
21474            }
21475            multi_buffer::Event::ExcerptsEdited {
21476                excerpt_ids,
21477                buffer_ids,
21478            } => {
21479                self.display_map.update(cx, |map, cx| {
21480                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21481                });
21482                cx.emit(EditorEvent::ExcerptsEdited {
21483                    ids: excerpt_ids.clone(),
21484                });
21485            }
21486            multi_buffer::Event::ExcerptsExpanded { ids } => {
21487                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21488                self.refresh_document_highlights(cx);
21489                for id in ids {
21490                    self.fetched_tree_sitter_chunks.remove(id);
21491                }
21492                self.colorize_brackets(false, cx);
21493                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21494            }
21495            multi_buffer::Event::Reparsed(buffer_id) => {
21496                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21497                self.refresh_selected_text_highlights(true, window, cx);
21498                self.colorize_brackets(true, cx);
21499                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21500
21501                cx.emit(EditorEvent::Reparsed(*buffer_id));
21502            }
21503            multi_buffer::Event::DiffHunksToggled => {
21504                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21505            }
21506            multi_buffer::Event::LanguageChanged(buffer_id) => {
21507                self.registered_buffers.remove(&buffer_id);
21508                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21509                cx.emit(EditorEvent::Reparsed(*buffer_id));
21510                cx.notify();
21511            }
21512            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21513            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21514            multi_buffer::Event::FileHandleChanged
21515            | multi_buffer::Event::Reloaded
21516            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21517            multi_buffer::Event::DiagnosticsUpdated => {
21518                self.update_diagnostics_state(window, cx);
21519            }
21520            _ => {}
21521        };
21522    }
21523
21524    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21525        if !self.diagnostics_enabled() {
21526            return;
21527        }
21528        self.refresh_active_diagnostics(cx);
21529        self.refresh_inline_diagnostics(true, window, cx);
21530        self.scrollbar_marker_state.dirty = true;
21531        cx.notify();
21532    }
21533
21534    pub fn start_temporary_diff_override(&mut self) {
21535        self.load_diff_task.take();
21536        self.temporary_diff_override = true;
21537    }
21538
21539    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21540        self.temporary_diff_override = false;
21541        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21542        self.buffer.update(cx, |buffer, cx| {
21543            buffer.set_all_diff_hunks_collapsed(cx);
21544        });
21545
21546        if let Some(project) = self.project.clone() {
21547            self.load_diff_task = Some(
21548                update_uncommitted_diff_for_buffer(
21549                    cx.entity(),
21550                    &project,
21551                    self.buffer.read(cx).all_buffers(),
21552                    self.buffer.clone(),
21553                    cx,
21554                )
21555                .shared(),
21556            );
21557        }
21558    }
21559
21560    fn on_display_map_changed(
21561        &mut self,
21562        _: Entity<DisplayMap>,
21563        _: &mut Window,
21564        cx: &mut Context<Self>,
21565    ) {
21566        cx.notify();
21567    }
21568
21569    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21570        if !self.mode.is_full() {
21571            return Vec::new();
21572        }
21573
21574        let theme_settings = theme::ThemeSettings::get_global(cx);
21575
21576        theme_settings
21577            .theme_overrides
21578            .get(cx.theme().name.as_ref())
21579            .map(|theme_style| &theme_style.accents)
21580            .into_iter()
21581            .flatten()
21582            .chain(
21583                theme_settings
21584                    .experimental_theme_overrides
21585                    .as_ref()
21586                    .map(|overrides| &overrides.accents)
21587                    .into_iter()
21588                    .flatten(),
21589            )
21590            .flat_map(|accent| accent.0.clone())
21591            .collect()
21592    }
21593
21594    fn fetch_applicable_language_settings(
21595        &self,
21596        cx: &App,
21597    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21598        if !self.mode.is_full() {
21599            return HashMap::default();
21600        }
21601
21602        self.buffer().read(cx).all_buffers().into_iter().fold(
21603            HashMap::default(),
21604            |mut acc, buffer| {
21605                let buffer = buffer.read(cx);
21606                let language = buffer.language().map(|language| language.name());
21607                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21608                    let file = buffer.file();
21609                    v.insert(language_settings(language, file, cx).into_owned());
21610                }
21611                acc
21612            },
21613        )
21614    }
21615
21616    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21617        let new_language_settings = self.fetch_applicable_language_settings(cx);
21618        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21619        self.applicable_language_settings = new_language_settings;
21620
21621        let new_accent_overrides = self.fetch_accent_overrides(cx);
21622        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21623        self.accent_overrides = new_accent_overrides;
21624
21625        if self.diagnostics_enabled() {
21626            let new_severity = EditorSettings::get_global(cx)
21627                .diagnostics_max_severity
21628                .unwrap_or(DiagnosticSeverity::Hint);
21629            self.set_max_diagnostics_severity(new_severity, cx);
21630        }
21631        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21632        self.update_edit_prediction_settings(cx);
21633        self.refresh_edit_prediction(true, false, window, cx);
21634        self.refresh_inline_values(cx);
21635        self.refresh_inlay_hints(
21636            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21637                self.selections.newest_anchor().head(),
21638                &self.buffer.read(cx).snapshot(cx),
21639                cx,
21640            )),
21641            cx,
21642        );
21643
21644        let old_cursor_shape = self.cursor_shape;
21645        let old_show_breadcrumbs = self.show_breadcrumbs;
21646
21647        {
21648            let editor_settings = EditorSettings::get_global(cx);
21649            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21650            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21651            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21652            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21653        }
21654
21655        if old_cursor_shape != self.cursor_shape {
21656            cx.emit(EditorEvent::CursorShapeChanged);
21657        }
21658
21659        if old_show_breadcrumbs != self.show_breadcrumbs {
21660            cx.emit(EditorEvent::BreadcrumbsChanged);
21661        }
21662
21663        let project_settings = ProjectSettings::get_global(cx);
21664        self.buffer_serialization = self
21665            .should_serialize_buffer()
21666            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21667
21668        if self.mode.is_full() {
21669            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21670            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21671            if self.show_inline_diagnostics != show_inline_diagnostics {
21672                self.show_inline_diagnostics = show_inline_diagnostics;
21673                self.refresh_inline_diagnostics(false, window, cx);
21674            }
21675
21676            if self.git_blame_inline_enabled != inline_blame_enabled {
21677                self.toggle_git_blame_inline_internal(false, window, cx);
21678            }
21679
21680            let minimap_settings = EditorSettings::get_global(cx).minimap;
21681            if self.minimap_visibility != MinimapVisibility::Disabled {
21682                if self.minimap_visibility.settings_visibility()
21683                    != minimap_settings.minimap_enabled()
21684                {
21685                    self.set_minimap_visibility(
21686                        MinimapVisibility::for_mode(self.mode(), cx),
21687                        window,
21688                        cx,
21689                    );
21690                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21691                    minimap_entity.update(cx, |minimap_editor, cx| {
21692                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21693                    })
21694                }
21695            }
21696
21697            if language_settings_changed || accent_overrides_changed {
21698                self.colorize_brackets(true, cx);
21699            }
21700
21701            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21702                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21703            }) {
21704                if !inlay_splice.is_empty() {
21705                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21706                }
21707                self.refresh_colors_for_visible_range(None, window, cx);
21708            }
21709        }
21710
21711        cx.notify();
21712    }
21713
21714    pub fn set_searchable(&mut self, searchable: bool) {
21715        self.searchable = searchable;
21716    }
21717
21718    pub fn searchable(&self) -> bool {
21719        self.searchable
21720    }
21721
21722    pub fn open_excerpts_in_split(
21723        &mut self,
21724        _: &OpenExcerptsSplit,
21725        window: &mut Window,
21726        cx: &mut Context<Self>,
21727    ) {
21728        self.open_excerpts_common(None, true, window, cx)
21729    }
21730
21731    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21732        self.open_excerpts_common(None, false, window, cx)
21733    }
21734
21735    fn open_excerpts_common(
21736        &mut self,
21737        jump_data: Option<JumpData>,
21738        split: bool,
21739        window: &mut Window,
21740        cx: &mut Context<Self>,
21741    ) {
21742        let Some(workspace) = self.workspace() else {
21743            cx.propagate();
21744            return;
21745        };
21746
21747        if self.buffer.read(cx).is_singleton() {
21748            cx.propagate();
21749            return;
21750        }
21751
21752        let mut new_selections_by_buffer = HashMap::default();
21753        match &jump_data {
21754            Some(JumpData::MultiBufferPoint {
21755                excerpt_id,
21756                position,
21757                anchor,
21758                line_offset_from_top,
21759            }) => {
21760                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21761                if let Some(buffer) = multi_buffer_snapshot
21762                    .buffer_id_for_excerpt(*excerpt_id)
21763                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21764                {
21765                    let buffer_snapshot = buffer.read(cx).snapshot();
21766                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21767                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21768                    } else {
21769                        buffer_snapshot.clip_point(*position, Bias::Left)
21770                    };
21771                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21772                    new_selections_by_buffer.insert(
21773                        buffer,
21774                        (
21775                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21776                            Some(*line_offset_from_top),
21777                        ),
21778                    );
21779                }
21780            }
21781            Some(JumpData::MultiBufferRow {
21782                row,
21783                line_offset_from_top,
21784            }) => {
21785                let point = MultiBufferPoint::new(row.0, 0);
21786                if let Some((buffer, buffer_point, _)) =
21787                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21788                {
21789                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21790                    new_selections_by_buffer
21791                        .entry(buffer)
21792                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21793                        .0
21794                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21795                }
21796            }
21797            None => {
21798                let selections = self
21799                    .selections
21800                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21801                let multi_buffer = self.buffer.read(cx);
21802                for selection in selections {
21803                    for (snapshot, range, _, anchor) in multi_buffer
21804                        .snapshot(cx)
21805                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21806                    {
21807                        if let Some(anchor) = anchor {
21808                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21809                            else {
21810                                continue;
21811                            };
21812                            let offset = text::ToOffset::to_offset(
21813                                &anchor.text_anchor,
21814                                &buffer_handle.read(cx).snapshot(),
21815                            );
21816                            let range = BufferOffset(offset)..BufferOffset(offset);
21817                            new_selections_by_buffer
21818                                .entry(buffer_handle)
21819                                .or_insert((Vec::new(), None))
21820                                .0
21821                                .push(range)
21822                        } else {
21823                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21824                            else {
21825                                continue;
21826                            };
21827                            new_selections_by_buffer
21828                                .entry(buffer_handle)
21829                                .or_insert((Vec::new(), None))
21830                                .0
21831                                .push(range)
21832                        }
21833                    }
21834                }
21835            }
21836        }
21837
21838        new_selections_by_buffer
21839            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21840
21841        if new_selections_by_buffer.is_empty() {
21842            return;
21843        }
21844
21845        // We defer the pane interaction because we ourselves are a workspace item
21846        // and activating a new item causes the pane to call a method on us reentrantly,
21847        // which panics if we're on the stack.
21848        window.defer(cx, move |window, cx| {
21849            workspace.update(cx, |workspace, cx| {
21850                let pane = if split {
21851                    workspace.adjacent_pane(window, cx)
21852                } else {
21853                    workspace.active_pane().clone()
21854                };
21855
21856                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21857                    let editor = buffer
21858                        .read(cx)
21859                        .file()
21860                        .is_none()
21861                        .then(|| {
21862                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21863                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21864                            // Instead, we try to activate the existing editor in the pane first.
21865                            let (editor, pane_item_index) =
21866                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21867                                    let editor = item.downcast::<Editor>()?;
21868                                    let singleton_buffer =
21869                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21870                                    if singleton_buffer == buffer {
21871                                        Some((editor, i))
21872                                    } else {
21873                                        None
21874                                    }
21875                                })?;
21876                            pane.update(cx, |pane, cx| {
21877                                pane.activate_item(pane_item_index, true, true, window, cx)
21878                            });
21879                            Some(editor)
21880                        })
21881                        .flatten()
21882                        .unwrap_or_else(|| {
21883                            workspace.open_project_item::<Self>(
21884                                pane.clone(),
21885                                buffer,
21886                                true,
21887                                true,
21888                                window,
21889                                cx,
21890                            )
21891                        });
21892
21893                    editor.update(cx, |editor, cx| {
21894                        let autoscroll = match scroll_offset {
21895                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21896                            None => Autoscroll::newest(),
21897                        };
21898                        let nav_history = editor.nav_history.take();
21899                        editor.change_selections(
21900                            SelectionEffects::scroll(autoscroll),
21901                            window,
21902                            cx,
21903                            |s| {
21904                                s.select_ranges(ranges.into_iter().map(|range| {
21905                                    // we checked that the editor is a singleton editor so the offsets are valid
21906                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21907                                }));
21908                            },
21909                        );
21910                        editor.nav_history = nav_history;
21911                    });
21912                }
21913            })
21914        });
21915    }
21916
21917    // For now, don't allow opening excerpts in buffers that aren't backed by
21918    // regular project files.
21919    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21920        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21921    }
21922
21923    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21924        let snapshot = self.buffer.read(cx).read(cx);
21925        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21926        Some(
21927            ranges
21928                .iter()
21929                .map(move |range| {
21930                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21931                })
21932                .collect(),
21933        )
21934    }
21935
21936    fn selection_replacement_ranges(
21937        &self,
21938        range: Range<MultiBufferOffsetUtf16>,
21939        cx: &mut App,
21940    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21941        let selections = self
21942            .selections
21943            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21944        let newest_selection = selections
21945            .iter()
21946            .max_by_key(|selection| selection.id)
21947            .unwrap();
21948        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21949        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21950        let snapshot = self.buffer.read(cx).read(cx);
21951        selections
21952            .into_iter()
21953            .map(|mut selection| {
21954                selection.start.0.0 =
21955                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21956                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21957                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21958                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21959            })
21960            .collect()
21961    }
21962
21963    fn report_editor_event(
21964        &self,
21965        reported_event: ReportEditorEvent,
21966        file_extension: Option<String>,
21967        cx: &App,
21968    ) {
21969        if cfg!(any(test, feature = "test-support")) {
21970            return;
21971        }
21972
21973        let Some(project) = &self.project else { return };
21974
21975        // If None, we are in a file without an extension
21976        let file = self
21977            .buffer
21978            .read(cx)
21979            .as_singleton()
21980            .and_then(|b| b.read(cx).file());
21981        let file_extension = file_extension.or(file
21982            .as_ref()
21983            .and_then(|file| Path::new(file.file_name(cx)).extension())
21984            .and_then(|e| e.to_str())
21985            .map(|a| a.to_string()));
21986
21987        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21988            .map(|vim_mode| vim_mode.0)
21989            .unwrap_or(false);
21990
21991        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21992        let copilot_enabled = edit_predictions_provider
21993            == language::language_settings::EditPredictionProvider::Copilot;
21994        let copilot_enabled_for_language = self
21995            .buffer
21996            .read(cx)
21997            .language_settings(cx)
21998            .show_edit_predictions;
21999
22000        let project = project.read(cx);
22001        let event_type = reported_event.event_type();
22002
22003        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22004            telemetry::event!(
22005                event_type,
22006                type = if auto_saved {"autosave"} else {"manual"},
22007                file_extension,
22008                vim_mode,
22009                copilot_enabled,
22010                copilot_enabled_for_language,
22011                edit_predictions_provider,
22012                is_via_ssh = project.is_via_remote_server(),
22013            );
22014        } else {
22015            telemetry::event!(
22016                event_type,
22017                file_extension,
22018                vim_mode,
22019                copilot_enabled,
22020                copilot_enabled_for_language,
22021                edit_predictions_provider,
22022                is_via_ssh = project.is_via_remote_server(),
22023            );
22024        };
22025    }
22026
22027    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22028    /// with each line being an array of {text, highlight} objects.
22029    fn copy_highlight_json(
22030        &mut self,
22031        _: &CopyHighlightJson,
22032        window: &mut Window,
22033        cx: &mut Context<Self>,
22034    ) {
22035        #[derive(Serialize)]
22036        struct Chunk<'a> {
22037            text: String,
22038            highlight: Option<&'a str>,
22039        }
22040
22041        let snapshot = self.buffer.read(cx).snapshot(cx);
22042        let range = self
22043            .selected_text_range(false, window, cx)
22044            .and_then(|selection| {
22045                if selection.range.is_empty() {
22046                    None
22047                } else {
22048                    Some(
22049                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22050                            selection.range.start,
22051                        )))
22052                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22053                                selection.range.end,
22054                            ))),
22055                    )
22056                }
22057            })
22058            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22059
22060        let chunks = snapshot.chunks(range, true);
22061        let mut lines = Vec::new();
22062        let mut line: VecDeque<Chunk> = VecDeque::new();
22063
22064        let Some(style) = self.style.as_ref() else {
22065            return;
22066        };
22067
22068        for chunk in chunks {
22069            let highlight = chunk
22070                .syntax_highlight_id
22071                .and_then(|id| id.name(&style.syntax));
22072            let mut chunk_lines = chunk.text.split('\n').peekable();
22073            while let Some(text) = chunk_lines.next() {
22074                let mut merged_with_last_token = false;
22075                if let Some(last_token) = line.back_mut()
22076                    && last_token.highlight == highlight
22077                {
22078                    last_token.text.push_str(text);
22079                    merged_with_last_token = true;
22080                }
22081
22082                if !merged_with_last_token {
22083                    line.push_back(Chunk {
22084                        text: text.into(),
22085                        highlight,
22086                    });
22087                }
22088
22089                if chunk_lines.peek().is_some() {
22090                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22091                        line.pop_front();
22092                    }
22093                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22094                        line.pop_back();
22095                    }
22096
22097                    lines.push(mem::take(&mut line));
22098                }
22099            }
22100        }
22101
22102        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22103            return;
22104        };
22105        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22106    }
22107
22108    pub fn open_context_menu(
22109        &mut self,
22110        _: &OpenContextMenu,
22111        window: &mut Window,
22112        cx: &mut Context<Self>,
22113    ) {
22114        self.request_autoscroll(Autoscroll::newest(), cx);
22115        let position = self
22116            .selections
22117            .newest_display(&self.display_snapshot(cx))
22118            .start;
22119        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22120    }
22121
22122    pub fn replay_insert_event(
22123        &mut self,
22124        text: &str,
22125        relative_utf16_range: Option<Range<isize>>,
22126        window: &mut Window,
22127        cx: &mut Context<Self>,
22128    ) {
22129        if !self.input_enabled {
22130            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22131            return;
22132        }
22133        if let Some(relative_utf16_range) = relative_utf16_range {
22134            let selections = self
22135                .selections
22136                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22137            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22138                let new_ranges = selections.into_iter().map(|range| {
22139                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22140                        range
22141                            .head()
22142                            .0
22143                            .0
22144                            .saturating_add_signed(relative_utf16_range.start),
22145                    ));
22146                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22147                        range
22148                            .head()
22149                            .0
22150                            .0
22151                            .saturating_add_signed(relative_utf16_range.end),
22152                    ));
22153                    start..end
22154                });
22155                s.select_ranges(new_ranges);
22156            });
22157        }
22158
22159        self.handle_input(text, window, cx);
22160    }
22161
22162    pub fn is_focused(&self, window: &Window) -> bool {
22163        self.focus_handle.is_focused(window)
22164    }
22165
22166    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22167        cx.emit(EditorEvent::Focused);
22168
22169        if let Some(descendant) = self
22170            .last_focused_descendant
22171            .take()
22172            .and_then(|descendant| descendant.upgrade())
22173        {
22174            window.focus(&descendant);
22175        } else {
22176            if let Some(blame) = self.blame.as_ref() {
22177                blame.update(cx, GitBlame::focus)
22178            }
22179
22180            self.blink_manager.update(cx, BlinkManager::enable);
22181            self.show_cursor_names(window, cx);
22182            self.buffer.update(cx, |buffer, cx| {
22183                buffer.finalize_last_transaction(cx);
22184                if self.leader_id.is_none() {
22185                    buffer.set_active_selections(
22186                        &self.selections.disjoint_anchors_arc(),
22187                        self.selections.line_mode(),
22188                        self.cursor_shape,
22189                        cx,
22190                    );
22191                }
22192            });
22193
22194            if let Some(position_map) = self.last_position_map.clone() {
22195                EditorElement::mouse_moved(
22196                    self,
22197                    &MouseMoveEvent {
22198                        position: window.mouse_position(),
22199                        pressed_button: None,
22200                        modifiers: window.modifiers(),
22201                    },
22202                    &position_map,
22203                    window,
22204                    cx,
22205                );
22206            }
22207        }
22208    }
22209
22210    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22211        cx.emit(EditorEvent::FocusedIn)
22212    }
22213
22214    fn handle_focus_out(
22215        &mut self,
22216        event: FocusOutEvent,
22217        _window: &mut Window,
22218        cx: &mut Context<Self>,
22219    ) {
22220        if event.blurred != self.focus_handle {
22221            self.last_focused_descendant = Some(event.blurred);
22222        }
22223        self.selection_drag_state = SelectionDragState::None;
22224        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22225    }
22226
22227    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22228        self.blink_manager.update(cx, BlinkManager::disable);
22229        self.buffer
22230            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22231
22232        if let Some(blame) = self.blame.as_ref() {
22233            blame.update(cx, GitBlame::blur)
22234        }
22235        if !self.hover_state.focused(window, cx) {
22236            hide_hover(self, cx);
22237        }
22238        if !self
22239            .context_menu
22240            .borrow()
22241            .as_ref()
22242            .is_some_and(|context_menu| context_menu.focused(window, cx))
22243        {
22244            self.hide_context_menu(window, cx);
22245        }
22246        self.take_active_edit_prediction(cx);
22247        cx.emit(EditorEvent::Blurred);
22248        cx.notify();
22249    }
22250
22251    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22252        let mut pending: String = window
22253            .pending_input_keystrokes()
22254            .into_iter()
22255            .flatten()
22256            .filter_map(|keystroke| keystroke.key_char.clone())
22257            .collect();
22258
22259        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22260            pending = "".to_string();
22261        }
22262
22263        let existing_pending = self
22264            .text_highlights::<PendingInput>(cx)
22265            .map(|(_, ranges)| ranges.to_vec());
22266        if existing_pending.is_none() && pending.is_empty() {
22267            return;
22268        }
22269        let transaction =
22270            self.transact(window, cx, |this, window, cx| {
22271                let selections = this
22272                    .selections
22273                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22274                let edits = selections
22275                    .iter()
22276                    .map(|selection| (selection.end..selection.end, pending.clone()));
22277                this.edit(edits, cx);
22278                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22279                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22280                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22281                    }));
22282                });
22283                if let Some(existing_ranges) = existing_pending {
22284                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22285                    this.edit(edits, cx);
22286                }
22287            });
22288
22289        let snapshot = self.snapshot(window, cx);
22290        let ranges = self
22291            .selections
22292            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22293            .into_iter()
22294            .map(|selection| {
22295                snapshot.buffer_snapshot().anchor_after(selection.end)
22296                    ..snapshot
22297                        .buffer_snapshot()
22298                        .anchor_before(selection.end + pending.len())
22299            })
22300            .collect();
22301
22302        if pending.is_empty() {
22303            self.clear_highlights::<PendingInput>(cx);
22304        } else {
22305            self.highlight_text::<PendingInput>(
22306                ranges,
22307                HighlightStyle {
22308                    underline: Some(UnderlineStyle {
22309                        thickness: px(1.),
22310                        color: None,
22311                        wavy: false,
22312                    }),
22313                    ..Default::default()
22314                },
22315                cx,
22316            );
22317        }
22318
22319        self.ime_transaction = self.ime_transaction.or(transaction);
22320        if let Some(transaction) = self.ime_transaction {
22321            self.buffer.update(cx, |buffer, cx| {
22322                buffer.group_until_transaction(transaction, cx);
22323            });
22324        }
22325
22326        if self.text_highlights::<PendingInput>(cx).is_none() {
22327            self.ime_transaction.take();
22328        }
22329    }
22330
22331    pub fn register_action_renderer(
22332        &mut self,
22333        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22334    ) -> Subscription {
22335        let id = self.next_editor_action_id.post_inc();
22336        self.editor_actions
22337            .borrow_mut()
22338            .insert(id, Box::new(listener));
22339
22340        let editor_actions = self.editor_actions.clone();
22341        Subscription::new(move || {
22342            editor_actions.borrow_mut().remove(&id);
22343        })
22344    }
22345
22346    pub fn register_action<A: Action>(
22347        &mut self,
22348        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22349    ) -> Subscription {
22350        let id = self.next_editor_action_id.post_inc();
22351        let listener = Arc::new(listener);
22352        self.editor_actions.borrow_mut().insert(
22353            id,
22354            Box::new(move |_, window, _| {
22355                let listener = listener.clone();
22356                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22357                    let action = action.downcast_ref().unwrap();
22358                    if phase == DispatchPhase::Bubble {
22359                        listener(action, window, cx)
22360                    }
22361                })
22362            }),
22363        );
22364
22365        let editor_actions = self.editor_actions.clone();
22366        Subscription::new(move || {
22367            editor_actions.borrow_mut().remove(&id);
22368        })
22369    }
22370
22371    pub fn file_header_size(&self) -> u32 {
22372        FILE_HEADER_HEIGHT
22373    }
22374
22375    pub fn restore(
22376        &mut self,
22377        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22378        window: &mut Window,
22379        cx: &mut Context<Self>,
22380    ) {
22381        let workspace = self.workspace();
22382        let project = self.project();
22383        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22384            let mut tasks = Vec::new();
22385            for (buffer_id, changes) in revert_changes {
22386                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22387                    buffer.update(cx, |buffer, cx| {
22388                        buffer.edit(
22389                            changes
22390                                .into_iter()
22391                                .map(|(range, text)| (range, text.to_string())),
22392                            None,
22393                            cx,
22394                        );
22395                    });
22396
22397                    if let Some(project) =
22398                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22399                    {
22400                        project.update(cx, |project, cx| {
22401                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22402                        })
22403                    }
22404                }
22405            }
22406            tasks
22407        });
22408        cx.spawn_in(window, async move |_, cx| {
22409            for (buffer, task) in save_tasks {
22410                let result = task.await;
22411                if result.is_err() {
22412                    let Some(path) = buffer
22413                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22414                        .ok()
22415                    else {
22416                        continue;
22417                    };
22418                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22419                        let Some(task) = cx
22420                            .update_window_entity(workspace, |workspace, window, cx| {
22421                                workspace
22422                                    .open_path_preview(path, None, false, false, false, window, cx)
22423                            })
22424                            .ok()
22425                        else {
22426                            continue;
22427                        };
22428                        task.await.log_err();
22429                    }
22430                }
22431            }
22432        })
22433        .detach();
22434        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22435            selections.refresh()
22436        });
22437    }
22438
22439    pub fn to_pixel_point(
22440        &self,
22441        source: multi_buffer::Anchor,
22442        editor_snapshot: &EditorSnapshot,
22443        window: &mut Window,
22444    ) -> Option<gpui::Point<Pixels>> {
22445        let source_point = source.to_display_point(editor_snapshot);
22446        self.display_to_pixel_point(source_point, editor_snapshot, window)
22447    }
22448
22449    pub fn display_to_pixel_point(
22450        &self,
22451        source: DisplayPoint,
22452        editor_snapshot: &EditorSnapshot,
22453        window: &mut Window,
22454    ) -> Option<gpui::Point<Pixels>> {
22455        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22456        let text_layout_details = self.text_layout_details(window);
22457        let scroll_top = text_layout_details
22458            .scroll_anchor
22459            .scroll_position(editor_snapshot)
22460            .y;
22461
22462        if source.row().as_f64() < scroll_top.floor() {
22463            return None;
22464        }
22465        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22466        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22467        Some(gpui::Point::new(source_x, source_y))
22468    }
22469
22470    pub fn has_visible_completions_menu(&self) -> bool {
22471        !self.edit_prediction_preview_is_active()
22472            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22473                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22474            })
22475    }
22476
22477    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22478        if self.mode.is_minimap() {
22479            return;
22480        }
22481        self.addons
22482            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22483    }
22484
22485    pub fn unregister_addon<T: Addon>(&mut self) {
22486        self.addons.remove(&std::any::TypeId::of::<T>());
22487    }
22488
22489    pub fn addon<T: Addon>(&self) -> Option<&T> {
22490        let type_id = std::any::TypeId::of::<T>();
22491        self.addons
22492            .get(&type_id)
22493            .and_then(|item| item.to_any().downcast_ref::<T>())
22494    }
22495
22496    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22497        let type_id = std::any::TypeId::of::<T>();
22498        self.addons
22499            .get_mut(&type_id)
22500            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22501    }
22502
22503    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22504        let text_layout_details = self.text_layout_details(window);
22505        let style = &text_layout_details.editor_style;
22506        let font_id = window.text_system().resolve_font(&style.text.font());
22507        let font_size = style.text.font_size.to_pixels(window.rem_size());
22508        let line_height = style.text.line_height_in_pixels(window.rem_size());
22509        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22510        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22511
22512        CharacterDimensions {
22513            em_width,
22514            em_advance,
22515            line_height,
22516        }
22517    }
22518
22519    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22520        self.load_diff_task.clone()
22521    }
22522
22523    fn read_metadata_from_db(
22524        &mut self,
22525        item_id: u64,
22526        workspace_id: WorkspaceId,
22527        window: &mut Window,
22528        cx: &mut Context<Editor>,
22529    ) {
22530        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22531            && !self.mode.is_minimap()
22532            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22533        {
22534            let buffer_snapshot = OnceCell::new();
22535
22536            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22537                && !folds.is_empty()
22538            {
22539                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22540                self.fold_ranges(
22541                    folds
22542                        .into_iter()
22543                        .map(|(start, end)| {
22544                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22545                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22546                        })
22547                        .collect(),
22548                    false,
22549                    window,
22550                    cx,
22551                );
22552            }
22553
22554            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22555                && !selections.is_empty()
22556            {
22557                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22558                // skip adding the initial selection to selection history
22559                self.selection_history.mode = SelectionHistoryMode::Skipping;
22560                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22561                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22562                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22563                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22564                    }));
22565                });
22566                self.selection_history.mode = SelectionHistoryMode::Normal;
22567            };
22568        }
22569
22570        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22571    }
22572
22573    fn update_lsp_data(
22574        &mut self,
22575        for_buffer: Option<BufferId>,
22576        window: &mut Window,
22577        cx: &mut Context<'_, Self>,
22578    ) {
22579        self.pull_diagnostics(for_buffer, window, cx);
22580        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22581    }
22582
22583    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22584        if self.ignore_lsp_data() {
22585            return;
22586        }
22587        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22588            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22589        }
22590    }
22591
22592    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22593        if self.ignore_lsp_data() {
22594            return;
22595        }
22596
22597        if !self.registered_buffers.contains_key(&buffer_id)
22598            && let Some(project) = self.project.as_ref()
22599        {
22600            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22601                project.update(cx, |project, cx| {
22602                    self.registered_buffers.insert(
22603                        buffer_id,
22604                        project.register_buffer_with_language_servers(&buffer, cx),
22605                    );
22606                });
22607            } else {
22608                self.registered_buffers.remove(&buffer_id);
22609            }
22610        }
22611    }
22612
22613    fn ignore_lsp_data(&self) -> bool {
22614        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22615        // skip any LSP updates for it.
22616        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22617    }
22618}
22619
22620fn edit_for_markdown_paste<'a>(
22621    buffer: &MultiBufferSnapshot,
22622    range: Range<MultiBufferOffset>,
22623    to_insert: &'a str,
22624    url: Option<url::Url>,
22625) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22626    if url.is_none() {
22627        return (range, Cow::Borrowed(to_insert));
22628    };
22629
22630    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22631
22632    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22633        Cow::Borrowed(to_insert)
22634    } else {
22635        Cow::Owned(format!("[{old_text}]({to_insert})"))
22636    };
22637    (range, new_text)
22638}
22639
22640fn process_completion_for_edit(
22641    completion: &Completion,
22642    intent: CompletionIntent,
22643    buffer: &Entity<Buffer>,
22644    cursor_position: &text::Anchor,
22645    cx: &mut Context<Editor>,
22646) -> CompletionEdit {
22647    let buffer = buffer.read(cx);
22648    let buffer_snapshot = buffer.snapshot();
22649    let (snippet, new_text) = if completion.is_snippet() {
22650        let mut snippet_source = completion.new_text.clone();
22651        // Workaround for typescript language server issues so that methods don't expand within
22652        // strings and functions with type expressions. The previous point is used because the query
22653        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22654        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22655        let previous_point = if previous_point.column > 0 {
22656            cursor_position.to_previous_offset(&buffer_snapshot)
22657        } else {
22658            cursor_position.to_offset(&buffer_snapshot)
22659        };
22660        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22661            && scope.prefers_label_for_snippet_in_completion()
22662            && let Some(label) = completion.label()
22663            && matches!(
22664                completion.kind(),
22665                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22666            )
22667        {
22668            snippet_source = label;
22669        }
22670        match Snippet::parse(&snippet_source).log_err() {
22671            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22672            None => (None, completion.new_text.clone()),
22673        }
22674    } else {
22675        (None, completion.new_text.clone())
22676    };
22677
22678    let mut range_to_replace = {
22679        let replace_range = &completion.replace_range;
22680        if let CompletionSource::Lsp {
22681            insert_range: Some(insert_range),
22682            ..
22683        } = &completion.source
22684        {
22685            debug_assert_eq!(
22686                insert_range.start, replace_range.start,
22687                "insert_range and replace_range should start at the same position"
22688            );
22689            debug_assert!(
22690                insert_range
22691                    .start
22692                    .cmp(cursor_position, &buffer_snapshot)
22693                    .is_le(),
22694                "insert_range should start before or at cursor position"
22695            );
22696            debug_assert!(
22697                replace_range
22698                    .start
22699                    .cmp(cursor_position, &buffer_snapshot)
22700                    .is_le(),
22701                "replace_range should start before or at cursor position"
22702            );
22703
22704            let should_replace = match intent {
22705                CompletionIntent::CompleteWithInsert => false,
22706                CompletionIntent::CompleteWithReplace => true,
22707                CompletionIntent::Complete | CompletionIntent::Compose => {
22708                    let insert_mode =
22709                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22710                            .completions
22711                            .lsp_insert_mode;
22712                    match insert_mode {
22713                        LspInsertMode::Insert => false,
22714                        LspInsertMode::Replace => true,
22715                        LspInsertMode::ReplaceSubsequence => {
22716                            let mut text_to_replace = buffer.chars_for_range(
22717                                buffer.anchor_before(replace_range.start)
22718                                    ..buffer.anchor_after(replace_range.end),
22719                            );
22720                            let mut current_needle = text_to_replace.next();
22721                            for haystack_ch in completion.label.text.chars() {
22722                                if let Some(needle_ch) = current_needle
22723                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22724                                {
22725                                    current_needle = text_to_replace.next();
22726                                }
22727                            }
22728                            current_needle.is_none()
22729                        }
22730                        LspInsertMode::ReplaceSuffix => {
22731                            if replace_range
22732                                .end
22733                                .cmp(cursor_position, &buffer_snapshot)
22734                                .is_gt()
22735                            {
22736                                let range_after_cursor = *cursor_position..replace_range.end;
22737                                let text_after_cursor = buffer
22738                                    .text_for_range(
22739                                        buffer.anchor_before(range_after_cursor.start)
22740                                            ..buffer.anchor_after(range_after_cursor.end),
22741                                    )
22742                                    .collect::<String>()
22743                                    .to_ascii_lowercase();
22744                                completion
22745                                    .label
22746                                    .text
22747                                    .to_ascii_lowercase()
22748                                    .ends_with(&text_after_cursor)
22749                            } else {
22750                                true
22751                            }
22752                        }
22753                    }
22754                }
22755            };
22756
22757            if should_replace {
22758                replace_range.clone()
22759            } else {
22760                insert_range.clone()
22761            }
22762        } else {
22763            replace_range.clone()
22764        }
22765    };
22766
22767    if range_to_replace
22768        .end
22769        .cmp(cursor_position, &buffer_snapshot)
22770        .is_lt()
22771    {
22772        range_to_replace.end = *cursor_position;
22773    }
22774
22775    let replace_range = range_to_replace.to_offset(buffer);
22776    CompletionEdit {
22777        new_text,
22778        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22779        snippet,
22780    }
22781}
22782
22783struct CompletionEdit {
22784    new_text: String,
22785    replace_range: Range<BufferOffset>,
22786    snippet: Option<Snippet>,
22787}
22788
22789fn insert_extra_newline_brackets(
22790    buffer: &MultiBufferSnapshot,
22791    range: Range<MultiBufferOffset>,
22792    language: &language::LanguageScope,
22793) -> bool {
22794    let leading_whitespace_len = buffer
22795        .reversed_chars_at(range.start)
22796        .take_while(|c| c.is_whitespace() && *c != '\n')
22797        .map(|c| c.len_utf8())
22798        .sum::<usize>();
22799    let trailing_whitespace_len = buffer
22800        .chars_at(range.end)
22801        .take_while(|c| c.is_whitespace() && *c != '\n')
22802        .map(|c| c.len_utf8())
22803        .sum::<usize>();
22804    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22805
22806    language.brackets().any(|(pair, enabled)| {
22807        let pair_start = pair.start.trim_end();
22808        let pair_end = pair.end.trim_start();
22809
22810        enabled
22811            && pair.newline
22812            && buffer.contains_str_at(range.end, pair_end)
22813            && buffer.contains_str_at(
22814                range.start.saturating_sub_usize(pair_start.len()),
22815                pair_start,
22816            )
22817    })
22818}
22819
22820fn insert_extra_newline_tree_sitter(
22821    buffer: &MultiBufferSnapshot,
22822    range: Range<MultiBufferOffset>,
22823) -> bool {
22824    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22825        [(buffer, range, _)] => (*buffer, range.clone()),
22826        _ => return false,
22827    };
22828    let pair = {
22829        let mut result: Option<BracketMatch<usize>> = None;
22830
22831        for pair in buffer
22832            .all_bracket_ranges(range.start.0..range.end.0)
22833            .filter(move |pair| {
22834                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22835            })
22836        {
22837            let len = pair.close_range.end - pair.open_range.start;
22838
22839            if let Some(existing) = &result {
22840                let existing_len = existing.close_range.end - existing.open_range.start;
22841                if len > existing_len {
22842                    continue;
22843                }
22844            }
22845
22846            result = Some(pair);
22847        }
22848
22849        result
22850    };
22851    let Some(pair) = pair else {
22852        return false;
22853    };
22854    pair.newline_only
22855        && buffer
22856            .chars_for_range(pair.open_range.end..range.start.0)
22857            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22858            .all(|c| c.is_whitespace() && c != '\n')
22859}
22860
22861fn update_uncommitted_diff_for_buffer(
22862    editor: Entity<Editor>,
22863    project: &Entity<Project>,
22864    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22865    buffer: Entity<MultiBuffer>,
22866    cx: &mut App,
22867) -> Task<()> {
22868    let mut tasks = Vec::new();
22869    project.update(cx, |project, cx| {
22870        for buffer in buffers {
22871            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22872                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22873            }
22874        }
22875    });
22876    cx.spawn(async move |cx| {
22877        let diffs = future::join_all(tasks).await;
22878        if editor
22879            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22880            .unwrap_or(false)
22881        {
22882            return;
22883        }
22884
22885        buffer
22886            .update(cx, |buffer, cx| {
22887                for diff in diffs.into_iter().flatten() {
22888                    buffer.add_diff(diff, cx);
22889                }
22890            })
22891            .ok();
22892    })
22893}
22894
22895fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22896    let tab_size = tab_size.get() as usize;
22897    let mut width = offset;
22898
22899    for ch in text.chars() {
22900        width += if ch == '\t' {
22901            tab_size - (width % tab_size)
22902        } else {
22903            1
22904        };
22905    }
22906
22907    width - offset
22908}
22909
22910#[cfg(test)]
22911mod tests {
22912    use super::*;
22913
22914    #[test]
22915    fn test_string_size_with_expanded_tabs() {
22916        let nz = |val| NonZeroU32::new(val).unwrap();
22917        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22918        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22919        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22920        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22921        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22922        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22923        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22924        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22925    }
22926}
22927
22928/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22929struct WordBreakingTokenizer<'a> {
22930    input: &'a str,
22931}
22932
22933impl<'a> WordBreakingTokenizer<'a> {
22934    fn new(input: &'a str) -> Self {
22935        Self { input }
22936    }
22937}
22938
22939fn is_char_ideographic(ch: char) -> bool {
22940    use unicode_script::Script::*;
22941    use unicode_script::UnicodeScript;
22942    matches!(ch.script(), Han | Tangut | Yi)
22943}
22944
22945fn is_grapheme_ideographic(text: &str) -> bool {
22946    text.chars().any(is_char_ideographic)
22947}
22948
22949fn is_grapheme_whitespace(text: &str) -> bool {
22950    text.chars().any(|x| x.is_whitespace())
22951}
22952
22953fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22954    text.chars()
22955        .next()
22956        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22957}
22958
22959#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22960enum WordBreakToken<'a> {
22961    Word { token: &'a str, grapheme_len: usize },
22962    InlineWhitespace { token: &'a str, grapheme_len: usize },
22963    Newline,
22964}
22965
22966impl<'a> Iterator for WordBreakingTokenizer<'a> {
22967    /// Yields a span, the count of graphemes in the token, and whether it was
22968    /// whitespace. Note that it also breaks at word boundaries.
22969    type Item = WordBreakToken<'a>;
22970
22971    fn next(&mut self) -> Option<Self::Item> {
22972        use unicode_segmentation::UnicodeSegmentation;
22973        if self.input.is_empty() {
22974            return None;
22975        }
22976
22977        let mut iter = self.input.graphemes(true).peekable();
22978        let mut offset = 0;
22979        let mut grapheme_len = 0;
22980        if let Some(first_grapheme) = iter.next() {
22981            let is_newline = first_grapheme == "\n";
22982            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22983            offset += first_grapheme.len();
22984            grapheme_len += 1;
22985            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22986                if let Some(grapheme) = iter.peek().copied()
22987                    && should_stay_with_preceding_ideograph(grapheme)
22988                {
22989                    offset += grapheme.len();
22990                    grapheme_len += 1;
22991                }
22992            } else {
22993                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22994                let mut next_word_bound = words.peek().copied();
22995                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22996                    next_word_bound = words.next();
22997                }
22998                while let Some(grapheme) = iter.peek().copied() {
22999                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23000                        break;
23001                    };
23002                    if is_grapheme_whitespace(grapheme) != is_whitespace
23003                        || (grapheme == "\n") != is_newline
23004                    {
23005                        break;
23006                    };
23007                    offset += grapheme.len();
23008                    grapheme_len += 1;
23009                    iter.next();
23010                }
23011            }
23012            let token = &self.input[..offset];
23013            self.input = &self.input[offset..];
23014            if token == "\n" {
23015                Some(WordBreakToken::Newline)
23016            } else if is_whitespace {
23017                Some(WordBreakToken::InlineWhitespace {
23018                    token,
23019                    grapheme_len,
23020                })
23021            } else {
23022                Some(WordBreakToken::Word {
23023                    token,
23024                    grapheme_len,
23025                })
23026            }
23027        } else {
23028            None
23029        }
23030    }
23031}
23032
23033#[test]
23034fn test_word_breaking_tokenizer() {
23035    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23036        ("", &[]),
23037        ("  ", &[whitespace("  ", 2)]),
23038        ("Ʒ", &[word("Ʒ", 1)]),
23039        ("Ǽ", &[word("Ǽ", 1)]),
23040        ("", &[word("", 1)]),
23041        ("⋑⋑", &[word("⋑⋑", 2)]),
23042        (
23043            "原理,进而",
23044            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23045        ),
23046        (
23047            "hello world",
23048            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23049        ),
23050        (
23051            "hello, world",
23052            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23053        ),
23054        (
23055            "  hello world",
23056            &[
23057                whitespace("  ", 2),
23058                word("hello", 5),
23059                whitespace(" ", 1),
23060                word("world", 5),
23061            ],
23062        ),
23063        (
23064            "这是什么 \n 钢笔",
23065            &[
23066                word("", 1),
23067                word("", 1),
23068                word("", 1),
23069                word("", 1),
23070                whitespace(" ", 1),
23071                newline(),
23072                whitespace(" ", 1),
23073                word("", 1),
23074                word("", 1),
23075            ],
23076        ),
23077        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23078    ];
23079
23080    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23081        WordBreakToken::Word {
23082            token,
23083            grapheme_len,
23084        }
23085    }
23086
23087    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23088        WordBreakToken::InlineWhitespace {
23089            token,
23090            grapheme_len,
23091        }
23092    }
23093
23094    fn newline() -> WordBreakToken<'static> {
23095        WordBreakToken::Newline
23096    }
23097
23098    for (input, result) in tests {
23099        assert_eq!(
23100            WordBreakingTokenizer::new(input)
23101                .collect::<Vec<_>>()
23102                .as_slice(),
23103            *result,
23104        );
23105    }
23106}
23107
23108fn wrap_with_prefix(
23109    first_line_prefix: String,
23110    subsequent_lines_prefix: String,
23111    unwrapped_text: String,
23112    wrap_column: usize,
23113    tab_size: NonZeroU32,
23114    preserve_existing_whitespace: bool,
23115) -> String {
23116    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23117    let subsequent_lines_prefix_len =
23118        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23119    let mut wrapped_text = String::new();
23120    let mut current_line = first_line_prefix;
23121    let mut is_first_line = true;
23122
23123    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23124    let mut current_line_len = first_line_prefix_len;
23125    let mut in_whitespace = false;
23126    for token in tokenizer {
23127        let have_preceding_whitespace = in_whitespace;
23128        match token {
23129            WordBreakToken::Word {
23130                token,
23131                grapheme_len,
23132            } => {
23133                in_whitespace = false;
23134                let current_prefix_len = if is_first_line {
23135                    first_line_prefix_len
23136                } else {
23137                    subsequent_lines_prefix_len
23138                };
23139                if current_line_len + grapheme_len > wrap_column
23140                    && current_line_len != current_prefix_len
23141                {
23142                    wrapped_text.push_str(current_line.trim_end());
23143                    wrapped_text.push('\n');
23144                    is_first_line = false;
23145                    current_line = subsequent_lines_prefix.clone();
23146                    current_line_len = subsequent_lines_prefix_len;
23147                }
23148                current_line.push_str(token);
23149                current_line_len += grapheme_len;
23150            }
23151            WordBreakToken::InlineWhitespace {
23152                mut token,
23153                mut grapheme_len,
23154            } => {
23155                in_whitespace = true;
23156                if have_preceding_whitespace && !preserve_existing_whitespace {
23157                    continue;
23158                }
23159                if !preserve_existing_whitespace {
23160                    // Keep a single whitespace grapheme as-is
23161                    if let Some(first) =
23162                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23163                    {
23164                        token = first;
23165                    } else {
23166                        token = " ";
23167                    }
23168                    grapheme_len = 1;
23169                }
23170                let current_prefix_len = if is_first_line {
23171                    first_line_prefix_len
23172                } else {
23173                    subsequent_lines_prefix_len
23174                };
23175                if current_line_len + grapheme_len > wrap_column {
23176                    wrapped_text.push_str(current_line.trim_end());
23177                    wrapped_text.push('\n');
23178                    is_first_line = false;
23179                    current_line = subsequent_lines_prefix.clone();
23180                    current_line_len = subsequent_lines_prefix_len;
23181                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23182                    current_line.push_str(token);
23183                    current_line_len += grapheme_len;
23184                }
23185            }
23186            WordBreakToken::Newline => {
23187                in_whitespace = true;
23188                let current_prefix_len = if is_first_line {
23189                    first_line_prefix_len
23190                } else {
23191                    subsequent_lines_prefix_len
23192                };
23193                if preserve_existing_whitespace {
23194                    wrapped_text.push_str(current_line.trim_end());
23195                    wrapped_text.push('\n');
23196                    is_first_line = false;
23197                    current_line = subsequent_lines_prefix.clone();
23198                    current_line_len = subsequent_lines_prefix_len;
23199                } else if have_preceding_whitespace {
23200                    continue;
23201                } else if current_line_len + 1 > wrap_column
23202                    && current_line_len != current_prefix_len
23203                {
23204                    wrapped_text.push_str(current_line.trim_end());
23205                    wrapped_text.push('\n');
23206                    is_first_line = false;
23207                    current_line = subsequent_lines_prefix.clone();
23208                    current_line_len = subsequent_lines_prefix_len;
23209                } else if current_line_len != current_prefix_len {
23210                    current_line.push(' ');
23211                    current_line_len += 1;
23212                }
23213            }
23214        }
23215    }
23216
23217    if !current_line.is_empty() {
23218        wrapped_text.push_str(&current_line);
23219    }
23220    wrapped_text
23221}
23222
23223#[test]
23224fn test_wrap_with_prefix() {
23225    assert_eq!(
23226        wrap_with_prefix(
23227            "# ".to_string(),
23228            "# ".to_string(),
23229            "abcdefg".to_string(),
23230            4,
23231            NonZeroU32::new(4).unwrap(),
23232            false,
23233        ),
23234        "# abcdefg"
23235    );
23236    assert_eq!(
23237        wrap_with_prefix(
23238            "".to_string(),
23239            "".to_string(),
23240            "\thello world".to_string(),
23241            8,
23242            NonZeroU32::new(4).unwrap(),
23243            false,
23244        ),
23245        "hello\nworld"
23246    );
23247    assert_eq!(
23248        wrap_with_prefix(
23249            "// ".to_string(),
23250            "// ".to_string(),
23251            "xx \nyy zz aa bb cc".to_string(),
23252            12,
23253            NonZeroU32::new(4).unwrap(),
23254            false,
23255        ),
23256        "// xx yy zz\n// aa bb cc"
23257    );
23258    assert_eq!(
23259        wrap_with_prefix(
23260            String::new(),
23261            String::new(),
23262            "这是什么 \n 钢笔".to_string(),
23263            3,
23264            NonZeroU32::new(4).unwrap(),
23265            false,
23266        ),
23267        "这是什\n么 钢\n"
23268    );
23269    assert_eq!(
23270        wrap_with_prefix(
23271            String::new(),
23272            String::new(),
23273            format!("foo{}bar", '\u{2009}'), // thin space
23274            80,
23275            NonZeroU32::new(4).unwrap(),
23276            false,
23277        ),
23278        format!("foo{}bar", '\u{2009}')
23279    );
23280}
23281
23282pub trait CollaborationHub {
23283    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23284    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23285    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23286}
23287
23288impl CollaborationHub for Entity<Project> {
23289    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23290        self.read(cx).collaborators()
23291    }
23292
23293    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23294        self.read(cx).user_store().read(cx).participant_indices()
23295    }
23296
23297    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23298        let this = self.read(cx);
23299        let user_ids = this.collaborators().values().map(|c| c.user_id);
23300        this.user_store().read(cx).participant_names(user_ids, cx)
23301    }
23302}
23303
23304pub trait SemanticsProvider {
23305    fn hover(
23306        &self,
23307        buffer: &Entity<Buffer>,
23308        position: text::Anchor,
23309        cx: &mut App,
23310    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23311
23312    fn inline_values(
23313        &self,
23314        buffer_handle: Entity<Buffer>,
23315        range: Range<text::Anchor>,
23316        cx: &mut App,
23317    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23318
23319    fn applicable_inlay_chunks(
23320        &self,
23321        buffer: &Entity<Buffer>,
23322        ranges: &[Range<text::Anchor>],
23323        cx: &mut App,
23324    ) -> Vec<Range<BufferRow>>;
23325
23326    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23327
23328    fn inlay_hints(
23329        &self,
23330        invalidate: InvalidationStrategy,
23331        buffer: Entity<Buffer>,
23332        ranges: Vec<Range<text::Anchor>>,
23333        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23334        cx: &mut App,
23335    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23336
23337    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23338
23339    fn document_highlights(
23340        &self,
23341        buffer: &Entity<Buffer>,
23342        position: text::Anchor,
23343        cx: &mut App,
23344    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23345
23346    fn definitions(
23347        &self,
23348        buffer: &Entity<Buffer>,
23349        position: text::Anchor,
23350        kind: GotoDefinitionKind,
23351        cx: &mut App,
23352    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23353
23354    fn range_for_rename(
23355        &self,
23356        buffer: &Entity<Buffer>,
23357        position: text::Anchor,
23358        cx: &mut App,
23359    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23360
23361    fn perform_rename(
23362        &self,
23363        buffer: &Entity<Buffer>,
23364        position: text::Anchor,
23365        new_name: String,
23366        cx: &mut App,
23367    ) -> Option<Task<Result<ProjectTransaction>>>;
23368}
23369
23370pub trait CompletionProvider {
23371    fn completions(
23372        &self,
23373        excerpt_id: ExcerptId,
23374        buffer: &Entity<Buffer>,
23375        buffer_position: text::Anchor,
23376        trigger: CompletionContext,
23377        window: &mut Window,
23378        cx: &mut Context<Editor>,
23379    ) -> Task<Result<Vec<CompletionResponse>>>;
23380
23381    fn resolve_completions(
23382        &self,
23383        _buffer: Entity<Buffer>,
23384        _completion_indices: Vec<usize>,
23385        _completions: Rc<RefCell<Box<[Completion]>>>,
23386        _cx: &mut Context<Editor>,
23387    ) -> Task<Result<bool>> {
23388        Task::ready(Ok(false))
23389    }
23390
23391    fn apply_additional_edits_for_completion(
23392        &self,
23393        _buffer: Entity<Buffer>,
23394        _completions: Rc<RefCell<Box<[Completion]>>>,
23395        _completion_index: usize,
23396        _push_to_history: bool,
23397        _cx: &mut Context<Editor>,
23398    ) -> Task<Result<Option<language::Transaction>>> {
23399        Task::ready(Ok(None))
23400    }
23401
23402    fn is_completion_trigger(
23403        &self,
23404        buffer: &Entity<Buffer>,
23405        position: language::Anchor,
23406        text: &str,
23407        trigger_in_words: bool,
23408        menu_is_open: bool,
23409        cx: &mut Context<Editor>,
23410    ) -> bool;
23411
23412    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23413
23414    fn sort_completions(&self) -> bool {
23415        true
23416    }
23417
23418    fn filter_completions(&self) -> bool {
23419        true
23420    }
23421
23422    fn show_snippets(&self) -> bool {
23423        false
23424    }
23425}
23426
23427pub trait CodeActionProvider {
23428    fn id(&self) -> Arc<str>;
23429
23430    fn code_actions(
23431        &self,
23432        buffer: &Entity<Buffer>,
23433        range: Range<text::Anchor>,
23434        window: &mut Window,
23435        cx: &mut App,
23436    ) -> Task<Result<Vec<CodeAction>>>;
23437
23438    fn apply_code_action(
23439        &self,
23440        buffer_handle: Entity<Buffer>,
23441        action: CodeAction,
23442        excerpt_id: ExcerptId,
23443        push_to_history: bool,
23444        window: &mut Window,
23445        cx: &mut App,
23446    ) -> Task<Result<ProjectTransaction>>;
23447}
23448
23449impl CodeActionProvider for Entity<Project> {
23450    fn id(&self) -> Arc<str> {
23451        "project".into()
23452    }
23453
23454    fn code_actions(
23455        &self,
23456        buffer: &Entity<Buffer>,
23457        range: Range<text::Anchor>,
23458        _window: &mut Window,
23459        cx: &mut App,
23460    ) -> Task<Result<Vec<CodeAction>>> {
23461        self.update(cx, |project, cx| {
23462            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23463            let code_actions = project.code_actions(buffer, range, None, cx);
23464            cx.background_spawn(async move {
23465                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23466                Ok(code_lens_actions
23467                    .context("code lens fetch")?
23468                    .into_iter()
23469                    .flatten()
23470                    .chain(
23471                        code_actions
23472                            .context("code action fetch")?
23473                            .into_iter()
23474                            .flatten(),
23475                    )
23476                    .collect())
23477            })
23478        })
23479    }
23480
23481    fn apply_code_action(
23482        &self,
23483        buffer_handle: Entity<Buffer>,
23484        action: CodeAction,
23485        _excerpt_id: ExcerptId,
23486        push_to_history: bool,
23487        _window: &mut Window,
23488        cx: &mut App,
23489    ) -> Task<Result<ProjectTransaction>> {
23490        self.update(cx, |project, cx| {
23491            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23492        })
23493    }
23494}
23495
23496fn snippet_completions(
23497    project: &Project,
23498    buffer: &Entity<Buffer>,
23499    buffer_anchor: text::Anchor,
23500    classifier: CharClassifier,
23501    cx: &mut App,
23502) -> Task<Result<CompletionResponse>> {
23503    let languages = buffer.read(cx).languages_at(buffer_anchor);
23504    let snippet_store = project.snippets().read(cx);
23505
23506    let scopes: Vec<_> = languages
23507        .iter()
23508        .filter_map(|language| {
23509            let language_name = language.lsp_id();
23510            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23511
23512            if snippets.is_empty() {
23513                None
23514            } else {
23515                Some((language.default_scope(), snippets))
23516            }
23517        })
23518        .collect();
23519
23520    if scopes.is_empty() {
23521        return Task::ready(Ok(CompletionResponse {
23522            completions: vec![],
23523            display_options: CompletionDisplayOptions::default(),
23524            is_incomplete: false,
23525        }));
23526    }
23527
23528    let snapshot = buffer.read(cx).text_snapshot();
23529    let executor = cx.background_executor().clone();
23530
23531    cx.background_spawn(async move {
23532        let is_word_char = |c| classifier.is_word(c);
23533
23534        let mut is_incomplete = false;
23535        let mut completions: Vec<Completion> = Vec::new();
23536
23537        const MAX_PREFIX_LEN: usize = 128;
23538        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23539        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23540        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23541
23542        let max_buffer_window: String = snapshot
23543            .text_for_range(window_start..buffer_offset)
23544            .collect();
23545
23546        if max_buffer_window.is_empty() {
23547            return Ok(CompletionResponse {
23548                completions: vec![],
23549                display_options: CompletionDisplayOptions::default(),
23550                is_incomplete: true,
23551            });
23552        }
23553
23554        for (_scope, snippets) in scopes.into_iter() {
23555            // Sort snippets by word count to match longer snippet prefixes first.
23556            let mut sorted_snippet_candidates = snippets
23557                .iter()
23558                .enumerate()
23559                .flat_map(|(snippet_ix, snippet)| {
23560                    snippet
23561                        .prefix
23562                        .iter()
23563                        .enumerate()
23564                        .map(move |(prefix_ix, prefix)| {
23565                            let word_count =
23566                                snippet_candidate_suffixes(prefix, is_word_char).count();
23567                            ((snippet_ix, prefix_ix), prefix, word_count)
23568                        })
23569                })
23570                .collect_vec();
23571            sorted_snippet_candidates
23572                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23573
23574            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23575
23576            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23577                .take(
23578                    sorted_snippet_candidates
23579                        .first()
23580                        .map(|(_, _, word_count)| *word_count)
23581                        .unwrap_or_default(),
23582                )
23583                .collect_vec();
23584
23585            const MAX_RESULTS: usize = 100;
23586            // Each match also remembers how many characters from the buffer it consumed
23587            let mut matches: Vec<(StringMatch, usize)> = vec![];
23588
23589            let mut snippet_list_cutoff_index = 0;
23590            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23591                let word_count = buffer_index + 1;
23592                // Increase `snippet_list_cutoff_index` until we have all of the
23593                // snippets with sufficiently many words.
23594                while sorted_snippet_candidates
23595                    .get(snippet_list_cutoff_index)
23596                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23597                        *snippet_word_count >= word_count
23598                    })
23599                {
23600                    snippet_list_cutoff_index += 1;
23601                }
23602
23603                // Take only the candidates with at least `word_count` many words
23604                let snippet_candidates_at_word_len =
23605                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23606
23607                let candidates = snippet_candidates_at_word_len
23608                    .iter()
23609                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23610                    .enumerate() // index in `sorted_snippet_candidates`
23611                    // First char must match
23612                    .filter(|(_ix, prefix)| {
23613                        itertools::equal(
23614                            prefix
23615                                .chars()
23616                                .next()
23617                                .into_iter()
23618                                .flat_map(|c| c.to_lowercase()),
23619                            buffer_window
23620                                .chars()
23621                                .next()
23622                                .into_iter()
23623                                .flat_map(|c| c.to_lowercase()),
23624                        )
23625                    })
23626                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23627                    .collect::<Vec<StringMatchCandidate>>();
23628
23629                matches.extend(
23630                    fuzzy::match_strings(
23631                        &candidates,
23632                        &buffer_window,
23633                        buffer_window.chars().any(|c| c.is_uppercase()),
23634                        true,
23635                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23636                        &Default::default(),
23637                        executor.clone(),
23638                    )
23639                    .await
23640                    .into_iter()
23641                    .map(|string_match| (string_match, buffer_window.len())),
23642                );
23643
23644                if matches.len() >= MAX_RESULTS {
23645                    break;
23646                }
23647            }
23648
23649            let to_lsp = |point: &text::Anchor| {
23650                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23651                point_to_lsp(end)
23652            };
23653            let lsp_end = to_lsp(&buffer_anchor);
23654
23655            if matches.len() >= MAX_RESULTS {
23656                is_incomplete = true;
23657            }
23658
23659            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23660                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23661                    sorted_snippet_candidates[string_match.candidate_id];
23662                let snippet = &snippets[snippet_index];
23663                let start = buffer_offset - buffer_window_len;
23664                let start = snapshot.anchor_before(start);
23665                let range = start..buffer_anchor;
23666                let lsp_start = to_lsp(&start);
23667                let lsp_range = lsp::Range {
23668                    start: lsp_start,
23669                    end: lsp_end,
23670                };
23671                Completion {
23672                    replace_range: range,
23673                    new_text: snippet.body.clone(),
23674                    source: CompletionSource::Lsp {
23675                        insert_range: None,
23676                        server_id: LanguageServerId(usize::MAX),
23677                        resolved: true,
23678                        lsp_completion: Box::new(lsp::CompletionItem {
23679                            label: snippet.prefix.first().unwrap().clone(),
23680                            kind: Some(CompletionItemKind::SNIPPET),
23681                            label_details: snippet.description.as_ref().map(|description| {
23682                                lsp::CompletionItemLabelDetails {
23683                                    detail: Some(description.clone()),
23684                                    description: None,
23685                                }
23686                            }),
23687                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23688                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23689                                lsp::InsertReplaceEdit {
23690                                    new_text: snippet.body.clone(),
23691                                    insert: lsp_range,
23692                                    replace: lsp_range,
23693                                },
23694                            )),
23695                            filter_text: Some(snippet.body.clone()),
23696                            sort_text: Some(char::MAX.to_string()),
23697                            ..lsp::CompletionItem::default()
23698                        }),
23699                        lsp_defaults: None,
23700                    },
23701                    label: CodeLabel {
23702                        text: matching_prefix.clone(),
23703                        runs: Vec::new(),
23704                        filter_range: 0..matching_prefix.len(),
23705                    },
23706                    icon_path: None,
23707                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23708                        single_line: snippet.name.clone().into(),
23709                        plain_text: snippet
23710                            .description
23711                            .clone()
23712                            .map(|description| description.into()),
23713                    }),
23714                    insert_text_mode: None,
23715                    confirm: None,
23716                    match_start: Some(start),
23717                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23718                }
23719            }));
23720        }
23721
23722        Ok(CompletionResponse {
23723            completions,
23724            display_options: CompletionDisplayOptions::default(),
23725            is_incomplete,
23726        })
23727    })
23728}
23729
23730impl CompletionProvider for Entity<Project> {
23731    fn completions(
23732        &self,
23733        _excerpt_id: ExcerptId,
23734        buffer: &Entity<Buffer>,
23735        buffer_position: text::Anchor,
23736        options: CompletionContext,
23737        _window: &mut Window,
23738        cx: &mut Context<Editor>,
23739    ) -> Task<Result<Vec<CompletionResponse>>> {
23740        self.update(cx, |project, cx| {
23741            let task = project.completions(buffer, buffer_position, options, cx);
23742            cx.background_spawn(task)
23743        })
23744    }
23745
23746    fn resolve_completions(
23747        &self,
23748        buffer: Entity<Buffer>,
23749        completion_indices: Vec<usize>,
23750        completions: Rc<RefCell<Box<[Completion]>>>,
23751        cx: &mut Context<Editor>,
23752    ) -> Task<Result<bool>> {
23753        self.update(cx, |project, cx| {
23754            project.lsp_store().update(cx, |lsp_store, cx| {
23755                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23756            })
23757        })
23758    }
23759
23760    fn apply_additional_edits_for_completion(
23761        &self,
23762        buffer: Entity<Buffer>,
23763        completions: Rc<RefCell<Box<[Completion]>>>,
23764        completion_index: usize,
23765        push_to_history: bool,
23766        cx: &mut Context<Editor>,
23767    ) -> Task<Result<Option<language::Transaction>>> {
23768        self.update(cx, |project, cx| {
23769            project.lsp_store().update(cx, |lsp_store, cx| {
23770                lsp_store.apply_additional_edits_for_completion(
23771                    buffer,
23772                    completions,
23773                    completion_index,
23774                    push_to_history,
23775                    cx,
23776                )
23777            })
23778        })
23779    }
23780
23781    fn is_completion_trigger(
23782        &self,
23783        buffer: &Entity<Buffer>,
23784        position: language::Anchor,
23785        text: &str,
23786        trigger_in_words: bool,
23787        menu_is_open: bool,
23788        cx: &mut Context<Editor>,
23789    ) -> bool {
23790        let mut chars = text.chars();
23791        let char = if let Some(char) = chars.next() {
23792            char
23793        } else {
23794            return false;
23795        };
23796        if chars.next().is_some() {
23797            return false;
23798        }
23799
23800        let buffer = buffer.read(cx);
23801        let snapshot = buffer.snapshot();
23802        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23803            return false;
23804        }
23805        let classifier = snapshot
23806            .char_classifier_at(position)
23807            .scope_context(Some(CharScopeContext::Completion));
23808        if trigger_in_words && classifier.is_word(char) {
23809            return true;
23810        }
23811
23812        buffer.completion_triggers().contains(text)
23813    }
23814
23815    fn show_snippets(&self) -> bool {
23816        true
23817    }
23818}
23819
23820impl SemanticsProvider for Entity<Project> {
23821    fn hover(
23822        &self,
23823        buffer: &Entity<Buffer>,
23824        position: text::Anchor,
23825        cx: &mut App,
23826    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23827        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23828    }
23829
23830    fn document_highlights(
23831        &self,
23832        buffer: &Entity<Buffer>,
23833        position: text::Anchor,
23834        cx: &mut App,
23835    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23836        Some(self.update(cx, |project, cx| {
23837            project.document_highlights(buffer, position, cx)
23838        }))
23839    }
23840
23841    fn definitions(
23842        &self,
23843        buffer: &Entity<Buffer>,
23844        position: text::Anchor,
23845        kind: GotoDefinitionKind,
23846        cx: &mut App,
23847    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23848        Some(self.update(cx, |project, cx| match kind {
23849            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23850            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23851            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23852            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23853        }))
23854    }
23855
23856    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23857        self.update(cx, |project, cx| {
23858            if project
23859                .active_debug_session(cx)
23860                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23861            {
23862                return true;
23863            }
23864
23865            buffer.update(cx, |buffer, cx| {
23866                project.any_language_server_supports_inlay_hints(buffer, cx)
23867            })
23868        })
23869    }
23870
23871    fn inline_values(
23872        &self,
23873        buffer_handle: Entity<Buffer>,
23874        range: Range<text::Anchor>,
23875        cx: &mut App,
23876    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23877        self.update(cx, |project, cx| {
23878            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23879
23880            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23881        })
23882    }
23883
23884    fn applicable_inlay_chunks(
23885        &self,
23886        buffer: &Entity<Buffer>,
23887        ranges: &[Range<text::Anchor>],
23888        cx: &mut App,
23889    ) -> Vec<Range<BufferRow>> {
23890        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23891            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23892        })
23893    }
23894
23895    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23896        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23897            lsp_store.invalidate_inlay_hints(for_buffers)
23898        });
23899    }
23900
23901    fn inlay_hints(
23902        &self,
23903        invalidate: InvalidationStrategy,
23904        buffer: Entity<Buffer>,
23905        ranges: Vec<Range<text::Anchor>>,
23906        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23907        cx: &mut App,
23908    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23909        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23910            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23911        }))
23912    }
23913
23914    fn range_for_rename(
23915        &self,
23916        buffer: &Entity<Buffer>,
23917        position: text::Anchor,
23918        cx: &mut App,
23919    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23920        Some(self.update(cx, |project, cx| {
23921            let buffer = buffer.clone();
23922            let task = project.prepare_rename(buffer.clone(), position, cx);
23923            cx.spawn(async move |_, cx| {
23924                Ok(match task.await? {
23925                    PrepareRenameResponse::Success(range) => Some(range),
23926                    PrepareRenameResponse::InvalidPosition => None,
23927                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23928                        // Fallback on using TreeSitter info to determine identifier range
23929                        buffer.read_with(cx, |buffer, _| {
23930                            let snapshot = buffer.snapshot();
23931                            let (range, kind) = snapshot.surrounding_word(position, None);
23932                            if kind != Some(CharKind::Word) {
23933                                return None;
23934                            }
23935                            Some(
23936                                snapshot.anchor_before(range.start)
23937                                    ..snapshot.anchor_after(range.end),
23938                            )
23939                        })?
23940                    }
23941                })
23942            })
23943        }))
23944    }
23945
23946    fn perform_rename(
23947        &self,
23948        buffer: &Entity<Buffer>,
23949        position: text::Anchor,
23950        new_name: String,
23951        cx: &mut App,
23952    ) -> Option<Task<Result<ProjectTransaction>>> {
23953        Some(self.update(cx, |project, cx| {
23954            project.perform_rename(buffer.clone(), position, new_name, cx)
23955        }))
23956    }
23957}
23958
23959fn consume_contiguous_rows(
23960    contiguous_row_selections: &mut Vec<Selection<Point>>,
23961    selection: &Selection<Point>,
23962    display_map: &DisplaySnapshot,
23963    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23964) -> (MultiBufferRow, MultiBufferRow) {
23965    contiguous_row_selections.push(selection.clone());
23966    let start_row = starting_row(selection, display_map);
23967    let mut end_row = ending_row(selection, display_map);
23968
23969    while let Some(next_selection) = selections.peek() {
23970        if next_selection.start.row <= end_row.0 {
23971            end_row = ending_row(next_selection, display_map);
23972            contiguous_row_selections.push(selections.next().unwrap().clone());
23973        } else {
23974            break;
23975        }
23976    }
23977    (start_row, end_row)
23978}
23979
23980fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23981    if selection.start.column > 0 {
23982        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23983    } else {
23984        MultiBufferRow(selection.start.row)
23985    }
23986}
23987
23988fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23989    if next_selection.end.column > 0 || next_selection.is_empty() {
23990        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23991    } else {
23992        MultiBufferRow(next_selection.end.row)
23993    }
23994}
23995
23996impl EditorSnapshot {
23997    pub fn remote_selections_in_range<'a>(
23998        &'a self,
23999        range: &'a Range<Anchor>,
24000        collaboration_hub: &dyn CollaborationHub,
24001        cx: &'a App,
24002    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24003        let participant_names = collaboration_hub.user_names(cx);
24004        let participant_indices = collaboration_hub.user_participant_indices(cx);
24005        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24006        let collaborators_by_replica_id = collaborators_by_peer_id
24007            .values()
24008            .map(|collaborator| (collaborator.replica_id, collaborator))
24009            .collect::<HashMap<_, _>>();
24010        self.buffer_snapshot()
24011            .selections_in_range(range, false)
24012            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24013                if replica_id == ReplicaId::AGENT {
24014                    Some(RemoteSelection {
24015                        replica_id,
24016                        selection,
24017                        cursor_shape,
24018                        line_mode,
24019                        collaborator_id: CollaboratorId::Agent,
24020                        user_name: Some("Agent".into()),
24021                        color: cx.theme().players().agent(),
24022                    })
24023                } else {
24024                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24025                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24026                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24027                    Some(RemoteSelection {
24028                        replica_id,
24029                        selection,
24030                        cursor_shape,
24031                        line_mode,
24032                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24033                        user_name,
24034                        color: if let Some(index) = participant_index {
24035                            cx.theme().players().color_for_participant(index.0)
24036                        } else {
24037                            cx.theme().players().absent()
24038                        },
24039                    })
24040                }
24041            })
24042    }
24043
24044    pub fn hunks_for_ranges(
24045        &self,
24046        ranges: impl IntoIterator<Item = Range<Point>>,
24047    ) -> Vec<MultiBufferDiffHunk> {
24048        let mut hunks = Vec::new();
24049        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24050            HashMap::default();
24051        for query_range in ranges {
24052            let query_rows =
24053                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24054            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24055                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24056            ) {
24057                // Include deleted hunks that are adjacent to the query range, because
24058                // otherwise they would be missed.
24059                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24060                if hunk.status().is_deleted() {
24061                    intersects_range |= hunk.row_range.start == query_rows.end;
24062                    intersects_range |= hunk.row_range.end == query_rows.start;
24063                }
24064                if intersects_range {
24065                    if !processed_buffer_rows
24066                        .entry(hunk.buffer_id)
24067                        .or_default()
24068                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24069                    {
24070                        continue;
24071                    }
24072                    hunks.push(hunk);
24073                }
24074            }
24075        }
24076
24077        hunks
24078    }
24079
24080    fn display_diff_hunks_for_rows<'a>(
24081        &'a self,
24082        display_rows: Range<DisplayRow>,
24083        folded_buffers: &'a HashSet<BufferId>,
24084    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24085        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24086        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24087
24088        self.buffer_snapshot()
24089            .diff_hunks_in_range(buffer_start..buffer_end)
24090            .filter_map(|hunk| {
24091                if folded_buffers.contains(&hunk.buffer_id) {
24092                    return None;
24093                }
24094
24095                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24096                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24097
24098                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24099                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24100
24101                let display_hunk = if hunk_display_start.column() != 0 {
24102                    DisplayDiffHunk::Folded {
24103                        display_row: hunk_display_start.row(),
24104                    }
24105                } else {
24106                    let mut end_row = hunk_display_end.row();
24107                    if hunk_display_end.column() > 0 {
24108                        end_row.0 += 1;
24109                    }
24110                    let is_created_file = hunk.is_created_file();
24111                    DisplayDiffHunk::Unfolded {
24112                        status: hunk.status(),
24113                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24114                            ..hunk.diff_base_byte_range.end.0,
24115                        display_row_range: hunk_display_start.row()..end_row,
24116                        multi_buffer_range: Anchor::range_in_buffer(
24117                            hunk.excerpt_id,
24118                            hunk.buffer_range,
24119                        ),
24120                        is_created_file,
24121                    }
24122                };
24123
24124                Some(display_hunk)
24125            })
24126    }
24127
24128    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24129        self.display_snapshot
24130            .buffer_snapshot()
24131            .language_at(position)
24132    }
24133
24134    pub fn is_focused(&self) -> bool {
24135        self.is_focused
24136    }
24137
24138    pub fn placeholder_text(&self) -> Option<String> {
24139        self.placeholder_display_snapshot
24140            .as_ref()
24141            .map(|display_map| display_map.text())
24142    }
24143
24144    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24145        self.scroll_anchor.scroll_position(&self.display_snapshot)
24146    }
24147
24148    fn gutter_dimensions(
24149        &self,
24150        font_id: FontId,
24151        font_size: Pixels,
24152        max_line_number_width: Pixels,
24153        cx: &App,
24154    ) -> Option<GutterDimensions> {
24155        if !self.show_gutter {
24156            return None;
24157        }
24158
24159        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24160        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24161
24162        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24163            matches!(
24164                ProjectSettings::get_global(cx).git.git_gutter,
24165                GitGutterSetting::TrackedFiles
24166            )
24167        });
24168        let gutter_settings = EditorSettings::get_global(cx).gutter;
24169        let show_line_numbers = self
24170            .show_line_numbers
24171            .unwrap_or(gutter_settings.line_numbers);
24172        let line_gutter_width = if show_line_numbers {
24173            // Avoid flicker-like gutter resizes when the line number gains another digit by
24174            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24175            let min_width_for_number_on_gutter =
24176                ch_advance * gutter_settings.min_line_number_digits as f32;
24177            max_line_number_width.max(min_width_for_number_on_gutter)
24178        } else {
24179            0.0.into()
24180        };
24181
24182        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24183        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24184
24185        let git_blame_entries_width =
24186            self.git_blame_gutter_max_author_length
24187                .map(|max_author_length| {
24188                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24189                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24190
24191                    /// The number of characters to dedicate to gaps and margins.
24192                    const SPACING_WIDTH: usize = 4;
24193
24194                    let max_char_count = max_author_length.min(renderer.max_author_length())
24195                        + ::git::SHORT_SHA_LENGTH
24196                        + MAX_RELATIVE_TIMESTAMP.len()
24197                        + SPACING_WIDTH;
24198
24199                    ch_advance * max_char_count
24200                });
24201
24202        let is_singleton = self.buffer_snapshot().is_singleton();
24203
24204        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24205        left_padding += if !is_singleton {
24206            ch_width * 4.0
24207        } else if show_runnables || show_breakpoints {
24208            ch_width * 3.0
24209        } else if show_git_gutter && show_line_numbers {
24210            ch_width * 2.0
24211        } else if show_git_gutter || show_line_numbers {
24212            ch_width
24213        } else {
24214            px(0.)
24215        };
24216
24217        let shows_folds = is_singleton && gutter_settings.folds;
24218
24219        let right_padding = if shows_folds && show_line_numbers {
24220            ch_width * 4.0
24221        } else if shows_folds || (!is_singleton && show_line_numbers) {
24222            ch_width * 3.0
24223        } else if show_line_numbers {
24224            ch_width
24225        } else {
24226            px(0.)
24227        };
24228
24229        Some(GutterDimensions {
24230            left_padding,
24231            right_padding,
24232            width: line_gutter_width + left_padding + right_padding,
24233            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24234            git_blame_entries_width,
24235        })
24236    }
24237
24238    pub fn render_crease_toggle(
24239        &self,
24240        buffer_row: MultiBufferRow,
24241        row_contains_cursor: bool,
24242        editor: Entity<Editor>,
24243        window: &mut Window,
24244        cx: &mut App,
24245    ) -> Option<AnyElement> {
24246        let folded = self.is_line_folded(buffer_row);
24247        let mut is_foldable = false;
24248
24249        if let Some(crease) = self
24250            .crease_snapshot
24251            .query_row(buffer_row, self.buffer_snapshot())
24252        {
24253            is_foldable = true;
24254            match crease {
24255                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24256                    if let Some(render_toggle) = render_toggle {
24257                        let toggle_callback =
24258                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24259                                if folded {
24260                                    editor.update(cx, |editor, cx| {
24261                                        editor.fold_at(buffer_row, window, cx)
24262                                    });
24263                                } else {
24264                                    editor.update(cx, |editor, cx| {
24265                                        editor.unfold_at(buffer_row, window, cx)
24266                                    });
24267                                }
24268                            });
24269                        return Some((render_toggle)(
24270                            buffer_row,
24271                            folded,
24272                            toggle_callback,
24273                            window,
24274                            cx,
24275                        ));
24276                    }
24277                }
24278            }
24279        }
24280
24281        is_foldable |= self.starts_indent(buffer_row);
24282
24283        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24284            Some(
24285                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24286                    .toggle_state(folded)
24287                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24288                        if folded {
24289                            this.unfold_at(buffer_row, window, cx);
24290                        } else {
24291                            this.fold_at(buffer_row, window, cx);
24292                        }
24293                    }))
24294                    .into_any_element(),
24295            )
24296        } else {
24297            None
24298        }
24299    }
24300
24301    pub fn render_crease_trailer(
24302        &self,
24303        buffer_row: MultiBufferRow,
24304        window: &mut Window,
24305        cx: &mut App,
24306    ) -> Option<AnyElement> {
24307        let folded = self.is_line_folded(buffer_row);
24308        if let Crease::Inline { render_trailer, .. } = self
24309            .crease_snapshot
24310            .query_row(buffer_row, self.buffer_snapshot())?
24311        {
24312            let render_trailer = render_trailer.as_ref()?;
24313            Some(render_trailer(buffer_row, folded, window, cx))
24314        } else {
24315            None
24316        }
24317    }
24318}
24319
24320impl Deref for EditorSnapshot {
24321    type Target = DisplaySnapshot;
24322
24323    fn deref(&self) -> &Self::Target {
24324        &self.display_snapshot
24325    }
24326}
24327
24328#[derive(Clone, Debug, PartialEq, Eq)]
24329pub enum EditorEvent {
24330    InputIgnored {
24331        text: Arc<str>,
24332    },
24333    InputHandled {
24334        utf16_range_to_replace: Option<Range<isize>>,
24335        text: Arc<str>,
24336    },
24337    ExcerptsAdded {
24338        buffer: Entity<Buffer>,
24339        predecessor: ExcerptId,
24340        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24341    },
24342    ExcerptsRemoved {
24343        ids: Vec<ExcerptId>,
24344        removed_buffer_ids: Vec<BufferId>,
24345    },
24346    BufferFoldToggled {
24347        ids: Vec<ExcerptId>,
24348        folded: bool,
24349    },
24350    ExcerptsEdited {
24351        ids: Vec<ExcerptId>,
24352    },
24353    ExcerptsExpanded {
24354        ids: Vec<ExcerptId>,
24355    },
24356    BufferEdited,
24357    Edited {
24358        transaction_id: clock::Lamport,
24359    },
24360    Reparsed(BufferId),
24361    Focused,
24362    FocusedIn,
24363    Blurred,
24364    DirtyChanged,
24365    Saved,
24366    TitleChanged,
24367    SelectionsChanged {
24368        local: bool,
24369    },
24370    ScrollPositionChanged {
24371        local: bool,
24372        autoscroll: bool,
24373    },
24374    TransactionUndone {
24375        transaction_id: clock::Lamport,
24376    },
24377    TransactionBegun {
24378        transaction_id: clock::Lamport,
24379    },
24380    CursorShapeChanged,
24381    BreadcrumbsChanged,
24382    PushedToNavHistory {
24383        anchor: Anchor,
24384        is_deactivate: bool,
24385    },
24386}
24387
24388impl EventEmitter<EditorEvent> for Editor {}
24389
24390impl Focusable for Editor {
24391    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24392        self.focus_handle.clone()
24393    }
24394}
24395
24396impl Render for Editor {
24397    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24398        let settings = ThemeSettings::get_global(cx);
24399
24400        let mut text_style = match self.mode {
24401            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24402                color: cx.theme().colors().editor_foreground,
24403                font_family: settings.ui_font.family.clone(),
24404                font_features: settings.ui_font.features.clone(),
24405                font_fallbacks: settings.ui_font.fallbacks.clone(),
24406                font_size: rems(0.875).into(),
24407                font_weight: settings.ui_font.weight,
24408                line_height: relative(settings.buffer_line_height.value()),
24409                ..Default::default()
24410            },
24411            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24412                color: cx.theme().colors().editor_foreground,
24413                font_family: settings.buffer_font.family.clone(),
24414                font_features: settings.buffer_font.features.clone(),
24415                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24416                font_size: settings.buffer_font_size(cx).into(),
24417                font_weight: settings.buffer_font.weight,
24418                line_height: relative(settings.buffer_line_height.value()),
24419                ..Default::default()
24420            },
24421        };
24422        if let Some(text_style_refinement) = &self.text_style_refinement {
24423            text_style.refine(text_style_refinement)
24424        }
24425
24426        let background = match self.mode {
24427            EditorMode::SingleLine => cx.theme().system().transparent,
24428            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24429            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24430            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24431        };
24432
24433        EditorElement::new(
24434            &cx.entity(),
24435            EditorStyle {
24436                background,
24437                border: cx.theme().colors().border,
24438                local_player: cx.theme().players().local(),
24439                text: text_style,
24440                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24441                syntax: cx.theme().syntax().clone(),
24442                status: cx.theme().status().clone(),
24443                inlay_hints_style: make_inlay_hints_style(cx),
24444                edit_prediction_styles: make_suggestion_styles(cx),
24445                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24446                show_underlines: self.diagnostics_enabled(),
24447            },
24448        )
24449    }
24450}
24451
24452impl EntityInputHandler for Editor {
24453    fn text_for_range(
24454        &mut self,
24455        range_utf16: Range<usize>,
24456        adjusted_range: &mut Option<Range<usize>>,
24457        _: &mut Window,
24458        cx: &mut Context<Self>,
24459    ) -> Option<String> {
24460        let snapshot = self.buffer.read(cx).read(cx);
24461        let start = snapshot.clip_offset_utf16(
24462            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24463            Bias::Left,
24464        );
24465        let end = snapshot.clip_offset_utf16(
24466            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24467            Bias::Right,
24468        );
24469        if (start.0.0..end.0.0) != range_utf16 {
24470            adjusted_range.replace(start.0.0..end.0.0);
24471        }
24472        Some(snapshot.text_for_range(start..end).collect())
24473    }
24474
24475    fn selected_text_range(
24476        &mut self,
24477        ignore_disabled_input: bool,
24478        _: &mut Window,
24479        cx: &mut Context<Self>,
24480    ) -> Option<UTF16Selection> {
24481        // Prevent the IME menu from appearing when holding down an alphabetic key
24482        // while input is disabled.
24483        if !ignore_disabled_input && !self.input_enabled {
24484            return None;
24485        }
24486
24487        let selection = self
24488            .selections
24489            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24490        let range = selection.range();
24491
24492        Some(UTF16Selection {
24493            range: range.start.0.0..range.end.0.0,
24494            reversed: selection.reversed,
24495        })
24496    }
24497
24498    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24499        let snapshot = self.buffer.read(cx).read(cx);
24500        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24501        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24502    }
24503
24504    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24505        self.clear_highlights::<InputComposition>(cx);
24506        self.ime_transaction.take();
24507    }
24508
24509    fn replace_text_in_range(
24510        &mut self,
24511        range_utf16: Option<Range<usize>>,
24512        text: &str,
24513        window: &mut Window,
24514        cx: &mut Context<Self>,
24515    ) {
24516        if !self.input_enabled {
24517            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24518            return;
24519        }
24520
24521        self.transact(window, cx, |this, window, cx| {
24522            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24523                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24524                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24525                Some(this.selection_replacement_ranges(range_utf16, cx))
24526            } else {
24527                this.marked_text_ranges(cx)
24528            };
24529
24530            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24531                let newest_selection_id = this.selections.newest_anchor().id;
24532                this.selections
24533                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24534                    .iter()
24535                    .zip(ranges_to_replace.iter())
24536                    .find_map(|(selection, range)| {
24537                        if selection.id == newest_selection_id {
24538                            Some(
24539                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24540                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24541                            )
24542                        } else {
24543                            None
24544                        }
24545                    })
24546            });
24547
24548            cx.emit(EditorEvent::InputHandled {
24549                utf16_range_to_replace: range_to_replace,
24550                text: text.into(),
24551            });
24552
24553            if let Some(new_selected_ranges) = new_selected_ranges {
24554                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24555                    selections.select_ranges(new_selected_ranges)
24556                });
24557                this.backspace(&Default::default(), window, cx);
24558            }
24559
24560            this.handle_input(text, window, cx);
24561        });
24562
24563        if let Some(transaction) = self.ime_transaction {
24564            self.buffer.update(cx, |buffer, cx| {
24565                buffer.group_until_transaction(transaction, cx);
24566            });
24567        }
24568
24569        self.unmark_text(window, cx);
24570    }
24571
24572    fn replace_and_mark_text_in_range(
24573        &mut self,
24574        range_utf16: Option<Range<usize>>,
24575        text: &str,
24576        new_selected_range_utf16: Option<Range<usize>>,
24577        window: &mut Window,
24578        cx: &mut Context<Self>,
24579    ) {
24580        if !self.input_enabled {
24581            return;
24582        }
24583
24584        let transaction = self.transact(window, cx, |this, window, cx| {
24585            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24586                let snapshot = this.buffer.read(cx).read(cx);
24587                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24588                    for marked_range in &mut marked_ranges {
24589                        marked_range.end = marked_range.start + relative_range_utf16.end;
24590                        marked_range.start += relative_range_utf16.start;
24591                        marked_range.start =
24592                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24593                        marked_range.end =
24594                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24595                    }
24596                }
24597                Some(marked_ranges)
24598            } else if let Some(range_utf16) = range_utf16 {
24599                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24600                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24601                Some(this.selection_replacement_ranges(range_utf16, cx))
24602            } else {
24603                None
24604            };
24605
24606            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24607                let newest_selection_id = this.selections.newest_anchor().id;
24608                this.selections
24609                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24610                    .iter()
24611                    .zip(ranges_to_replace.iter())
24612                    .find_map(|(selection, range)| {
24613                        if selection.id == newest_selection_id {
24614                            Some(
24615                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24616                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24617                            )
24618                        } else {
24619                            None
24620                        }
24621                    })
24622            });
24623
24624            cx.emit(EditorEvent::InputHandled {
24625                utf16_range_to_replace: range_to_replace,
24626                text: text.into(),
24627            });
24628
24629            if let Some(ranges) = ranges_to_replace {
24630                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24631                    s.select_ranges(ranges)
24632                });
24633            }
24634
24635            let marked_ranges = {
24636                let snapshot = this.buffer.read(cx).read(cx);
24637                this.selections
24638                    .disjoint_anchors_arc()
24639                    .iter()
24640                    .map(|selection| {
24641                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24642                    })
24643                    .collect::<Vec<_>>()
24644            };
24645
24646            if text.is_empty() {
24647                this.unmark_text(window, cx);
24648            } else {
24649                this.highlight_text::<InputComposition>(
24650                    marked_ranges.clone(),
24651                    HighlightStyle {
24652                        underline: Some(UnderlineStyle {
24653                            thickness: px(1.),
24654                            color: None,
24655                            wavy: false,
24656                        }),
24657                        ..Default::default()
24658                    },
24659                    cx,
24660                );
24661            }
24662
24663            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24664            let use_autoclose = this.use_autoclose;
24665            let use_auto_surround = this.use_auto_surround;
24666            this.set_use_autoclose(false);
24667            this.set_use_auto_surround(false);
24668            this.handle_input(text, window, cx);
24669            this.set_use_autoclose(use_autoclose);
24670            this.set_use_auto_surround(use_auto_surround);
24671
24672            if let Some(new_selected_range) = new_selected_range_utf16 {
24673                let snapshot = this.buffer.read(cx).read(cx);
24674                let new_selected_ranges = marked_ranges
24675                    .into_iter()
24676                    .map(|marked_range| {
24677                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24678                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24679                            insertion_start.0 + new_selected_range.start,
24680                        ));
24681                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24682                            insertion_start.0 + new_selected_range.end,
24683                        ));
24684                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24685                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24686                    })
24687                    .collect::<Vec<_>>();
24688
24689                drop(snapshot);
24690                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24691                    selections.select_ranges(new_selected_ranges)
24692                });
24693            }
24694        });
24695
24696        self.ime_transaction = self.ime_transaction.or(transaction);
24697        if let Some(transaction) = self.ime_transaction {
24698            self.buffer.update(cx, |buffer, cx| {
24699                buffer.group_until_transaction(transaction, cx);
24700            });
24701        }
24702
24703        if self.text_highlights::<InputComposition>(cx).is_none() {
24704            self.ime_transaction.take();
24705        }
24706    }
24707
24708    fn bounds_for_range(
24709        &mut self,
24710        range_utf16: Range<usize>,
24711        element_bounds: gpui::Bounds<Pixels>,
24712        window: &mut Window,
24713        cx: &mut Context<Self>,
24714    ) -> Option<gpui::Bounds<Pixels>> {
24715        let text_layout_details = self.text_layout_details(window);
24716        let CharacterDimensions {
24717            em_width,
24718            em_advance,
24719            line_height,
24720        } = self.character_dimensions(window);
24721
24722        let snapshot = self.snapshot(window, cx);
24723        let scroll_position = snapshot.scroll_position();
24724        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24725
24726        let start =
24727            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24728        let x = Pixels::from(
24729            ScrollOffset::from(
24730                snapshot.x_for_display_point(start, &text_layout_details)
24731                    + self.gutter_dimensions.full_width(),
24732            ) - scroll_left,
24733        );
24734        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24735
24736        Some(Bounds {
24737            origin: element_bounds.origin + point(x, y),
24738            size: size(em_width, line_height),
24739        })
24740    }
24741
24742    fn character_index_for_point(
24743        &mut self,
24744        point: gpui::Point<Pixels>,
24745        _window: &mut Window,
24746        _cx: &mut Context<Self>,
24747    ) -> Option<usize> {
24748        let position_map = self.last_position_map.as_ref()?;
24749        if !position_map.text_hitbox.contains(&point) {
24750            return None;
24751        }
24752        let display_point = position_map.point_for_position(point).previous_valid;
24753        let anchor = position_map
24754            .snapshot
24755            .display_point_to_anchor(display_point, Bias::Left);
24756        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24757        Some(utf16_offset.0.0)
24758    }
24759
24760    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24761        self.input_enabled
24762    }
24763}
24764
24765trait SelectionExt {
24766    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24767    fn spanned_rows(
24768        &self,
24769        include_end_if_at_line_start: bool,
24770        map: &DisplaySnapshot,
24771    ) -> Range<MultiBufferRow>;
24772}
24773
24774impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24775    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24776        let start = self
24777            .start
24778            .to_point(map.buffer_snapshot())
24779            .to_display_point(map);
24780        let end = self
24781            .end
24782            .to_point(map.buffer_snapshot())
24783            .to_display_point(map);
24784        if self.reversed {
24785            end..start
24786        } else {
24787            start..end
24788        }
24789    }
24790
24791    fn spanned_rows(
24792        &self,
24793        include_end_if_at_line_start: bool,
24794        map: &DisplaySnapshot,
24795    ) -> Range<MultiBufferRow> {
24796        let start = self.start.to_point(map.buffer_snapshot());
24797        let mut end = self.end.to_point(map.buffer_snapshot());
24798        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24799            end.row -= 1;
24800        }
24801
24802        let buffer_start = map.prev_line_boundary(start).0;
24803        let buffer_end = map.next_line_boundary(end).0;
24804        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24805    }
24806}
24807
24808impl<T: InvalidationRegion> InvalidationStack<T> {
24809    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24810    where
24811        S: Clone + ToOffset,
24812    {
24813        while let Some(region) = self.last() {
24814            let all_selections_inside_invalidation_ranges =
24815                if selections.len() == region.ranges().len() {
24816                    selections
24817                        .iter()
24818                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24819                        .all(|(selection, invalidation_range)| {
24820                            let head = selection.head().to_offset(buffer);
24821                            invalidation_range.start <= head && invalidation_range.end >= head
24822                        })
24823                } else {
24824                    false
24825                };
24826
24827            if all_selections_inside_invalidation_ranges {
24828                break;
24829            } else {
24830                self.pop();
24831            }
24832        }
24833    }
24834}
24835
24836impl<T> Default for InvalidationStack<T> {
24837    fn default() -> Self {
24838        Self(Default::default())
24839    }
24840}
24841
24842impl<T> Deref for InvalidationStack<T> {
24843    type Target = Vec<T>;
24844
24845    fn deref(&self) -> &Self::Target {
24846        &self.0
24847    }
24848}
24849
24850impl<T> DerefMut for InvalidationStack<T> {
24851    fn deref_mut(&mut self) -> &mut Self::Target {
24852        &mut self.0
24853    }
24854}
24855
24856impl InvalidationRegion for SnippetState {
24857    fn ranges(&self) -> &[Range<Anchor>] {
24858        &self.ranges[self.active_index]
24859    }
24860}
24861
24862fn edit_prediction_edit_text(
24863    current_snapshot: &BufferSnapshot,
24864    edits: &[(Range<Anchor>, impl AsRef<str>)],
24865    edit_preview: &EditPreview,
24866    include_deletions: bool,
24867    cx: &App,
24868) -> HighlightedText {
24869    let edits = edits
24870        .iter()
24871        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24872        .collect::<Vec<_>>();
24873
24874    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24875}
24876
24877fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24878    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24879    // Just show the raw edit text with basic styling
24880    let mut text = String::new();
24881    let mut highlights = Vec::new();
24882
24883    let insertion_highlight_style = HighlightStyle {
24884        color: Some(cx.theme().colors().text),
24885        ..Default::default()
24886    };
24887
24888    for (_, edit_text) in edits {
24889        let start_offset = text.len();
24890        text.push_str(edit_text);
24891        let end_offset = text.len();
24892
24893        if start_offset < end_offset {
24894            highlights.push((start_offset..end_offset, insertion_highlight_style));
24895        }
24896    }
24897
24898    HighlightedText {
24899        text: text.into(),
24900        highlights,
24901    }
24902}
24903
24904pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24905    match severity {
24906        lsp::DiagnosticSeverity::ERROR => colors.error,
24907        lsp::DiagnosticSeverity::WARNING => colors.warning,
24908        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24909        lsp::DiagnosticSeverity::HINT => colors.info,
24910        _ => colors.ignored,
24911    }
24912}
24913
24914pub fn styled_runs_for_code_label<'a>(
24915    label: &'a CodeLabel,
24916    syntax_theme: &'a theme::SyntaxTheme,
24917) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24918    let fade_out = HighlightStyle {
24919        fade_out: Some(0.35),
24920        ..Default::default()
24921    };
24922
24923    let mut prev_end = label.filter_range.end;
24924    label
24925        .runs
24926        .iter()
24927        .enumerate()
24928        .flat_map(move |(ix, (range, highlight_id))| {
24929            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24930                style
24931            } else {
24932                return Default::default();
24933            };
24934            let muted_style = style.highlight(fade_out);
24935
24936            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24937            if range.start >= label.filter_range.end {
24938                if range.start > prev_end {
24939                    runs.push((prev_end..range.start, fade_out));
24940                }
24941                runs.push((range.clone(), muted_style));
24942            } else if range.end <= label.filter_range.end {
24943                runs.push((range.clone(), style));
24944            } else {
24945                runs.push((range.start..label.filter_range.end, style));
24946                runs.push((label.filter_range.end..range.end, muted_style));
24947            }
24948            prev_end = cmp::max(prev_end, range.end);
24949
24950            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24951                runs.push((prev_end..label.text.len(), fade_out));
24952            }
24953
24954            runs
24955        })
24956}
24957
24958pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24959    let mut prev_index = 0;
24960    let mut prev_codepoint: Option<char> = None;
24961    text.char_indices()
24962        .chain([(text.len(), '\0')])
24963        .filter_map(move |(index, codepoint)| {
24964            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24965            let is_boundary = index == text.len()
24966                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24967                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24968            if is_boundary {
24969                let chunk = &text[prev_index..index];
24970                prev_index = index;
24971                Some(chunk)
24972            } else {
24973                None
24974            }
24975        })
24976}
24977
24978/// Given a string of text immediately before the cursor, iterates over possible
24979/// strings a snippet could match to. More precisely: returns an iterator over
24980/// suffixes of `text` created by splitting at word boundaries (before & after
24981/// every non-word character).
24982///
24983/// Shorter suffixes are returned first.
24984pub(crate) fn snippet_candidate_suffixes(
24985    text: &str,
24986    is_word_char: impl Fn(char) -> bool,
24987) -> impl std::iter::Iterator<Item = &str> {
24988    let mut prev_index = text.len();
24989    let mut prev_codepoint = None;
24990    text.char_indices()
24991        .rev()
24992        .chain([(0, '\0')])
24993        .filter_map(move |(index, codepoint)| {
24994            let prev_index = std::mem::replace(&mut prev_index, index);
24995            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24996            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24997                None
24998            } else {
24999                let chunk = &text[prev_index..]; // go to end of string
25000                Some(chunk)
25001            }
25002        })
25003}
25004
25005pub trait RangeToAnchorExt: Sized {
25006    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25007
25008    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25009        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25010        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25011    }
25012}
25013
25014impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25015    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25016        let start_offset = self.start.to_offset(snapshot);
25017        let end_offset = self.end.to_offset(snapshot);
25018        if start_offset == end_offset {
25019            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25020        } else {
25021            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25022        }
25023    }
25024}
25025
25026pub trait RowExt {
25027    fn as_f64(&self) -> f64;
25028
25029    fn next_row(&self) -> Self;
25030
25031    fn previous_row(&self) -> Self;
25032
25033    fn minus(&self, other: Self) -> u32;
25034}
25035
25036impl RowExt for DisplayRow {
25037    fn as_f64(&self) -> f64 {
25038        self.0 as _
25039    }
25040
25041    fn next_row(&self) -> Self {
25042        Self(self.0 + 1)
25043    }
25044
25045    fn previous_row(&self) -> Self {
25046        Self(self.0.saturating_sub(1))
25047    }
25048
25049    fn minus(&self, other: Self) -> u32 {
25050        self.0 - other.0
25051    }
25052}
25053
25054impl RowExt for MultiBufferRow {
25055    fn as_f64(&self) -> f64 {
25056        self.0 as _
25057    }
25058
25059    fn next_row(&self) -> Self {
25060        Self(self.0 + 1)
25061    }
25062
25063    fn previous_row(&self) -> Self {
25064        Self(self.0.saturating_sub(1))
25065    }
25066
25067    fn minus(&self, other: Self) -> u32 {
25068        self.0 - other.0
25069    }
25070}
25071
25072trait RowRangeExt {
25073    type Row;
25074
25075    fn len(&self) -> usize;
25076
25077    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25078}
25079
25080impl RowRangeExt for Range<MultiBufferRow> {
25081    type Row = MultiBufferRow;
25082
25083    fn len(&self) -> usize {
25084        (self.end.0 - self.start.0) as usize
25085    }
25086
25087    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25088        (self.start.0..self.end.0).map(MultiBufferRow)
25089    }
25090}
25091
25092impl RowRangeExt for Range<DisplayRow> {
25093    type Row = DisplayRow;
25094
25095    fn len(&self) -> usize {
25096        (self.end.0 - self.start.0) as usize
25097    }
25098
25099    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25100        (self.start.0..self.end.0).map(DisplayRow)
25101    }
25102}
25103
25104/// If select range has more than one line, we
25105/// just point the cursor to range.start.
25106fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25107    if range.start.row == range.end.row {
25108        range
25109    } else {
25110        range.start..range.start
25111    }
25112}
25113pub struct KillRing(ClipboardItem);
25114impl Global for KillRing {}
25115
25116const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25117
25118enum BreakpointPromptEditAction {
25119    Log,
25120    Condition,
25121    HitCondition,
25122}
25123
25124struct BreakpointPromptEditor {
25125    pub(crate) prompt: Entity<Editor>,
25126    editor: WeakEntity<Editor>,
25127    breakpoint_anchor: Anchor,
25128    breakpoint: Breakpoint,
25129    edit_action: BreakpointPromptEditAction,
25130    block_ids: HashSet<CustomBlockId>,
25131    editor_margins: Arc<Mutex<EditorMargins>>,
25132    _subscriptions: Vec<Subscription>,
25133}
25134
25135impl BreakpointPromptEditor {
25136    const MAX_LINES: u8 = 4;
25137
25138    fn new(
25139        editor: WeakEntity<Editor>,
25140        breakpoint_anchor: Anchor,
25141        breakpoint: Breakpoint,
25142        edit_action: BreakpointPromptEditAction,
25143        window: &mut Window,
25144        cx: &mut Context<Self>,
25145    ) -> Self {
25146        let base_text = match edit_action {
25147            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25148            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25149            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25150        }
25151        .map(|msg| msg.to_string())
25152        .unwrap_or_default();
25153
25154        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25155        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25156
25157        let prompt = cx.new(|cx| {
25158            let mut prompt = Editor::new(
25159                EditorMode::AutoHeight {
25160                    min_lines: 1,
25161                    max_lines: Some(Self::MAX_LINES as usize),
25162                },
25163                buffer,
25164                None,
25165                window,
25166                cx,
25167            );
25168            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25169            prompt.set_show_cursor_when_unfocused(false, cx);
25170            prompt.set_placeholder_text(
25171                match edit_action {
25172                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25173                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25174                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25175                },
25176                window,
25177                cx,
25178            );
25179
25180            prompt
25181        });
25182
25183        Self {
25184            prompt,
25185            editor,
25186            breakpoint_anchor,
25187            breakpoint,
25188            edit_action,
25189            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25190            block_ids: Default::default(),
25191            _subscriptions: vec![],
25192        }
25193    }
25194
25195    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25196        self.block_ids.extend(block_ids)
25197    }
25198
25199    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25200        if let Some(editor) = self.editor.upgrade() {
25201            let message = self
25202                .prompt
25203                .read(cx)
25204                .buffer
25205                .read(cx)
25206                .as_singleton()
25207                .expect("A multi buffer in breakpoint prompt isn't possible")
25208                .read(cx)
25209                .as_rope()
25210                .to_string();
25211
25212            editor.update(cx, |editor, cx| {
25213                editor.edit_breakpoint_at_anchor(
25214                    self.breakpoint_anchor,
25215                    self.breakpoint.clone(),
25216                    match self.edit_action {
25217                        BreakpointPromptEditAction::Log => {
25218                            BreakpointEditAction::EditLogMessage(message.into())
25219                        }
25220                        BreakpointPromptEditAction::Condition => {
25221                            BreakpointEditAction::EditCondition(message.into())
25222                        }
25223                        BreakpointPromptEditAction::HitCondition => {
25224                            BreakpointEditAction::EditHitCondition(message.into())
25225                        }
25226                    },
25227                    cx,
25228                );
25229
25230                editor.remove_blocks(self.block_ids.clone(), None, cx);
25231                cx.focus_self(window);
25232            });
25233        }
25234    }
25235
25236    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25237        self.editor
25238            .update(cx, |editor, cx| {
25239                editor.remove_blocks(self.block_ids.clone(), None, cx);
25240                window.focus(&editor.focus_handle);
25241            })
25242            .log_err();
25243    }
25244
25245    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25246        let settings = ThemeSettings::get_global(cx);
25247        let text_style = TextStyle {
25248            color: if self.prompt.read(cx).read_only(cx) {
25249                cx.theme().colors().text_disabled
25250            } else {
25251                cx.theme().colors().text
25252            },
25253            font_family: settings.buffer_font.family.clone(),
25254            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25255            font_size: settings.buffer_font_size(cx).into(),
25256            font_weight: settings.buffer_font.weight,
25257            line_height: relative(settings.buffer_line_height.value()),
25258            ..Default::default()
25259        };
25260        EditorElement::new(
25261            &self.prompt,
25262            EditorStyle {
25263                background: cx.theme().colors().editor_background,
25264                local_player: cx.theme().players().local(),
25265                text: text_style,
25266                ..Default::default()
25267            },
25268        )
25269    }
25270}
25271
25272impl Render for BreakpointPromptEditor {
25273    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25274        let editor_margins = *self.editor_margins.lock();
25275        let gutter_dimensions = editor_margins.gutter;
25276        h_flex()
25277            .key_context("Editor")
25278            .bg(cx.theme().colors().editor_background)
25279            .border_y_1()
25280            .border_color(cx.theme().status().info_border)
25281            .size_full()
25282            .py(window.line_height() / 2.5)
25283            .on_action(cx.listener(Self::confirm))
25284            .on_action(cx.listener(Self::cancel))
25285            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25286            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25287    }
25288}
25289
25290impl Focusable for BreakpointPromptEditor {
25291    fn focus_handle(&self, cx: &App) -> FocusHandle {
25292        self.prompt.focus_handle(cx)
25293    }
25294}
25295
25296fn all_edits_insertions_or_deletions(
25297    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25298    snapshot: &MultiBufferSnapshot,
25299) -> bool {
25300    let mut all_insertions = true;
25301    let mut all_deletions = true;
25302
25303    for (range, new_text) in edits.iter() {
25304        let range_is_empty = range.to_offset(snapshot).is_empty();
25305        let text_is_empty = new_text.is_empty();
25306
25307        if range_is_empty != text_is_empty {
25308            if range_is_empty {
25309                all_deletions = false;
25310            } else {
25311                all_insertions = false;
25312            }
25313        } else {
25314            return false;
25315        }
25316
25317        if !all_insertions && !all_deletions {
25318            return false;
25319        }
25320    }
25321    all_insertions || all_deletions
25322}
25323
25324struct MissingEditPredictionKeybindingTooltip;
25325
25326impl Render for MissingEditPredictionKeybindingTooltip {
25327    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25328        ui::tooltip_container(cx, |container, cx| {
25329            container
25330                .flex_shrink_0()
25331                .max_w_80()
25332                .min_h(rems_from_px(124.))
25333                .justify_between()
25334                .child(
25335                    v_flex()
25336                        .flex_1()
25337                        .text_ui_sm(cx)
25338                        .child(Label::new("Conflict with Accept Keybinding"))
25339                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25340                )
25341                .child(
25342                    h_flex()
25343                        .pb_1()
25344                        .gap_1()
25345                        .items_end()
25346                        .w_full()
25347                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25348                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25349                        }))
25350                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25351                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25352                        })),
25353                )
25354        })
25355    }
25356}
25357
25358#[derive(Debug, Clone, Copy, PartialEq)]
25359pub struct LineHighlight {
25360    pub background: Background,
25361    pub border: Option<gpui::Hsla>,
25362    pub include_gutter: bool,
25363    pub type_id: Option<TypeId>,
25364}
25365
25366struct LineManipulationResult {
25367    pub new_text: String,
25368    pub line_count_before: usize,
25369    pub line_count_after: usize,
25370}
25371
25372fn render_diff_hunk_controls(
25373    row: u32,
25374    status: &DiffHunkStatus,
25375    hunk_range: Range<Anchor>,
25376    is_created_file: bool,
25377    line_height: Pixels,
25378    editor: &Entity<Editor>,
25379    _window: &mut Window,
25380    cx: &mut App,
25381) -> AnyElement {
25382    h_flex()
25383        .h(line_height)
25384        .mr_1()
25385        .gap_1()
25386        .px_0p5()
25387        .pb_1()
25388        .border_x_1()
25389        .border_b_1()
25390        .border_color(cx.theme().colors().border_variant)
25391        .rounded_b_lg()
25392        .bg(cx.theme().colors().editor_background)
25393        .gap_1()
25394        .block_mouse_except_scroll()
25395        .shadow_md()
25396        .child(if status.has_secondary_hunk() {
25397            Button::new(("stage", row as u64), "Stage")
25398                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25399                .tooltip({
25400                    let focus_handle = editor.focus_handle(cx);
25401                    move |_window, cx| {
25402                        Tooltip::for_action_in(
25403                            "Stage Hunk",
25404                            &::git::ToggleStaged,
25405                            &focus_handle,
25406                            cx,
25407                        )
25408                    }
25409                })
25410                .on_click({
25411                    let editor = editor.clone();
25412                    move |_event, _window, cx| {
25413                        editor.update(cx, |editor, cx| {
25414                            editor.stage_or_unstage_diff_hunks(
25415                                true,
25416                                vec![hunk_range.start..hunk_range.start],
25417                                cx,
25418                            );
25419                        });
25420                    }
25421                })
25422        } else {
25423            Button::new(("unstage", row as u64), "Unstage")
25424                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25425                .tooltip({
25426                    let focus_handle = editor.focus_handle(cx);
25427                    move |_window, cx| {
25428                        Tooltip::for_action_in(
25429                            "Unstage Hunk",
25430                            &::git::ToggleStaged,
25431                            &focus_handle,
25432                            cx,
25433                        )
25434                    }
25435                })
25436                .on_click({
25437                    let editor = editor.clone();
25438                    move |_event, _window, cx| {
25439                        editor.update(cx, |editor, cx| {
25440                            editor.stage_or_unstage_diff_hunks(
25441                                false,
25442                                vec![hunk_range.start..hunk_range.start],
25443                                cx,
25444                            );
25445                        });
25446                    }
25447                })
25448        })
25449        .child(
25450            Button::new(("restore", row as u64), "Restore")
25451                .tooltip({
25452                    let focus_handle = editor.focus_handle(cx);
25453                    move |_window, cx| {
25454                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25455                    }
25456                })
25457                .on_click({
25458                    let editor = editor.clone();
25459                    move |_event, window, cx| {
25460                        editor.update(cx, |editor, cx| {
25461                            let snapshot = editor.snapshot(window, cx);
25462                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25463                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25464                        });
25465                    }
25466                })
25467                .disabled(is_created_file),
25468        )
25469        .when(
25470            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25471            |el| {
25472                el.child(
25473                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25474                        .shape(IconButtonShape::Square)
25475                        .icon_size(IconSize::Small)
25476                        // .disabled(!has_multiple_hunks)
25477                        .tooltip({
25478                            let focus_handle = editor.focus_handle(cx);
25479                            move |_window, cx| {
25480                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25481                            }
25482                        })
25483                        .on_click({
25484                            let editor = editor.clone();
25485                            move |_event, window, cx| {
25486                                editor.update(cx, |editor, cx| {
25487                                    let snapshot = editor.snapshot(window, cx);
25488                                    let position =
25489                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25490                                    editor.go_to_hunk_before_or_after_position(
25491                                        &snapshot,
25492                                        position,
25493                                        Direction::Next,
25494                                        window,
25495                                        cx,
25496                                    );
25497                                    editor.expand_selected_diff_hunks(cx);
25498                                });
25499                            }
25500                        }),
25501                )
25502                .child(
25503                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25504                        .shape(IconButtonShape::Square)
25505                        .icon_size(IconSize::Small)
25506                        // .disabled(!has_multiple_hunks)
25507                        .tooltip({
25508                            let focus_handle = editor.focus_handle(cx);
25509                            move |_window, cx| {
25510                                Tooltip::for_action_in(
25511                                    "Previous Hunk",
25512                                    &GoToPreviousHunk,
25513                                    &focus_handle,
25514                                    cx,
25515                                )
25516                            }
25517                        })
25518                        .on_click({
25519                            let editor = editor.clone();
25520                            move |_event, window, cx| {
25521                                editor.update(cx, |editor, cx| {
25522                                    let snapshot = editor.snapshot(window, cx);
25523                                    let point =
25524                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25525                                    editor.go_to_hunk_before_or_after_position(
25526                                        &snapshot,
25527                                        point,
25528                                        Direction::Prev,
25529                                        window,
25530                                        cx,
25531                                    );
25532                                    editor.expand_selected_diff_hunks(cx);
25533                                });
25534                            }
25535                        }),
25536                )
25537            },
25538        )
25539        .into_any_element()
25540}
25541
25542pub fn multibuffer_context_lines(cx: &App) -> u32 {
25543    EditorSettings::try_get(cx)
25544        .map(|settings| settings.excerpt_context_lines)
25545        .unwrap_or(2)
25546        .min(32)
25547}