editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  111    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle,
  112    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  113    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  125    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  149    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  150    ProjectPath, ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::GitStoreEvent,
  159    lsp_store::{
  160        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  161        OpenLspBufferHandle,
  162    },
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  169use serde::{Deserialize, Serialize};
  170use settings::{
  171    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  172    update_settings_file,
  173};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    collections::hash_map,
  182    iter::{self, Peekable},
  183    mem,
  184    num::NonZeroU32,
  185    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  193use theme::{
  194    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    inlays::{
  216        InlineValueCache,
  217        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  218    },
  219    scroll::{ScrollOffset, ScrollPixelOffset},
  220    selections_collection::resolve_selections_wrapping_blocks,
  221    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  222};
  223
  224pub const FILE_HEADER_HEIGHT: u32 = 2;
  225pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  226const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  227const MAX_LINE_LEN: usize = 1024;
  228const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  229const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  230pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  231#[doc(hidden)]
  232pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  233pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  234
  235pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  238pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  239
  240pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  241pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  242pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  243
  244pub type RenderDiffHunkControlsFn = Arc<
  245    dyn Fn(
  246        u32,
  247        &DiffHunkStatus,
  248        Range<Anchor>,
  249        bool,
  250        Pixels,
  251        &Entity<Editor>,
  252        &mut Window,
  253        &mut App,
  254    ) -> AnyElement,
  255>;
  256
  257enum ReportEditorEvent {
  258    Saved { auto_saved: bool },
  259    EditorOpened,
  260    Closed,
  261}
  262
  263impl ReportEditorEvent {
  264    pub fn event_type(&self) -> &'static str {
  265        match self {
  266            Self::Saved { .. } => "Editor Saved",
  267            Self::EditorOpened => "Editor Opened",
  268            Self::Closed => "Editor Closed",
  269        }
  270    }
  271}
  272
  273pub enum ActiveDebugLine {}
  274pub enum DebugStackFrameLine {}
  275enum DocumentHighlightRead {}
  276enum DocumentHighlightWrite {}
  277enum InputComposition {}
  278pub enum PendingInput {}
  279enum SelectedTextHighlight {}
  280
  281pub enum ConflictsOuter {}
  282pub enum ConflictsOurs {}
  283pub enum ConflictsTheirs {}
  284pub enum ConflictsOursMarker {}
  285pub enum ConflictsTheirsMarker {}
  286
  287#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  288pub enum Navigated {
  289    Yes,
  290    No,
  291}
  292
  293impl Navigated {
  294    pub fn from_bool(yes: bool) -> Navigated {
  295        if yes { Navigated::Yes } else { Navigated::No }
  296    }
  297}
  298
  299#[derive(Debug, Clone, PartialEq, Eq)]
  300enum DisplayDiffHunk {
  301    Folded {
  302        display_row: DisplayRow,
  303    },
  304    Unfolded {
  305        is_created_file: bool,
  306        diff_base_byte_range: Range<usize>,
  307        display_row_range: Range<DisplayRow>,
  308        multi_buffer_range: Range<Anchor>,
  309        status: DiffHunkStatus,
  310    },
  311}
  312
  313pub enum HideMouseCursorOrigin {
  314    TypingAction,
  315    MovementAction,
  316}
  317
  318pub fn init(cx: &mut App) {
  319    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  320
  321    workspace::register_project_item::<Editor>(cx);
  322    workspace::FollowableViewRegistry::register::<Editor>(cx);
  323    workspace::register_serializable_item::<Editor>(cx);
  324
  325    cx.observe_new(
  326        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  327            workspace.register_action(Editor::new_file);
  328            workspace.register_action(Editor::new_file_split);
  329            workspace.register_action(Editor::new_file_vertical);
  330            workspace.register_action(Editor::new_file_horizontal);
  331            workspace.register_action(Editor::cancel_language_server_work);
  332            workspace.register_action(Editor::toggle_focus);
  333        },
  334    )
  335    .detach();
  336
  337    cx.on_action(move |_: &workspace::NewFile, cx| {
  338        let app_state = workspace::AppState::global(cx);
  339        if let Some(app_state) = app_state.upgrade() {
  340            workspace::open_new(
  341                Default::default(),
  342                app_state,
  343                cx,
  344                |workspace, window, cx| {
  345                    Editor::new_file(workspace, &Default::default(), window, cx)
  346                },
  347            )
  348            .detach();
  349        }
  350    });
  351    cx.on_action(move |_: &workspace::NewWindow, cx| {
  352        let app_state = workspace::AppState::global(cx);
  353        if let Some(app_state) = app_state.upgrade() {
  354            workspace::open_new(
  355                Default::default(),
  356                app_state,
  357                cx,
  358                |workspace, window, cx| {
  359                    cx.activate(true);
  360                    Editor::new_file(workspace, &Default::default(), window, cx)
  361                },
  362            )
  363            .detach();
  364        }
  365    });
  366}
  367
  368pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  369    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  370}
  371
  372pub trait DiagnosticRenderer {
  373    fn render_group(
  374        &self,
  375        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  376        buffer_id: BufferId,
  377        snapshot: EditorSnapshot,
  378        editor: WeakEntity<Editor>,
  379        language_registry: Option<Arc<LanguageRegistry>>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        language_registry: Option<Arc<LanguageRegistry>>,
  389        cx: &mut App,
  390    ) -> Option<Entity<markdown::Markdown>>;
  391
  392    fn open_link(
  393        &self,
  394        editor: &mut Editor,
  395        link: SharedString,
  396        window: &mut Window,
  397        cx: &mut Context<Editor>,
  398    );
  399}
  400
  401pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  402
  403impl GlobalDiagnosticRenderer {
  404    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  405        cx.try_global::<Self>().map(|g| g.0.clone())
  406    }
  407}
  408
  409impl gpui::Global for GlobalDiagnosticRenderer {}
  410pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  411    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  412}
  413
  414pub struct SearchWithinRange;
  415
  416trait InvalidationRegion {
  417    fn ranges(&self) -> &[Range<Anchor>];
  418}
  419
  420#[derive(Clone, Debug, PartialEq)]
  421pub enum SelectPhase {
  422    Begin {
  423        position: DisplayPoint,
  424        add: bool,
  425        click_count: usize,
  426    },
  427    BeginColumnar {
  428        position: DisplayPoint,
  429        reset: bool,
  430        mode: ColumnarMode,
  431        goal_column: u32,
  432    },
  433    Extend {
  434        position: DisplayPoint,
  435        click_count: usize,
  436    },
  437    Update {
  438        position: DisplayPoint,
  439        goal_column: u32,
  440        scroll_delta: gpui::Point<f32>,
  441    },
  442    End,
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum ColumnarMode {
  447    FromMouse,
  448    FromSelection,
  449}
  450
  451#[derive(Clone, Debug)]
  452pub enum SelectMode {
  453    Character,
  454    Word(Range<Anchor>),
  455    Line(Range<Anchor>),
  456    All,
  457}
  458
  459#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  460pub enum SizingBehavior {
  461    /// The editor will layout itself using `size_full` and will include the vertical
  462    /// scroll margin as requested by user settings.
  463    #[default]
  464    Default,
  465    /// The editor will layout itself using `size_full`, but will not have any
  466    /// vertical overscroll.
  467    ExcludeOverscrollMargin,
  468    /// The editor will request a vertical size according to its content and will be
  469    /// layouted without a vertical scroll margin.
  470    SizeByContent,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine,
  476    AutoHeight {
  477        min_lines: usize,
  478        max_lines: Option<usize>,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// Determines the sizing behavior for this editor
  486        sizing_behavior: SizingBehavior,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sizing_behavior: SizingBehavior::Default,
  499        }
  500    }
  501
  502    #[inline]
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    #[inline]
  508    pub fn is_single_line(&self) -> bool {
  509        matches!(self, Self::SingleLine { .. })
  510    }
  511
  512    #[inline]
  513    fn is_minimap(&self) -> bool {
  514        matches!(self, Self::Minimap { .. })
  515    }
  516}
  517
  518#[derive(Copy, Clone, Debug)]
  519pub enum SoftWrap {
  520    /// Prefer not to wrap at all.
  521    ///
  522    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  523    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  524    GitDiff,
  525    /// Prefer a single line generally, unless an overly long line is encountered.
  526    None,
  527    /// Soft wrap lines that exceed the editor width.
  528    EditorWidth,
  529    /// Soft wrap lines at the preferred line length.
  530    Column(u32),
  531    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  532    Bounded(u32),
  533}
  534
  535#[derive(Clone)]
  536pub struct EditorStyle {
  537    pub background: Hsla,
  538    pub border: Hsla,
  539    pub local_player: PlayerColor,
  540    pub text: TextStyle,
  541    pub scrollbar_width: Pixels,
  542    pub syntax: Arc<SyntaxTheme>,
  543    pub status: StatusColors,
  544    pub inlay_hints_style: HighlightStyle,
  545    pub edit_prediction_styles: EditPredictionStyles,
  546    pub unnecessary_code_fade: f32,
  547    pub show_underlines: bool,
  548}
  549
  550impl Default for EditorStyle {
  551    fn default() -> Self {
  552        Self {
  553            background: Hsla::default(),
  554            border: Hsla::default(),
  555            local_player: PlayerColor::default(),
  556            text: TextStyle::default(),
  557            scrollbar_width: Pixels::default(),
  558            syntax: Default::default(),
  559            // HACK: Status colors don't have a real default.
  560            // We should look into removing the status colors from the editor
  561            // style and retrieve them directly from the theme.
  562            status: StatusColors::dark(),
  563            inlay_hints_style: HighlightStyle::default(),
  564            edit_prediction_styles: EditPredictionStyles {
  565                insertion: HighlightStyle::default(),
  566                whitespace: HighlightStyle::default(),
  567            },
  568            unnecessary_code_fade: Default::default(),
  569            show_underlines: true,
  570        }
  571    }
  572}
  573
  574pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  575    let show_background = language_settings::language_settings(None, None, cx)
  576        .inlay_hints
  577        .show_background;
  578
  579    let mut style = cx.theme().syntax().get("hint");
  580
  581    if style.color.is_none() {
  582        style.color = Some(cx.theme().status().hint);
  583    }
  584
  585    if !show_background {
  586        style.background_color = None;
  587        return style;
  588    }
  589
  590    if style.background_color.is_none() {
  591        style.background_color = Some(cx.theme().status().hint_background);
  592    }
  593
  594    style
  595}
  596
  597pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  598    EditPredictionStyles {
  599        insertion: HighlightStyle {
  600            color: Some(cx.theme().status().predictive),
  601            ..HighlightStyle::default()
  602        },
  603        whitespace: HighlightStyle {
  604            background_color: Some(cx.theme().status().created_background),
  605            ..HighlightStyle::default()
  606        },
  607    }
  608}
  609
  610type CompletionId = usize;
  611
  612pub(crate) enum EditDisplayMode {
  613    TabAccept,
  614    DiffPopover,
  615    Inline,
  616}
  617
  618enum EditPrediction {
  619    Edit {
  620        edits: Vec<(Range<Anchor>, Arc<str>)>,
  621        edit_preview: Option<EditPreview>,
  622        display_mode: EditDisplayMode,
  623        snapshot: BufferSnapshot,
  624    },
  625    /// Move to a specific location in the active editor
  626    MoveWithin {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in a different editor (not the active one)
  631    MoveOutside {
  632        target: language::Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635}
  636
  637struct EditPredictionState {
  638    inlay_ids: Vec<InlayId>,
  639    completion: EditPrediction,
  640    completion_id: Option<SharedString>,
  641    invalidation_range: Option<Range<Anchor>>,
  642}
  643
  644enum EditPredictionSettings {
  645    Disabled,
  646    Enabled {
  647        show_in_menu: bool,
  648        preview_requires_modifier: bool,
  649    },
  650}
  651
  652enum EditPredictionHighlight {}
  653
  654#[derive(Debug, Clone)]
  655struct InlineDiagnostic {
  656    message: SharedString,
  657    group_id: usize,
  658    is_primary: bool,
  659    start: Point,
  660    severity: lsp::DiagnosticSeverity,
  661}
  662
  663pub enum MenuEditPredictionsPolicy {
  664    Never,
  665    ByProvider,
  666}
  667
  668pub enum EditPredictionPreview {
  669    /// Modifier is not pressed
  670    Inactive { released_too_fast: bool },
  671    /// Modifier pressed
  672    Active {
  673        since: Instant,
  674        previous_scroll_position: Option<ScrollAnchor>,
  675    },
  676}
  677
  678impl EditPredictionPreview {
  679    pub fn released_too_fast(&self) -> bool {
  680        match self {
  681            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  682            EditPredictionPreview::Active { .. } => false,
  683        }
  684    }
  685
  686    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  687        if let EditPredictionPreview::Active {
  688            previous_scroll_position,
  689            ..
  690        } = self
  691        {
  692            *previous_scroll_position = scroll_position;
  693        }
  694    }
  695}
  696
  697pub struct ContextMenuOptions {
  698    pub min_entries_visible: usize,
  699    pub max_entries_visible: usize,
  700    pub placement: Option<ContextMenuPlacement>,
  701}
  702
  703#[derive(Debug, Clone, PartialEq, Eq)]
  704pub enum ContextMenuPlacement {
  705    Above,
  706    Below,
  707}
  708
  709#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  710struct EditorActionId(usize);
  711
  712impl EditorActionId {
  713    pub fn post_inc(&mut self) -> Self {
  714        let answer = self.0;
  715
  716        *self = Self(answer + 1);
  717
  718        Self(answer)
  719    }
  720}
  721
  722// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  723// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  724
  725type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  726type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  727
  728#[derive(Default)]
  729struct ScrollbarMarkerState {
  730    scrollbar_size: Size<Pixels>,
  731    dirty: bool,
  732    markers: Arc<[PaintQuad]>,
  733    pending_refresh: Option<Task<Result<()>>>,
  734}
  735
  736impl ScrollbarMarkerState {
  737    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  738        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  739    }
  740}
  741
  742#[derive(Clone, Copy, PartialEq, Eq)]
  743pub enum MinimapVisibility {
  744    Disabled,
  745    Enabled {
  746        /// The configuration currently present in the users settings.
  747        setting_configuration: bool,
  748        /// Whether to override the currently set visibility from the users setting.
  749        toggle_override: bool,
  750    },
  751}
  752
  753impl MinimapVisibility {
  754    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  755        if mode.is_full() {
  756            Self::Enabled {
  757                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  758                toggle_override: false,
  759            }
  760        } else {
  761            Self::Disabled
  762        }
  763    }
  764
  765    fn hidden(&self) -> Self {
  766        match *self {
  767            Self::Enabled {
  768                setting_configuration,
  769                ..
  770            } => Self::Enabled {
  771                setting_configuration,
  772                toggle_override: setting_configuration,
  773            },
  774            Self::Disabled => Self::Disabled,
  775        }
  776    }
  777
  778    fn disabled(&self) -> bool {
  779        matches!(*self, Self::Disabled)
  780    }
  781
  782    fn settings_visibility(&self) -> bool {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => setting_configuration,
  788            _ => false,
  789        }
  790    }
  791
  792    fn visible(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                toggle_override,
  797            } => setting_configuration ^ toggle_override,
  798            _ => false,
  799        }
  800    }
  801
  802    fn toggle_visibility(&self) -> Self {
  803        match *self {
  804            Self::Enabled {
  805                toggle_override,
  806                setting_configuration,
  807            } => Self::Enabled {
  808                setting_configuration,
  809                toggle_override: !toggle_override,
  810            },
  811            Self::Disabled => Self::Disabled,
  812        }
  813    }
  814}
  815
  816#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  817pub enum BufferSerialization {
  818    All,
  819    NonDirtyBuffers,
  820}
  821
  822impl BufferSerialization {
  823    fn new(restore_unsaved_buffers: bool) -> Self {
  824        if restore_unsaved_buffers {
  825            Self::All
  826        } else {
  827            Self::NonDirtyBuffers
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863/// Addons allow storing per-editor state in other crates (e.g. Vim)
  864pub trait Addon: 'static {
  865    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  866
  867    fn render_buffer_header_controls(
  868        &self,
  869        _: &ExcerptInfo,
  870        _: &Window,
  871        _: &App,
  872    ) -> Option<AnyElement> {
  873        None
  874    }
  875
  876    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  877        None
  878    }
  879
  880    fn to_any(&self) -> &dyn std::any::Any;
  881
  882    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  883        None
  884    }
  885}
  886
  887struct ChangeLocation {
  888    current: Option<Vec<Anchor>>,
  889    original: Vec<Anchor>,
  890}
  891impl ChangeLocation {
  892    fn locations(&self) -> &[Anchor] {
  893        self.current.as_ref().unwrap_or(&self.original)
  894    }
  895}
  896
  897/// A set of caret positions, registered when the editor was edited.
  898pub struct ChangeList {
  899    changes: Vec<ChangeLocation>,
  900    /// Currently "selected" change.
  901    position: Option<usize>,
  902}
  903
  904impl ChangeList {
  905    pub fn new() -> Self {
  906        Self {
  907            changes: Vec::new(),
  908            position: None,
  909        }
  910    }
  911
  912    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  913    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  914    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  915        if self.changes.is_empty() {
  916            return None;
  917        }
  918
  919        let prev = self.position.unwrap_or(self.changes.len());
  920        let next = if direction == Direction::Prev {
  921            prev.saturating_sub(count)
  922        } else {
  923            (prev + count).min(self.changes.len() - 1)
  924        };
  925        self.position = Some(next);
  926        self.changes.get(next).map(|change| change.locations())
  927    }
  928
  929    /// Adds a new change to the list, resetting the change list position.
  930    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  931        self.position.take();
  932        if let Some(last) = self.changes.last_mut()
  933            && group
  934        {
  935            last.current = Some(new_positions)
  936        } else {
  937            self.changes.push(ChangeLocation {
  938                original: new_positions,
  939                current: None,
  940            });
  941        }
  942    }
  943
  944    pub fn last(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.locations())
  946    }
  947
  948    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.original.as_slice())
  950    }
  951
  952    pub fn invert_last_group(&mut self) {
  953        if let Some(last) = self.changes.last_mut()
  954            && let Some(current) = last.current.as_mut()
  955        {
  956            mem::swap(&mut last.original, current);
  957        }
  958    }
  959}
  960
  961#[derive(Clone)]
  962struct InlineBlamePopoverState {
  963    scroll_handle: ScrollHandle,
  964    commit_message: Option<ParsedCommitMessage>,
  965    markdown: Entity<Markdown>,
  966}
  967
  968struct InlineBlamePopover {
  969    position: gpui::Point<Pixels>,
  970    hide_task: Option<Task<()>>,
  971    popover_bounds: Option<Bounds<Pixels>>,
  972    popover_state: InlineBlamePopoverState,
  973    keyboard_grace: bool,
  974}
  975
  976enum SelectionDragState {
  977    /// State when no drag related activity is detected.
  978    None,
  979    /// State when the mouse is down on a selection that is about to be dragged.
  980    ReadyToDrag {
  981        selection: Selection<Anchor>,
  982        click_position: gpui::Point<Pixels>,
  983        mouse_down_time: Instant,
  984    },
  985    /// State when the mouse is dragging the selection in the editor.
  986    Dragging {
  987        selection: Selection<Anchor>,
  988        drop_cursor: Selection<Anchor>,
  989        hide_drop_cursor: bool,
  990    },
  991}
  992
  993enum ColumnarSelectionState {
  994    FromMouse {
  995        selection_tail: Anchor,
  996        display_point: Option<DisplayPoint>,
  997    },
  998    FromSelection {
  999        selection_tail: Anchor,
 1000    },
 1001}
 1002
 1003/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1004/// a breakpoint on them.
 1005#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1006struct PhantomBreakpointIndicator {
 1007    display_row: DisplayRow,
 1008    /// There's a small debounce between hovering over the line and showing the indicator.
 1009    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1010    is_active: bool,
 1011    collides_with_existing_breakpoint: bool,
 1012}
 1013
 1014/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1015///
 1016/// See the [module level documentation](self) for more information.
 1017pub struct Editor {
 1018    focus_handle: FocusHandle,
 1019    last_focused_descendant: Option<WeakFocusHandle>,
 1020    /// The text buffer being edited
 1021    buffer: Entity<MultiBuffer>,
 1022    /// Map of how text in the buffer should be displayed.
 1023    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1024    pub display_map: Entity<DisplayMap>,
 1025    placeholder_display_map: Option<Entity<DisplayMap>>,
 1026    pub selections: SelectionsCollection,
 1027    pub scroll_manager: ScrollManager,
 1028    /// When inline assist editors are linked, they all render cursors because
 1029    /// typing enters text into each of them, even the ones that aren't focused.
 1030    pub(crate) show_cursor_when_unfocused: bool,
 1031    columnar_selection_state: Option<ColumnarSelectionState>,
 1032    add_selections_state: Option<AddSelectionsState>,
 1033    select_next_state: Option<SelectNextState>,
 1034    select_prev_state: Option<SelectNextState>,
 1035    selection_history: SelectionHistory,
 1036    defer_selection_effects: bool,
 1037    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1038    autoclose_regions: Vec<AutocloseRegion>,
 1039    snippet_stack: InvalidationStack<SnippetState>,
 1040    select_syntax_node_history: SelectSyntaxNodeHistory,
 1041    ime_transaction: Option<TransactionId>,
 1042    pub diagnostics_max_severity: DiagnosticSeverity,
 1043    active_diagnostics: ActiveDiagnostic,
 1044    show_inline_diagnostics: bool,
 1045    inline_diagnostics_update: Task<()>,
 1046    inline_diagnostics_enabled: bool,
 1047    diagnostics_enabled: bool,
 1048    word_completions_enabled: bool,
 1049    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1050    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1051    hard_wrap: Option<usize>,
 1052    project: Option<Entity<Project>>,
 1053    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1054    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1055    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1056    blink_manager: Entity<BlinkManager>,
 1057    show_cursor_names: bool,
 1058    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1059    pub show_local_selections: bool,
 1060    mode: EditorMode,
 1061    show_breadcrumbs: bool,
 1062    show_gutter: bool,
 1063    show_scrollbars: ScrollbarAxes,
 1064    minimap_visibility: MinimapVisibility,
 1065    offset_content: bool,
 1066    disable_expand_excerpt_buttons: bool,
 1067    show_line_numbers: Option<bool>,
 1068    use_relative_line_numbers: Option<bool>,
 1069    show_git_diff_gutter: Option<bool>,
 1070    show_code_actions: Option<bool>,
 1071    show_runnables: Option<bool>,
 1072    show_breakpoints: Option<bool>,
 1073    show_wrap_guides: Option<bool>,
 1074    show_indent_guides: Option<bool>,
 1075    highlight_order: usize,
 1076    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1077    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1078    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1079    scrollbar_marker_state: ScrollbarMarkerState,
 1080    active_indent_guides_state: ActiveIndentGuidesState,
 1081    nav_history: Option<ItemNavHistory>,
 1082    context_menu: RefCell<Option<CodeContextMenu>>,
 1083    context_menu_options: Option<ContextMenuOptions>,
 1084    mouse_context_menu: Option<MouseContextMenu>,
 1085    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1086    inline_blame_popover: Option<InlineBlamePopover>,
 1087    inline_blame_popover_show_task: Option<Task<()>>,
 1088    signature_help_state: SignatureHelpState,
 1089    auto_signature_help: Option<bool>,
 1090    find_all_references_task_sources: Vec<Anchor>,
 1091    next_completion_id: CompletionId,
 1092    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1093    code_actions_task: Option<Task<Result<()>>>,
 1094    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1096    document_highlights_task: Option<Task<()>>,
 1097    linked_editing_range_task: Option<Task<Option<()>>>,
 1098    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1099    pending_rename: Option<RenameState>,
 1100    searchable: bool,
 1101    cursor_shape: CursorShape,
 1102    current_line_highlight: Option<CurrentLineHighlight>,
 1103    pub collapse_matches: bool,
 1104    autoindent_mode: Option<AutoindentMode>,
 1105    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1106    input_enabled: bool,
 1107    use_modal_editing: bool,
 1108    read_only: bool,
 1109    leader_id: Option<CollaboratorId>,
 1110    remote_id: Option<ViewId>,
 1111    pub hover_state: HoverState,
 1112    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1113    gutter_hovered: bool,
 1114    hovered_link_state: Option<HoveredLinkState>,
 1115    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1116    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1117    active_edit_prediction: Option<EditPredictionState>,
 1118    /// Used to prevent flickering as the user types while the menu is open
 1119    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1120    edit_prediction_settings: EditPredictionSettings,
 1121    edit_predictions_hidden_for_vim_mode: bool,
 1122    show_edit_predictions_override: Option<bool>,
 1123    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1124    edit_prediction_preview: EditPredictionPreview,
 1125    edit_prediction_indent_conflict: bool,
 1126    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1127    next_inlay_id: usize,
 1128    next_color_inlay_id: usize,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    buffer_serialization: Option<BufferSerialization>,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    post_scroll_update: Task<()>,
 1195    refresh_colors_task: Task<()>,
 1196    inlay_hints: Option<LspInlayHintData>,
 1197    folding_newlines: Task<()>,
 1198    select_next_is_case_sensitive: Option<bool>,
 1199    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1200    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1201    accent_overrides: Vec<SharedString>,
 1202    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1203    use_base_text_line_numbers: bool,
 1204}
 1205
 1206fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1207    if debounce_ms > 0 {
 1208        Some(Duration::from_millis(debounce_ms))
 1209    } else {
 1210        None
 1211    }
 1212}
 1213
 1214#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1215enum NextScrollCursorCenterTopBottom {
 1216    #[default]
 1217    Center,
 1218    Top,
 1219    Bottom,
 1220}
 1221
 1222impl NextScrollCursorCenterTopBottom {
 1223    fn next(&self) -> Self {
 1224        match self {
 1225            Self::Center => Self::Top,
 1226            Self::Top => Self::Bottom,
 1227            Self::Bottom => Self::Center,
 1228        }
 1229    }
 1230}
 1231
 1232#[derive(Clone)]
 1233pub struct EditorSnapshot {
 1234    pub mode: EditorMode,
 1235    show_gutter: bool,
 1236    show_line_numbers: Option<bool>,
 1237    show_git_diff_gutter: Option<bool>,
 1238    show_code_actions: Option<bool>,
 1239    show_runnables: Option<bool>,
 1240    show_breakpoints: Option<bool>,
 1241    git_blame_gutter_max_author_length: Option<usize>,
 1242    pub display_snapshot: DisplaySnapshot,
 1243    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1244    is_focused: bool,
 1245    scroll_anchor: ScrollAnchor,
 1246    ongoing_scroll: OngoingScroll,
 1247    current_line_highlight: CurrentLineHighlight,
 1248    gutter_hovered: bool,
 1249}
 1250
 1251#[derive(Default, Debug, Clone, Copy)]
 1252pub struct GutterDimensions {
 1253    pub left_padding: Pixels,
 1254    pub right_padding: Pixels,
 1255    pub width: Pixels,
 1256    pub margin: Pixels,
 1257    pub git_blame_entries_width: Option<Pixels>,
 1258}
 1259
 1260impl GutterDimensions {
 1261    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1262        Self {
 1263            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1264            ..Default::default()
 1265        }
 1266    }
 1267
 1268    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1269        -cx.text_system().descent(font_id, font_size)
 1270    }
 1271    /// The full width of the space taken up by the gutter.
 1272    pub fn full_width(&self) -> Pixels {
 1273        self.margin + self.width
 1274    }
 1275
 1276    /// The width of the space reserved for the fold indicators,
 1277    /// use alongside 'justify_end' and `gutter_width` to
 1278    /// right align content with the line numbers
 1279    pub fn fold_area_width(&self) -> Pixels {
 1280        self.margin + self.right_padding
 1281    }
 1282}
 1283
 1284struct CharacterDimensions {
 1285    em_width: Pixels,
 1286    em_advance: Pixels,
 1287    line_height: Pixels,
 1288}
 1289
 1290#[derive(Debug)]
 1291pub struct RemoteSelection {
 1292    pub replica_id: ReplicaId,
 1293    pub selection: Selection<Anchor>,
 1294    pub cursor_shape: CursorShape,
 1295    pub collaborator_id: CollaboratorId,
 1296    pub line_mode: bool,
 1297    pub user_name: Option<SharedString>,
 1298    pub color: PlayerColor,
 1299}
 1300
 1301#[derive(Clone, Debug)]
 1302struct SelectionHistoryEntry {
 1303    selections: Arc<[Selection<Anchor>]>,
 1304    select_next_state: Option<SelectNextState>,
 1305    select_prev_state: Option<SelectNextState>,
 1306    add_selections_state: Option<AddSelectionsState>,
 1307}
 1308
 1309#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1310enum SelectionHistoryMode {
 1311    #[default]
 1312    Normal,
 1313    Undoing,
 1314    Redoing,
 1315    Skipping,
 1316}
 1317
 1318#[derive(Clone, PartialEq, Eq, Hash)]
 1319struct HoveredCursor {
 1320    replica_id: ReplicaId,
 1321    selection_id: usize,
 1322}
 1323
 1324#[derive(Debug)]
 1325/// SelectionEffects controls the side-effects of updating the selection.
 1326///
 1327/// The default behaviour does "what you mostly want":
 1328/// - it pushes to the nav history if the cursor moved by >10 lines
 1329/// - it re-triggers completion requests
 1330/// - it scrolls to fit
 1331///
 1332/// You might want to modify these behaviours. For example when doing a "jump"
 1333/// like go to definition, we always want to add to nav history; but when scrolling
 1334/// in vim mode we never do.
 1335///
 1336/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1337/// move.
 1338#[derive(Clone)]
 1339pub struct SelectionEffects {
 1340    nav_history: Option<bool>,
 1341    completions: bool,
 1342    scroll: Option<Autoscroll>,
 1343}
 1344
 1345impl Default for SelectionEffects {
 1346    fn default() -> Self {
 1347        Self {
 1348            nav_history: None,
 1349            completions: true,
 1350            scroll: Some(Autoscroll::fit()),
 1351        }
 1352    }
 1353}
 1354impl SelectionEffects {
 1355    pub fn scroll(scroll: Autoscroll) -> Self {
 1356        Self {
 1357            scroll: Some(scroll),
 1358            ..Default::default()
 1359        }
 1360    }
 1361
 1362    pub fn no_scroll() -> Self {
 1363        Self {
 1364            scroll: None,
 1365            ..Default::default()
 1366        }
 1367    }
 1368
 1369    pub fn completions(self, completions: bool) -> Self {
 1370        Self {
 1371            completions,
 1372            ..self
 1373        }
 1374    }
 1375
 1376    pub fn nav_history(self, nav_history: bool) -> Self {
 1377        Self {
 1378            nav_history: Some(nav_history),
 1379            ..self
 1380        }
 1381    }
 1382}
 1383
 1384struct DeferredSelectionEffectsState {
 1385    changed: bool,
 1386    effects: SelectionEffects,
 1387    old_cursor_position: Anchor,
 1388    history_entry: SelectionHistoryEntry,
 1389}
 1390
 1391#[derive(Default)]
 1392struct SelectionHistory {
 1393    #[allow(clippy::type_complexity)]
 1394    selections_by_transaction:
 1395        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1396    mode: SelectionHistoryMode,
 1397    undo_stack: VecDeque<SelectionHistoryEntry>,
 1398    redo_stack: VecDeque<SelectionHistoryEntry>,
 1399}
 1400
 1401impl SelectionHistory {
 1402    #[track_caller]
 1403    fn insert_transaction(
 1404        &mut self,
 1405        transaction_id: TransactionId,
 1406        selections: Arc<[Selection<Anchor>]>,
 1407    ) {
 1408        if selections.is_empty() {
 1409            log::error!(
 1410                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1411                std::panic::Location::caller()
 1412            );
 1413            return;
 1414        }
 1415        self.selections_by_transaction
 1416            .insert(transaction_id, (selections, None));
 1417    }
 1418
 1419    #[allow(clippy::type_complexity)]
 1420    fn transaction(
 1421        &self,
 1422        transaction_id: TransactionId,
 1423    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1424        self.selections_by_transaction.get(&transaction_id)
 1425    }
 1426
 1427    #[allow(clippy::type_complexity)]
 1428    fn transaction_mut(
 1429        &mut self,
 1430        transaction_id: TransactionId,
 1431    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1432        self.selections_by_transaction.get_mut(&transaction_id)
 1433    }
 1434
 1435    fn push(&mut self, entry: SelectionHistoryEntry) {
 1436        if !entry.selections.is_empty() {
 1437            match self.mode {
 1438                SelectionHistoryMode::Normal => {
 1439                    self.push_undo(entry);
 1440                    self.redo_stack.clear();
 1441                }
 1442                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1443                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1444                SelectionHistoryMode::Skipping => {}
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .undo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.undo_stack.push_back(entry);
 1456            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.undo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461
 1462    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1463        if self
 1464            .redo_stack
 1465            .back()
 1466            .is_none_or(|e| e.selections != entry.selections)
 1467        {
 1468            self.redo_stack.push_back(entry);
 1469            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1470                self.redo_stack.pop_front();
 1471            }
 1472        }
 1473    }
 1474}
 1475
 1476#[derive(Clone, Copy)]
 1477pub struct RowHighlightOptions {
 1478    pub autoscroll: bool,
 1479    pub include_gutter: bool,
 1480}
 1481
 1482impl Default for RowHighlightOptions {
 1483    fn default() -> Self {
 1484        Self {
 1485            autoscroll: Default::default(),
 1486            include_gutter: true,
 1487        }
 1488    }
 1489}
 1490
 1491struct RowHighlight {
 1492    index: usize,
 1493    range: Range<Anchor>,
 1494    color: Hsla,
 1495    options: RowHighlightOptions,
 1496    type_id: TypeId,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsState {
 1501    groups: Vec<AddSelectionsGroup>,
 1502}
 1503
 1504#[derive(Clone, Debug)]
 1505struct AddSelectionsGroup {
 1506    above: bool,
 1507    stack: Vec<usize>,
 1508}
 1509
 1510#[derive(Clone)]
 1511struct SelectNextState {
 1512    query: AhoCorasick,
 1513    wordwise: bool,
 1514    done: bool,
 1515}
 1516
 1517impl std::fmt::Debug for SelectNextState {
 1518    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1519        f.debug_struct(std::any::type_name::<Self>())
 1520            .field("wordwise", &self.wordwise)
 1521            .field("done", &self.done)
 1522            .finish()
 1523    }
 1524}
 1525
 1526#[derive(Debug)]
 1527struct AutocloseRegion {
 1528    selection_id: usize,
 1529    range: Range<Anchor>,
 1530    pair: BracketPair,
 1531}
 1532
 1533#[derive(Debug)]
 1534struct SnippetState {
 1535    ranges: Vec<Vec<Range<Anchor>>>,
 1536    active_index: usize,
 1537    choices: Vec<Option<Vec<String>>>,
 1538}
 1539
 1540#[doc(hidden)]
 1541pub struct RenameState {
 1542    pub range: Range<Anchor>,
 1543    pub old_name: Arc<str>,
 1544    pub editor: Entity<Editor>,
 1545    block_id: CustomBlockId,
 1546}
 1547
 1548struct InvalidationStack<T>(Vec<T>);
 1549
 1550struct RegisteredEditPredictionProvider {
 1551    provider: Arc<dyn EditPredictionProviderHandle>,
 1552    _subscription: Subscription,
 1553}
 1554
 1555#[derive(Debug, PartialEq, Eq)]
 1556pub struct ActiveDiagnosticGroup {
 1557    pub active_range: Range<Anchor>,
 1558    pub active_message: String,
 1559    pub group_id: usize,
 1560    pub blocks: HashSet<CustomBlockId>,
 1561}
 1562
 1563#[derive(Debug, PartialEq, Eq)]
 1564
 1565pub(crate) enum ActiveDiagnostic {
 1566    None,
 1567    All,
 1568    Group(ActiveDiagnosticGroup),
 1569}
 1570
 1571#[derive(Serialize, Deserialize, Clone, Debug)]
 1572pub struct ClipboardSelection {
 1573    /// The number of bytes in this selection.
 1574    pub len: usize,
 1575    /// Whether this was a full-line selection.
 1576    pub is_entire_line: bool,
 1577    /// The indentation of the first line when this content was originally copied.
 1578    pub first_line_indent: u32,
 1579}
 1580
 1581// selections, scroll behavior, was newest selection reversed
 1582type SelectSyntaxNodeHistoryState = (
 1583    Box<[Selection<MultiBufferOffset>]>,
 1584    SelectSyntaxNodeScrollBehavior,
 1585    bool,
 1586);
 1587
 1588#[derive(Default)]
 1589struct SelectSyntaxNodeHistory {
 1590    stack: Vec<SelectSyntaxNodeHistoryState>,
 1591    // disable temporarily to allow changing selections without losing the stack
 1592    pub disable_clearing: bool,
 1593}
 1594
 1595impl SelectSyntaxNodeHistory {
 1596    pub fn try_clear(&mut self) {
 1597        if !self.disable_clearing {
 1598            self.stack.clear();
 1599        }
 1600    }
 1601
 1602    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1603        self.stack.push(selection);
 1604    }
 1605
 1606    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1607        self.stack.pop()
 1608    }
 1609}
 1610
 1611enum SelectSyntaxNodeScrollBehavior {
 1612    CursorTop,
 1613    FitSelection,
 1614    CursorBottom,
 1615}
 1616
 1617#[derive(Debug)]
 1618pub(crate) struct NavigationData {
 1619    cursor_anchor: Anchor,
 1620    cursor_position: Point,
 1621    scroll_anchor: ScrollAnchor,
 1622    scroll_top_row: u32,
 1623}
 1624
 1625#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1626pub enum GotoDefinitionKind {
 1627    Symbol,
 1628    Declaration,
 1629    Type,
 1630    Implementation,
 1631}
 1632
 1633pub enum FormatTarget {
 1634    Buffers(HashSet<Entity<Buffer>>),
 1635    Ranges(Vec<Range<MultiBufferPoint>>),
 1636}
 1637
 1638pub(crate) struct FocusedBlock {
 1639    id: BlockId,
 1640    focus_handle: WeakFocusHandle,
 1641}
 1642
 1643#[derive(Clone, Debug)]
 1644enum JumpData {
 1645    MultiBufferRow {
 1646        row: MultiBufferRow,
 1647        line_offset_from_top: u32,
 1648    },
 1649    MultiBufferPoint {
 1650        excerpt_id: ExcerptId,
 1651        position: Point,
 1652        anchor: text::Anchor,
 1653        line_offset_from_top: u32,
 1654    },
 1655}
 1656
 1657pub enum MultibufferSelectionMode {
 1658    First,
 1659    All,
 1660}
 1661
 1662#[derive(Clone, Copy, Debug, Default)]
 1663pub struct RewrapOptions {
 1664    pub override_language_settings: bool,
 1665    pub preserve_existing_whitespace: bool,
 1666}
 1667
 1668impl Editor {
 1669    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(EditorMode::full(), buffer, None, window, cx)
 1679    }
 1680
 1681    pub fn auto_height(
 1682        min_lines: usize,
 1683        max_lines: usize,
 1684        window: &mut Window,
 1685        cx: &mut Context<Self>,
 1686    ) -> Self {
 1687        let buffer = cx.new(|cx| Buffer::local("", cx));
 1688        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1689        Self::new(
 1690            EditorMode::AutoHeight {
 1691                min_lines,
 1692                max_lines: Some(max_lines),
 1693            },
 1694            buffer,
 1695            None,
 1696            window,
 1697            cx,
 1698        )
 1699    }
 1700
 1701    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1702    /// The editor grows as tall as needed to fit its content.
 1703    pub fn auto_height_unbounded(
 1704        min_lines: usize,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        let buffer = cx.new(|cx| Buffer::local("", cx));
 1709        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1710        Self::new(
 1711            EditorMode::AutoHeight {
 1712                min_lines,
 1713                max_lines: None,
 1714            },
 1715            buffer,
 1716            None,
 1717            window,
 1718            cx,
 1719        )
 1720    }
 1721
 1722    pub fn for_buffer(
 1723        buffer: Entity<Buffer>,
 1724        project: Option<Entity<Project>>,
 1725        window: &mut Window,
 1726        cx: &mut Context<Self>,
 1727    ) -> Self {
 1728        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1729        Self::new(EditorMode::full(), buffer, project, window, cx)
 1730    }
 1731
 1732    pub fn for_multibuffer(
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Self::new(EditorMode::full(), buffer, project, window, cx)
 1739    }
 1740
 1741    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1742        let mut clone = Self::new(
 1743            self.mode.clone(),
 1744            self.buffer.clone(),
 1745            self.project.clone(),
 1746            window,
 1747            cx,
 1748        );
 1749        self.display_map.update(cx, |display_map, cx| {
 1750            let snapshot = display_map.snapshot(cx);
 1751            clone.display_map.update(cx, |display_map, cx| {
 1752                display_map.set_state(&snapshot, cx);
 1753            });
 1754        });
 1755        clone.folds_did_change(cx);
 1756        clone.selections.clone_state(&self.selections);
 1757        clone.scroll_manager.clone_state(&self.scroll_manager);
 1758        clone.searchable = self.searchable;
 1759        clone.read_only = self.read_only;
 1760        clone
 1761    }
 1762
 1763    pub fn new(
 1764        mode: EditorMode,
 1765        buffer: Entity<MultiBuffer>,
 1766        project: Option<Entity<Project>>,
 1767        window: &mut Window,
 1768        cx: &mut Context<Self>,
 1769    ) -> Self {
 1770        Editor::new_internal(mode, buffer, project, None, window, cx)
 1771    }
 1772
 1773    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1774        let multi_buffer = self.buffer().read(cx);
 1775        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1776        let multi_buffer_visible_start = self
 1777            .scroll_manager
 1778            .anchor()
 1779            .anchor
 1780            .to_point(&multi_buffer_snapshot);
 1781        let max_row = multi_buffer_snapshot.max_point().row;
 1782
 1783        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1784        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1785
 1786        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1787            let outline_items = buffer
 1788                .outline_items_containing(
 1789                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1790                    true,
 1791                    self.style().map(|style| style.syntax.as_ref()),
 1792                )
 1793                .into_iter()
 1794                .map(|outline_item| OutlineItem {
 1795                    depth: outline_item.depth,
 1796                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1797                    source_range_for_text: Anchor::range_in_buffer(
 1798                        *excerpt_id,
 1799                        outline_item.source_range_for_text,
 1800                    ),
 1801                    text: outline_item.text,
 1802                    highlight_ranges: outline_item.highlight_ranges,
 1803                    name_ranges: outline_item.name_ranges,
 1804                    body_range: outline_item
 1805                        .body_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1807                    annotation_range: outline_item
 1808                        .annotation_range
 1809                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1810                });
 1811            return Some(outline_items.collect());
 1812        }
 1813
 1814        None
 1815    }
 1816
 1817    fn new_internal(
 1818        mode: EditorMode,
 1819        multi_buffer: Entity<MultiBuffer>,
 1820        project: Option<Entity<Project>>,
 1821        display_map: Option<Entity<DisplayMap>>,
 1822        window: &mut Window,
 1823        cx: &mut Context<Self>,
 1824    ) -> Self {
 1825        debug_assert!(
 1826            display_map.is_none() || mode.is_minimap(),
 1827            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1828        );
 1829
 1830        let full_mode = mode.is_full();
 1831        let is_minimap = mode.is_minimap();
 1832        let diagnostics_max_severity = if full_mode {
 1833            EditorSettings::get_global(cx)
 1834                .diagnostics_max_severity
 1835                .unwrap_or(DiagnosticSeverity::Hint)
 1836        } else {
 1837            DiagnosticSeverity::Off
 1838        };
 1839        let style = window.text_style();
 1840        let font_size = style.font_size.to_pixels(window.rem_size());
 1841        let editor = cx.entity().downgrade();
 1842        let fold_placeholder = FoldPlaceholder {
 1843            constrain_width: false,
 1844            render: Arc::new(move |fold_id, fold_range, cx| {
 1845                let editor = editor.clone();
 1846                div()
 1847                    .id(fold_id)
 1848                    .bg(cx.theme().colors().ghost_element_background)
 1849                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1850                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1851                    .rounded_xs()
 1852                    .size_full()
 1853                    .cursor_pointer()
 1854                    .child("")
 1855                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1856                    .on_click(move |_, _window, cx| {
 1857                        editor
 1858                            .update(cx, |editor, cx| {
 1859                                editor.unfold_ranges(
 1860                                    &[fold_range.start..fold_range.end],
 1861                                    true,
 1862                                    false,
 1863                                    cx,
 1864                                );
 1865                                cx.stop_propagation();
 1866                            })
 1867                            .ok();
 1868                    })
 1869                    .into_any()
 1870            }),
 1871            merge_adjacent: true,
 1872            ..FoldPlaceholder::default()
 1873        };
 1874        let display_map = display_map.unwrap_or_else(|| {
 1875            cx.new(|cx| {
 1876                DisplayMap::new(
 1877                    multi_buffer.clone(),
 1878                    style.font(),
 1879                    font_size,
 1880                    None,
 1881                    FILE_HEADER_HEIGHT,
 1882                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1883                    fold_placeholder,
 1884                    diagnostics_max_severity,
 1885                    cx,
 1886                )
 1887            })
 1888        });
 1889
 1890        let selections = SelectionsCollection::new();
 1891
 1892        let blink_manager = cx.new(|cx| {
 1893            let mut blink_manager = BlinkManager::new(
 1894                CURSOR_BLINK_INTERVAL,
 1895                |cx| EditorSettings::get_global(cx).cursor_blink,
 1896                cx,
 1897            );
 1898            if is_minimap {
 1899                blink_manager.disable(cx);
 1900            }
 1901            blink_manager
 1902        });
 1903
 1904        let soft_wrap_mode_override =
 1905            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1906
 1907        let mut project_subscriptions = Vec::new();
 1908        if full_mode && let Some(project) = project.as_ref() {
 1909            project_subscriptions.push(cx.subscribe_in(
 1910                project,
 1911                window,
 1912                |editor, _, event, window, cx| match event {
 1913                    project::Event::RefreshCodeLens => {
 1914                        // we always query lens with actions, without storing them, always refreshing them
 1915                    }
 1916                    project::Event::RefreshInlayHints {
 1917                        server_id,
 1918                        request_id,
 1919                    } => {
 1920                        editor.refresh_inlay_hints(
 1921                            InlayHintRefreshReason::RefreshRequested {
 1922                                server_id: *server_id,
 1923                                request_id: *request_id,
 1924                            },
 1925                            cx,
 1926                        );
 1927                    }
 1928                    project::Event::LanguageServerRemoved(..) => {
 1929                        if editor.tasks_update_task.is_none() {
 1930                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1931                        }
 1932                        editor.registered_buffers.clear();
 1933                        editor.register_visible_buffers(cx);
 1934                    }
 1935                    project::Event::LanguageServerAdded(..) => {
 1936                        if editor.tasks_update_task.is_none() {
 1937                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1938                        }
 1939                    }
 1940                    project::Event::SnippetEdit(id, snippet_edits) => {
 1941                        // todo(lw): Non singletons
 1942                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1943                            let snapshot = buffer.read(cx).snapshot();
 1944                            let focus_handle = editor.focus_handle(cx);
 1945                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1946                                for (range, snippet) in snippet_edits {
 1947                                    let buffer_range =
 1948                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1949                                    editor
 1950                                        .insert_snippet(
 1951                                            &[MultiBufferOffset(buffer_range.start)
 1952                                                ..MultiBufferOffset(buffer_range.end)],
 1953                                            snippet.clone(),
 1954                                            window,
 1955                                            cx,
 1956                                        )
 1957                                        .ok();
 1958                                }
 1959                            }
 1960                        }
 1961                    }
 1962                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1963                        let buffer_id = *buffer_id;
 1964                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1965                            editor.register_buffer(buffer_id, cx);
 1966                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1967                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1968                            refresh_linked_ranges(editor, window, cx);
 1969                            editor.refresh_code_actions(window, cx);
 1970                            editor.refresh_document_highlights(cx);
 1971                        }
 1972                    }
 1973
 1974                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1975                        let Some(workspace) = editor.workspace() else {
 1976                            return;
 1977                        };
 1978                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1979                        else {
 1980                            return;
 1981                        };
 1982
 1983                        if active_editor.entity_id() == cx.entity_id() {
 1984                            let entity_id = cx.entity_id();
 1985                            workspace.update(cx, |this, cx| {
 1986                                this.panes_mut()
 1987                                    .iter_mut()
 1988                                    .filter(|pane| pane.entity_id() != entity_id)
 1989                                    .for_each(|p| {
 1990                                        p.update(cx, |pane, _| {
 1991                                            pane.nav_history_mut().rename_item(
 1992                                                entity_id,
 1993                                                project_path.clone(),
 1994                                                abs_path.clone().into(),
 1995                                            );
 1996                                        })
 1997                                    });
 1998                            });
 1999                            let edited_buffers_already_open = {
 2000                                let other_editors: Vec<Entity<Editor>> = workspace
 2001                                    .read(cx)
 2002                                    .panes()
 2003                                    .iter()
 2004                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2005                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2006                                    .collect();
 2007
 2008                                transaction.0.keys().all(|buffer| {
 2009                                    other_editors.iter().any(|editor| {
 2010                                        let multi_buffer = editor.read(cx).buffer();
 2011                                        multi_buffer.read(cx).is_singleton()
 2012                                            && multi_buffer.read(cx).as_singleton().map_or(
 2013                                                false,
 2014                                                |singleton| {
 2015                                                    singleton.entity_id() == buffer.entity_id()
 2016                                                },
 2017                                            )
 2018                                    })
 2019                                })
 2020                            };
 2021                            if !edited_buffers_already_open {
 2022                                let workspace = workspace.downgrade();
 2023                                let transaction = transaction.clone();
 2024                                cx.defer_in(window, move |_, window, cx| {
 2025                                    cx.spawn_in(window, async move |editor, cx| {
 2026                                        Self::open_project_transaction(
 2027                                            &editor,
 2028                                            workspace,
 2029                                            transaction,
 2030                                            "Rename".to_string(),
 2031                                            cx,
 2032                                        )
 2033                                        .await
 2034                                        .ok()
 2035                                    })
 2036                                    .detach();
 2037                                });
 2038                            }
 2039                        }
 2040                    }
 2041
 2042                    _ => {}
 2043                },
 2044            ));
 2045            if let Some(task_inventory) = project
 2046                .read(cx)
 2047                .task_store()
 2048                .read(cx)
 2049                .task_inventory()
 2050                .cloned()
 2051            {
 2052                project_subscriptions.push(cx.observe_in(
 2053                    &task_inventory,
 2054                    window,
 2055                    |editor, _, window, cx| {
 2056                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2057                    },
 2058                ));
 2059            };
 2060
 2061            project_subscriptions.push(cx.subscribe_in(
 2062                &project.read(cx).breakpoint_store(),
 2063                window,
 2064                |editor, _, event, window, cx| match event {
 2065                    BreakpointStoreEvent::ClearDebugLines => {
 2066                        editor.clear_row_highlights::<ActiveDebugLine>();
 2067                        editor.refresh_inline_values(cx);
 2068                    }
 2069                    BreakpointStoreEvent::SetDebugLine => {
 2070                        if editor.go_to_active_debug_line(window, cx) {
 2071                            cx.stop_propagation();
 2072                        }
 2073
 2074                        editor.refresh_inline_values(cx);
 2075                    }
 2076                    _ => {}
 2077                },
 2078            ));
 2079            let git_store = project.read(cx).git_store().clone();
 2080            let project = project.clone();
 2081            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2082                if let GitStoreEvent::RepositoryAdded = event {
 2083                    this.load_diff_task = Some(
 2084                        update_uncommitted_diff_for_buffer(
 2085                            cx.entity(),
 2086                            &project,
 2087                            this.buffer.read(cx).all_buffers(),
 2088                            this.buffer.clone(),
 2089                            cx,
 2090                        )
 2091                        .shared(),
 2092                    );
 2093                }
 2094            }));
 2095        }
 2096
 2097        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2098
 2099        let inlay_hint_settings =
 2100            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2101        let focus_handle = cx.focus_handle();
 2102        if !is_minimap {
 2103            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2104                .detach();
 2105            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2106                .detach();
 2107            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2108                .detach();
 2109            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2110                .detach();
 2111            cx.observe_pending_input(window, Self::observe_pending_input)
 2112                .detach();
 2113        }
 2114
 2115        let show_indent_guides =
 2116            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2117                Some(false)
 2118            } else {
 2119                None
 2120            };
 2121
 2122        let breakpoint_store = match (&mode, project.as_ref()) {
 2123            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2124            _ => None,
 2125        };
 2126
 2127        let mut code_action_providers = Vec::new();
 2128        let mut load_uncommitted_diff = None;
 2129        if let Some(project) = project.clone() {
 2130            load_uncommitted_diff = Some(
 2131                update_uncommitted_diff_for_buffer(
 2132                    cx.entity(),
 2133                    &project,
 2134                    multi_buffer.read(cx).all_buffers(),
 2135                    multi_buffer.clone(),
 2136                    cx,
 2137                )
 2138                .shared(),
 2139            );
 2140            code_action_providers.push(Rc::new(project) as Rc<_>);
 2141        }
 2142
 2143        let mut editor = Self {
 2144            focus_handle,
 2145            show_cursor_when_unfocused: false,
 2146            last_focused_descendant: None,
 2147            buffer: multi_buffer.clone(),
 2148            display_map: display_map.clone(),
 2149            placeholder_display_map: None,
 2150            selections,
 2151            scroll_manager: ScrollManager::new(cx),
 2152            columnar_selection_state: None,
 2153            add_selections_state: None,
 2154            select_next_state: None,
 2155            select_prev_state: None,
 2156            selection_history: SelectionHistory::default(),
 2157            defer_selection_effects: false,
 2158            deferred_selection_effects_state: None,
 2159            autoclose_regions: Vec::new(),
 2160            snippet_stack: InvalidationStack::default(),
 2161            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2162            ime_transaction: None,
 2163            active_diagnostics: ActiveDiagnostic::None,
 2164            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2165            inline_diagnostics_update: Task::ready(()),
 2166            inline_diagnostics: Vec::new(),
 2167            soft_wrap_mode_override,
 2168            diagnostics_max_severity,
 2169            hard_wrap: None,
 2170            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2171            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2172            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2173            project,
 2174            blink_manager: blink_manager.clone(),
 2175            show_local_selections: true,
 2176            show_scrollbars: ScrollbarAxes {
 2177                horizontal: full_mode,
 2178                vertical: full_mode,
 2179            },
 2180            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2181            offset_content: !matches!(mode, EditorMode::SingleLine),
 2182            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2183            show_gutter: full_mode,
 2184            show_line_numbers: (!full_mode).then_some(false),
 2185            use_relative_line_numbers: None,
 2186            disable_expand_excerpt_buttons: !full_mode,
 2187            show_git_diff_gutter: None,
 2188            show_code_actions: None,
 2189            show_runnables: None,
 2190            show_breakpoints: None,
 2191            show_wrap_guides: None,
 2192            show_indent_guides,
 2193            highlight_order: 0,
 2194            highlighted_rows: HashMap::default(),
 2195            background_highlights: HashMap::default(),
 2196            gutter_highlights: HashMap::default(),
 2197            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2198            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2199            nav_history: None,
 2200            context_menu: RefCell::new(None),
 2201            context_menu_options: None,
 2202            mouse_context_menu: None,
 2203            completion_tasks: Vec::new(),
 2204            inline_blame_popover: None,
 2205            inline_blame_popover_show_task: None,
 2206            signature_help_state: SignatureHelpState::default(),
 2207            auto_signature_help: None,
 2208            find_all_references_task_sources: Vec::new(),
 2209            next_completion_id: 0,
 2210            next_inlay_id: 0,
 2211            code_action_providers,
 2212            available_code_actions: None,
 2213            code_actions_task: None,
 2214            quick_selection_highlight_task: None,
 2215            debounced_selection_highlight_task: None,
 2216            document_highlights_task: None,
 2217            linked_editing_range_task: None,
 2218            pending_rename: None,
 2219            searchable: !is_minimap,
 2220            cursor_shape: EditorSettings::get_global(cx)
 2221                .cursor_shape
 2222                .unwrap_or_default(),
 2223            current_line_highlight: None,
 2224            autoindent_mode: Some(AutoindentMode::EachLine),
 2225            collapse_matches: false,
 2226            workspace: None,
 2227            input_enabled: !is_minimap,
 2228            use_modal_editing: full_mode,
 2229            read_only: is_minimap,
 2230            use_autoclose: true,
 2231            use_auto_surround: true,
 2232            auto_replace_emoji_shortcode: false,
 2233            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2234            leader_id: None,
 2235            remote_id: None,
 2236            hover_state: HoverState::default(),
 2237            pending_mouse_down: None,
 2238            hovered_link_state: None,
 2239            edit_prediction_provider: None,
 2240            active_edit_prediction: None,
 2241            stale_edit_prediction_in_menu: None,
 2242            edit_prediction_preview: EditPredictionPreview::Inactive {
 2243                released_too_fast: false,
 2244            },
 2245            inline_diagnostics_enabled: full_mode,
 2246            diagnostics_enabled: full_mode,
 2247            word_completions_enabled: full_mode,
 2248            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2249            gutter_hovered: false,
 2250            pixel_position_of_newest_cursor: None,
 2251            last_bounds: None,
 2252            last_position_map: None,
 2253            expect_bounds_change: None,
 2254            gutter_dimensions: GutterDimensions::default(),
 2255            style: None,
 2256            show_cursor_names: false,
 2257            hovered_cursors: HashMap::default(),
 2258            next_editor_action_id: EditorActionId::default(),
 2259            editor_actions: Rc::default(),
 2260            edit_predictions_hidden_for_vim_mode: false,
 2261            show_edit_predictions_override: None,
 2262            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2263            edit_prediction_settings: EditPredictionSettings::Disabled,
 2264            edit_prediction_indent_conflict: false,
 2265            edit_prediction_requires_modifier_in_indent_conflict: true,
 2266            custom_context_menu: None,
 2267            show_git_blame_gutter: false,
 2268            show_git_blame_inline: false,
 2269            show_selection_menu: None,
 2270            show_git_blame_inline_delay_task: None,
 2271            git_blame_inline_enabled: full_mode
 2272                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2273            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2274            buffer_serialization: is_minimap.not().then(|| {
 2275                BufferSerialization::new(
 2276                    ProjectSettings::get_global(cx)
 2277                        .session
 2278                        .restore_unsaved_buffers,
 2279                )
 2280            }),
 2281            blame: None,
 2282            blame_subscription: None,
 2283            tasks: BTreeMap::default(),
 2284
 2285            breakpoint_store,
 2286            gutter_breakpoint_indicator: (None, None),
 2287            hovered_diff_hunk_row: None,
 2288            _subscriptions: (!is_minimap)
 2289                .then(|| {
 2290                    vec![
 2291                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2292                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2293                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2294                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2295                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2296                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2297                        cx.observe_window_activation(window, |editor, window, cx| {
 2298                            let active = window.is_window_active();
 2299                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2300                                if active {
 2301                                    blink_manager.enable(cx);
 2302                                } else {
 2303                                    blink_manager.disable(cx);
 2304                                }
 2305                            });
 2306                            if active {
 2307                                editor.show_mouse_cursor(cx);
 2308                            }
 2309                        }),
 2310                    ]
 2311                })
 2312                .unwrap_or_default(),
 2313            tasks_update_task: None,
 2314            pull_diagnostics_task: Task::ready(()),
 2315            colors: None,
 2316            refresh_colors_task: Task::ready(()),
 2317            inlay_hints: None,
 2318            next_color_inlay_id: 0,
 2319            post_scroll_update: Task::ready(()),
 2320            linked_edit_ranges: Default::default(),
 2321            in_project_search: false,
 2322            previous_search_ranges: None,
 2323            breadcrumb_header: None,
 2324            focused_block: None,
 2325            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2326            addons: HashMap::default(),
 2327            registered_buffers: HashMap::default(),
 2328            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2329            selection_mark_mode: false,
 2330            toggle_fold_multiple_buffers: Task::ready(()),
 2331            serialize_selections: Task::ready(()),
 2332            serialize_folds: Task::ready(()),
 2333            text_style_refinement: None,
 2334            load_diff_task: load_uncommitted_diff,
 2335            temporary_diff_override: false,
 2336            mouse_cursor_hidden: false,
 2337            minimap: None,
 2338            hide_mouse_mode: EditorSettings::get_global(cx)
 2339                .hide_mouse
 2340                .unwrap_or_default(),
 2341            change_list: ChangeList::new(),
 2342            mode,
 2343            selection_drag_state: SelectionDragState::None,
 2344            folding_newlines: Task::ready(()),
 2345            lookup_key: None,
 2346            select_next_is_case_sensitive: None,
 2347            applicable_language_settings: HashMap::default(),
 2348            accent_overrides: Vec::new(),
 2349            fetched_tree_sitter_chunks: HashMap::default(),
 2350            use_base_text_line_numbers: false,
 2351        };
 2352
 2353        if is_minimap {
 2354            return editor;
 2355        }
 2356
 2357        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2358        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2359
 2360        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2361            editor
 2362                ._subscriptions
 2363                .push(cx.observe(breakpoints, |_, _, cx| {
 2364                    cx.notify();
 2365                }));
 2366        }
 2367        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2368        editor._subscriptions.extend(project_subscriptions);
 2369
 2370        editor._subscriptions.push(cx.subscribe_in(
 2371            &cx.entity(),
 2372            window,
 2373            |editor, _, e: &EditorEvent, window, cx| match e {
 2374                EditorEvent::ScrollPositionChanged { local, .. } => {
 2375                    if *local {
 2376                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2377                        editor.inline_blame_popover.take();
 2378                        let new_anchor = editor.scroll_manager.anchor();
 2379                        let snapshot = editor.snapshot(window, cx);
 2380                        editor.update_restoration_data(cx, move |data| {
 2381                            data.scroll_position = (
 2382                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2383                                new_anchor.offset,
 2384                            );
 2385                        });
 2386
 2387                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2388                            cx.background_executor()
 2389                                .timer(Duration::from_millis(50))
 2390                                .await;
 2391                            editor
 2392                                .update_in(cx, |editor, window, cx| {
 2393                                    editor.register_visible_buffers(cx);
 2394                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2395                                    editor.refresh_inlay_hints(
 2396                                        InlayHintRefreshReason::NewLinesShown,
 2397                                        cx,
 2398                                    );
 2399                                    editor.colorize_brackets(false, cx);
 2400                                })
 2401                                .ok();
 2402                        });
 2403                    }
 2404                }
 2405                EditorEvent::Edited { .. } => {
 2406                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2407                        .map(|vim_mode| vim_mode.0)
 2408                        .unwrap_or(false);
 2409                    if !vim_mode {
 2410                        let display_map = editor.display_snapshot(cx);
 2411                        let selections = editor.selections.all_adjusted_display(&display_map);
 2412                        let pop_state = editor
 2413                            .change_list
 2414                            .last()
 2415                            .map(|previous| {
 2416                                previous.len() == selections.len()
 2417                                    && previous.iter().enumerate().all(|(ix, p)| {
 2418                                        p.to_display_point(&display_map).row()
 2419                                            == selections[ix].head().row()
 2420                                    })
 2421                            })
 2422                            .unwrap_or(false);
 2423                        let new_positions = selections
 2424                            .into_iter()
 2425                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2426                            .collect();
 2427                        editor
 2428                            .change_list
 2429                            .push_to_change_list(pop_state, new_positions);
 2430                    }
 2431                }
 2432                _ => (),
 2433            },
 2434        ));
 2435
 2436        if let Some(dap_store) = editor
 2437            .project
 2438            .as_ref()
 2439            .map(|project| project.read(cx).dap_store())
 2440        {
 2441            let weak_editor = cx.weak_entity();
 2442
 2443            editor
 2444                ._subscriptions
 2445                .push(
 2446                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2447                        let session_entity = cx.entity();
 2448                        weak_editor
 2449                            .update(cx, |editor, cx| {
 2450                                editor._subscriptions.push(
 2451                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2452                                );
 2453                            })
 2454                            .ok();
 2455                    }),
 2456                );
 2457
 2458            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2459                editor
 2460                    ._subscriptions
 2461                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2462            }
 2463        }
 2464
 2465        // skip adding the initial selection to selection history
 2466        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2467        editor.end_selection(window, cx);
 2468        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2469
 2470        editor.scroll_manager.show_scrollbars(window, cx);
 2471        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2472
 2473        if full_mode {
 2474            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2475            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2476
 2477            if editor.git_blame_inline_enabled {
 2478                editor.start_git_blame_inline(false, window, cx);
 2479            }
 2480
 2481            editor.go_to_active_debug_line(window, cx);
 2482
 2483            editor.minimap =
 2484                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2485            editor.colors = Some(LspColorData::new(cx));
 2486            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2487
 2488            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2489                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2490            }
 2491            editor.update_lsp_data(None, window, cx);
 2492            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2493        }
 2494
 2495        editor
 2496    }
 2497
 2498    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2499        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2500    }
 2501
 2502    pub fn deploy_mouse_context_menu(
 2503        &mut self,
 2504        position: gpui::Point<Pixels>,
 2505        context_menu: Entity<ContextMenu>,
 2506        window: &mut Window,
 2507        cx: &mut Context<Self>,
 2508    ) {
 2509        self.mouse_context_menu = Some(MouseContextMenu::new(
 2510            self,
 2511            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2512            context_menu,
 2513            window,
 2514            cx,
 2515        ));
 2516    }
 2517
 2518    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2519        self.mouse_context_menu
 2520            .as_ref()
 2521            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2522    }
 2523
 2524    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2525        if self
 2526            .selections
 2527            .pending_anchor()
 2528            .is_some_and(|pending_selection| {
 2529                let snapshot = self.buffer().read(cx).snapshot(cx);
 2530                pending_selection.range().includes(range, &snapshot)
 2531            })
 2532        {
 2533            return true;
 2534        }
 2535
 2536        self.selections
 2537            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2538            .into_iter()
 2539            .any(|selection| {
 2540                // This is needed to cover a corner case, if we just check for an existing
 2541                // selection in the fold range, having a cursor at the start of the fold
 2542                // marks it as selected. Non-empty selections don't cause this.
 2543                let length = selection.end - selection.start;
 2544                length > 0
 2545            })
 2546    }
 2547
 2548    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2549        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2550    }
 2551
 2552    fn key_context_internal(
 2553        &self,
 2554        has_active_edit_prediction: bool,
 2555        window: &mut Window,
 2556        cx: &mut App,
 2557    ) -> KeyContext {
 2558        let mut key_context = KeyContext::new_with_defaults();
 2559        key_context.add("Editor");
 2560        let mode = match self.mode {
 2561            EditorMode::SingleLine => "single_line",
 2562            EditorMode::AutoHeight { .. } => "auto_height",
 2563            EditorMode::Minimap { .. } => "minimap",
 2564            EditorMode::Full { .. } => "full",
 2565        };
 2566
 2567        if EditorSettings::jupyter_enabled(cx) {
 2568            key_context.add("jupyter");
 2569        }
 2570
 2571        key_context.set("mode", mode);
 2572        if self.pending_rename.is_some() {
 2573            key_context.add("renaming");
 2574        }
 2575
 2576        if let Some(snippet_stack) = self.snippet_stack.last() {
 2577            key_context.add("in_snippet");
 2578
 2579            if snippet_stack.active_index > 0 {
 2580                key_context.add("has_previous_tabstop");
 2581            }
 2582
 2583            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2584                key_context.add("has_next_tabstop");
 2585            }
 2586        }
 2587
 2588        match self.context_menu.borrow().as_ref() {
 2589            Some(CodeContextMenu::Completions(menu)) => {
 2590                if menu.visible() {
 2591                    key_context.add("menu");
 2592                    key_context.add("showing_completions");
 2593                }
 2594            }
 2595            Some(CodeContextMenu::CodeActions(menu)) => {
 2596                if menu.visible() {
 2597                    key_context.add("menu");
 2598                    key_context.add("showing_code_actions")
 2599                }
 2600            }
 2601            None => {}
 2602        }
 2603
 2604        if self.signature_help_state.has_multiple_signatures() {
 2605            key_context.add("showing_signature_help");
 2606        }
 2607
 2608        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2609        if !self.focus_handle(cx).contains_focused(window, cx)
 2610            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2611        {
 2612            for addon in self.addons.values() {
 2613                addon.extend_key_context(&mut key_context, cx)
 2614            }
 2615        }
 2616
 2617        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2618            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2619                Some(
 2620                    file.full_path(cx)
 2621                        .extension()?
 2622                        .to_string_lossy()
 2623                        .into_owned(),
 2624                )
 2625            }) {
 2626                key_context.set("extension", extension);
 2627            }
 2628        } else {
 2629            key_context.add("multibuffer");
 2630        }
 2631
 2632        if has_active_edit_prediction {
 2633            if self.edit_prediction_in_conflict() {
 2634                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2635            } else {
 2636                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2637                key_context.add("copilot_suggestion");
 2638            }
 2639        }
 2640
 2641        if self.selection_mark_mode {
 2642            key_context.add("selection_mode");
 2643        }
 2644
 2645        let disjoint = self.selections.disjoint_anchors();
 2646        let snapshot = self.snapshot(window, cx);
 2647        let snapshot = snapshot.buffer_snapshot();
 2648        if self.mode == EditorMode::SingleLine
 2649            && let [selection] = disjoint
 2650            && selection.start == selection.end
 2651            && selection.end.to_offset(snapshot) == snapshot.len()
 2652        {
 2653            key_context.add("end_of_input");
 2654        }
 2655
 2656        if self.has_any_expanded_diff_hunks(cx) {
 2657            key_context.add("diffs_expanded");
 2658        }
 2659
 2660        key_context
 2661    }
 2662
 2663    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2664        self.last_bounds.as_ref()
 2665    }
 2666
 2667    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2668        if self.mouse_cursor_hidden {
 2669            self.mouse_cursor_hidden = false;
 2670            cx.notify();
 2671        }
 2672    }
 2673
 2674    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2675        let hide_mouse_cursor = match origin {
 2676            HideMouseCursorOrigin::TypingAction => {
 2677                matches!(
 2678                    self.hide_mouse_mode,
 2679                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2680                )
 2681            }
 2682            HideMouseCursorOrigin::MovementAction => {
 2683                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2684            }
 2685        };
 2686        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2687            self.mouse_cursor_hidden = hide_mouse_cursor;
 2688            cx.notify();
 2689        }
 2690    }
 2691
 2692    pub fn edit_prediction_in_conflict(&self) -> bool {
 2693        if !self.show_edit_predictions_in_menu() {
 2694            return false;
 2695        }
 2696
 2697        let showing_completions = self
 2698            .context_menu
 2699            .borrow()
 2700            .as_ref()
 2701            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2702
 2703        showing_completions
 2704            || self.edit_prediction_requires_modifier()
 2705            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2706            // bindings to insert tab characters.
 2707            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2708    }
 2709
 2710    pub fn accept_edit_prediction_keybind(
 2711        &self,
 2712        accept_partial: bool,
 2713        window: &mut Window,
 2714        cx: &mut App,
 2715    ) -> AcceptEditPredictionBinding {
 2716        let key_context = self.key_context_internal(true, window, cx);
 2717        let in_conflict = self.edit_prediction_in_conflict();
 2718
 2719        let bindings = if accept_partial {
 2720            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2721        } else {
 2722            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2723        };
 2724
 2725        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2726        // just the first one.
 2727        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2728            !in_conflict
 2729                || binding
 2730                    .keystrokes()
 2731                    .first()
 2732                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2733        }))
 2734    }
 2735
 2736    pub fn new_file(
 2737        workspace: &mut Workspace,
 2738        _: &workspace::NewFile,
 2739        window: &mut Window,
 2740        cx: &mut Context<Workspace>,
 2741    ) {
 2742        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2743            "Failed to create buffer",
 2744            window,
 2745            cx,
 2746            |e, _, _| match e.error_code() {
 2747                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2748                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2749                e.error_tag("required").unwrap_or("the latest version")
 2750            )),
 2751                _ => None,
 2752            },
 2753        );
 2754    }
 2755
 2756    pub fn new_in_workspace(
 2757        workspace: &mut Workspace,
 2758        window: &mut Window,
 2759        cx: &mut Context<Workspace>,
 2760    ) -> Task<Result<Entity<Editor>>> {
 2761        let project = workspace.project().clone();
 2762        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2763
 2764        cx.spawn_in(window, async move |workspace, cx| {
 2765            let buffer = create.await?;
 2766            workspace.update_in(cx, |workspace, window, cx| {
 2767                let editor =
 2768                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2769                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2770                editor
 2771            })
 2772        })
 2773    }
 2774
 2775    fn new_file_vertical(
 2776        workspace: &mut Workspace,
 2777        _: &workspace::NewFileSplitVertical,
 2778        window: &mut Window,
 2779        cx: &mut Context<Workspace>,
 2780    ) {
 2781        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2782    }
 2783
 2784    fn new_file_horizontal(
 2785        workspace: &mut Workspace,
 2786        _: &workspace::NewFileSplitHorizontal,
 2787        window: &mut Window,
 2788        cx: &mut Context<Workspace>,
 2789    ) {
 2790        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2791    }
 2792
 2793    fn new_file_split(
 2794        workspace: &mut Workspace,
 2795        action: &workspace::NewFileSplit,
 2796        window: &mut Window,
 2797        cx: &mut Context<Workspace>,
 2798    ) {
 2799        Self::new_file_in_direction(workspace, action.0, window, cx)
 2800    }
 2801
 2802    fn new_file_in_direction(
 2803        workspace: &mut Workspace,
 2804        direction: SplitDirection,
 2805        window: &mut Window,
 2806        cx: &mut Context<Workspace>,
 2807    ) {
 2808        let project = workspace.project().clone();
 2809        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2810
 2811        cx.spawn_in(window, async move |workspace, cx| {
 2812            let buffer = create.await?;
 2813            workspace.update_in(cx, move |workspace, window, cx| {
 2814                workspace.split_item(
 2815                    direction,
 2816                    Box::new(
 2817                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2818                    ),
 2819                    window,
 2820                    cx,
 2821                )
 2822            })?;
 2823            anyhow::Ok(())
 2824        })
 2825        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2826            match e.error_code() {
 2827                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2828                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2829                e.error_tag("required").unwrap_or("the latest version")
 2830            )),
 2831                _ => None,
 2832            }
 2833        });
 2834    }
 2835
 2836    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2837        self.leader_id
 2838    }
 2839
 2840    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2841        &self.buffer
 2842    }
 2843
 2844    pub fn project(&self) -> Option<&Entity<Project>> {
 2845        self.project.as_ref()
 2846    }
 2847
 2848    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2849        self.workspace.as_ref()?.0.upgrade()
 2850    }
 2851
 2852    /// Returns the workspace serialization ID if this editor should be serialized.
 2853    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2854        self.workspace
 2855            .as_ref()
 2856            .filter(|_| self.should_serialize_buffer())
 2857            .and_then(|workspace| workspace.1)
 2858    }
 2859
 2860    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2861        self.buffer().read(cx).title(cx)
 2862    }
 2863
 2864    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2865        let git_blame_gutter_max_author_length = self
 2866            .render_git_blame_gutter(cx)
 2867            .then(|| {
 2868                if let Some(blame) = self.blame.as_ref() {
 2869                    let max_author_length =
 2870                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2871                    Some(max_author_length)
 2872                } else {
 2873                    None
 2874                }
 2875            })
 2876            .flatten();
 2877
 2878        EditorSnapshot {
 2879            mode: self.mode.clone(),
 2880            show_gutter: self.show_gutter,
 2881            show_line_numbers: self.show_line_numbers,
 2882            show_git_diff_gutter: self.show_git_diff_gutter,
 2883            show_code_actions: self.show_code_actions,
 2884            show_runnables: self.show_runnables,
 2885            show_breakpoints: self.show_breakpoints,
 2886            git_blame_gutter_max_author_length,
 2887            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2888            placeholder_display_snapshot: self
 2889                .placeholder_display_map
 2890                .as_ref()
 2891                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2892            scroll_anchor: self.scroll_manager.anchor(),
 2893            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2894            is_focused: self.focus_handle.is_focused(window),
 2895            current_line_highlight: self
 2896                .current_line_highlight
 2897                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2898            gutter_hovered: self.gutter_hovered,
 2899        }
 2900    }
 2901
 2902    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2903        self.buffer.read(cx).language_at(point, cx)
 2904    }
 2905
 2906    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2907        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2908    }
 2909
 2910    pub fn active_excerpt(
 2911        &self,
 2912        cx: &App,
 2913    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2914        self.buffer
 2915            .read(cx)
 2916            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2917    }
 2918
 2919    pub fn mode(&self) -> &EditorMode {
 2920        &self.mode
 2921    }
 2922
 2923    pub fn set_mode(&mut self, mode: EditorMode) {
 2924        self.mode = mode;
 2925    }
 2926
 2927    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2928        self.collaboration_hub.as_deref()
 2929    }
 2930
 2931    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2932        self.collaboration_hub = Some(hub);
 2933    }
 2934
 2935    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2936        self.in_project_search = in_project_search;
 2937    }
 2938
 2939    pub fn set_custom_context_menu(
 2940        &mut self,
 2941        f: impl 'static
 2942        + Fn(
 2943            &mut Self,
 2944            DisplayPoint,
 2945            &mut Window,
 2946            &mut Context<Self>,
 2947        ) -> Option<Entity<ui::ContextMenu>>,
 2948    ) {
 2949        self.custom_context_menu = Some(Box::new(f))
 2950    }
 2951
 2952    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2953        self.completion_provider = provider;
 2954    }
 2955
 2956    #[cfg(any(test, feature = "test-support"))]
 2957    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2958        self.completion_provider.clone()
 2959    }
 2960
 2961    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2962        self.semantics_provider.clone()
 2963    }
 2964
 2965    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2966        self.semantics_provider = provider;
 2967    }
 2968
 2969    pub fn set_edit_prediction_provider<T>(
 2970        &mut self,
 2971        provider: Option<Entity<T>>,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974    ) where
 2975        T: EditPredictionProvider,
 2976    {
 2977        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2978            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2979                if this.focus_handle.is_focused(window) {
 2980                    this.update_visible_edit_prediction(window, cx);
 2981                }
 2982            }),
 2983            provider: Arc::new(provider),
 2984        });
 2985        self.update_edit_prediction_settings(cx);
 2986        self.refresh_edit_prediction(false, false, window, cx);
 2987    }
 2988
 2989    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2990        self.placeholder_display_map
 2991            .as_ref()
 2992            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2993    }
 2994
 2995    pub fn set_placeholder_text(
 2996        &mut self,
 2997        placeholder_text: &str,
 2998        window: &mut Window,
 2999        cx: &mut Context<Self>,
 3000    ) {
 3001        let multibuffer = cx
 3002            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3003
 3004        let style = window.text_style();
 3005
 3006        self.placeholder_display_map = Some(cx.new(|cx| {
 3007            DisplayMap::new(
 3008                multibuffer,
 3009                style.font(),
 3010                style.font_size.to_pixels(window.rem_size()),
 3011                None,
 3012                FILE_HEADER_HEIGHT,
 3013                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3014                Default::default(),
 3015                DiagnosticSeverity::Off,
 3016                cx,
 3017            )
 3018        }));
 3019        cx.notify();
 3020    }
 3021
 3022    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3023        self.cursor_shape = cursor_shape;
 3024
 3025        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3026        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3027
 3028        cx.notify();
 3029    }
 3030
 3031    pub fn cursor_shape(&self) -> CursorShape {
 3032        self.cursor_shape
 3033    }
 3034
 3035    pub fn set_current_line_highlight(
 3036        &mut self,
 3037        current_line_highlight: Option<CurrentLineHighlight>,
 3038    ) {
 3039        self.current_line_highlight = current_line_highlight;
 3040    }
 3041
 3042    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3043        self.collapse_matches = collapse_matches;
 3044    }
 3045
 3046    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3047        if self.collapse_matches {
 3048            return range.start..range.start;
 3049        }
 3050        range.clone()
 3051    }
 3052
 3053    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3054        self.display_map.read(cx).clip_at_line_ends
 3055    }
 3056
 3057    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3058        if self.display_map.read(cx).clip_at_line_ends != clip {
 3059            self.display_map
 3060                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3061        }
 3062    }
 3063
 3064    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3065        self.input_enabled = input_enabled;
 3066    }
 3067
 3068    pub fn set_edit_predictions_hidden_for_vim_mode(
 3069        &mut self,
 3070        hidden: bool,
 3071        window: &mut Window,
 3072        cx: &mut Context<Self>,
 3073    ) {
 3074        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3075            self.edit_predictions_hidden_for_vim_mode = hidden;
 3076            if hidden {
 3077                self.update_visible_edit_prediction(window, cx);
 3078            } else {
 3079                self.refresh_edit_prediction(true, false, window, cx);
 3080            }
 3081        }
 3082    }
 3083
 3084    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3085        self.menu_edit_predictions_policy = value;
 3086    }
 3087
 3088    pub fn set_autoindent(&mut self, autoindent: bool) {
 3089        if autoindent {
 3090            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3091        } else {
 3092            self.autoindent_mode = None;
 3093        }
 3094    }
 3095
 3096    pub fn read_only(&self, cx: &App) -> bool {
 3097        self.read_only || self.buffer.read(cx).read_only()
 3098    }
 3099
 3100    pub fn set_read_only(&mut self, read_only: bool) {
 3101        self.read_only = read_only;
 3102    }
 3103
 3104    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3105        self.use_autoclose = autoclose;
 3106    }
 3107
 3108    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3109        self.use_auto_surround = auto_surround;
 3110    }
 3111
 3112    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3113        self.auto_replace_emoji_shortcode = auto_replace;
 3114    }
 3115
 3116    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3117        self.buffer_serialization = should_serialize.then(|| {
 3118            BufferSerialization::new(
 3119                ProjectSettings::get_global(cx)
 3120                    .session
 3121                    .restore_unsaved_buffers,
 3122            )
 3123        })
 3124    }
 3125
 3126    fn should_serialize_buffer(&self) -> bool {
 3127        self.buffer_serialization.is_some()
 3128    }
 3129
 3130    pub fn toggle_edit_predictions(
 3131        &mut self,
 3132        _: &ToggleEditPrediction,
 3133        window: &mut Window,
 3134        cx: &mut Context<Self>,
 3135    ) {
 3136        if self.show_edit_predictions_override.is_some() {
 3137            self.set_show_edit_predictions(None, window, cx);
 3138        } else {
 3139            let show_edit_predictions = !self.edit_predictions_enabled();
 3140            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3141        }
 3142    }
 3143
 3144    pub fn set_show_edit_predictions(
 3145        &mut self,
 3146        show_edit_predictions: Option<bool>,
 3147        window: &mut Window,
 3148        cx: &mut Context<Self>,
 3149    ) {
 3150        self.show_edit_predictions_override = show_edit_predictions;
 3151        self.update_edit_prediction_settings(cx);
 3152
 3153        if let Some(false) = show_edit_predictions {
 3154            self.discard_edit_prediction(false, cx);
 3155        } else {
 3156            self.refresh_edit_prediction(false, true, window, cx);
 3157        }
 3158    }
 3159
 3160    fn edit_predictions_disabled_in_scope(
 3161        &self,
 3162        buffer: &Entity<Buffer>,
 3163        buffer_position: language::Anchor,
 3164        cx: &App,
 3165    ) -> bool {
 3166        let snapshot = buffer.read(cx).snapshot();
 3167        let settings = snapshot.settings_at(buffer_position, cx);
 3168
 3169        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3170            return false;
 3171        };
 3172
 3173        scope.override_name().is_some_and(|scope_name| {
 3174            settings
 3175                .edit_predictions_disabled_in
 3176                .iter()
 3177                .any(|s| s == scope_name)
 3178        })
 3179    }
 3180
 3181    pub fn set_use_modal_editing(&mut self, to: bool) {
 3182        self.use_modal_editing = to;
 3183    }
 3184
 3185    pub fn use_modal_editing(&self) -> bool {
 3186        self.use_modal_editing
 3187    }
 3188
 3189    fn selections_did_change(
 3190        &mut self,
 3191        local: bool,
 3192        old_cursor_position: &Anchor,
 3193        effects: SelectionEffects,
 3194        window: &mut Window,
 3195        cx: &mut Context<Self>,
 3196    ) {
 3197        window.invalidate_character_coordinates();
 3198
 3199        // Copy selections to primary selection buffer
 3200        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3201        if local {
 3202            let selections = self
 3203                .selections
 3204                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3205            let buffer_handle = self.buffer.read(cx).read(cx);
 3206
 3207            let mut text = String::new();
 3208            for (index, selection) in selections.iter().enumerate() {
 3209                let text_for_selection = buffer_handle
 3210                    .text_for_range(selection.start..selection.end)
 3211                    .collect::<String>();
 3212
 3213                text.push_str(&text_for_selection);
 3214                if index != selections.len() - 1 {
 3215                    text.push('\n');
 3216                }
 3217            }
 3218
 3219            if !text.is_empty() {
 3220                cx.write_to_primary(ClipboardItem::new_string(text));
 3221            }
 3222        }
 3223
 3224        let selection_anchors = self.selections.disjoint_anchors_arc();
 3225
 3226        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3227            self.buffer.update(cx, |buffer, cx| {
 3228                buffer.set_active_selections(
 3229                    &selection_anchors,
 3230                    self.selections.line_mode(),
 3231                    self.cursor_shape,
 3232                    cx,
 3233                )
 3234            });
 3235        }
 3236        let display_map = self
 3237            .display_map
 3238            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3239        let buffer = display_map.buffer_snapshot();
 3240        if self.selections.count() == 1 {
 3241            self.add_selections_state = None;
 3242        }
 3243        self.select_next_state = None;
 3244        self.select_prev_state = None;
 3245        self.select_syntax_node_history.try_clear();
 3246        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3247        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3248        self.take_rename(false, window, cx);
 3249
 3250        let newest_selection = self.selections.newest_anchor();
 3251        let new_cursor_position = newest_selection.head();
 3252        let selection_start = newest_selection.start;
 3253
 3254        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3255            self.push_to_nav_history(
 3256                *old_cursor_position,
 3257                Some(new_cursor_position.to_point(buffer)),
 3258                false,
 3259                effects.nav_history == Some(true),
 3260                cx,
 3261            );
 3262        }
 3263
 3264        if local {
 3265            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3266                self.register_buffer(buffer_id, cx);
 3267            }
 3268
 3269            let mut context_menu = self.context_menu.borrow_mut();
 3270            let completion_menu = match context_menu.as_ref() {
 3271                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3272                Some(CodeContextMenu::CodeActions(_)) => {
 3273                    *context_menu = None;
 3274                    None
 3275                }
 3276                None => None,
 3277            };
 3278            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3279            drop(context_menu);
 3280
 3281            if effects.completions
 3282                && let Some(completion_position) = completion_position
 3283            {
 3284                let start_offset = selection_start.to_offset(buffer);
 3285                let position_matches = start_offset == completion_position.to_offset(buffer);
 3286                let continue_showing = if position_matches {
 3287                    if self.snippet_stack.is_empty() {
 3288                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3289                            == Some(CharKind::Word)
 3290                    } else {
 3291                        // Snippet choices can be shown even when the cursor is in whitespace.
 3292                        // Dismissing the menu with actions like backspace is handled by
 3293                        // invalidation regions.
 3294                        true
 3295                    }
 3296                } else {
 3297                    false
 3298                };
 3299
 3300                if continue_showing {
 3301                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3302                } else {
 3303                    self.hide_context_menu(window, cx);
 3304                }
 3305            }
 3306
 3307            hide_hover(self, cx);
 3308
 3309            if old_cursor_position.to_display_point(&display_map).row()
 3310                != new_cursor_position.to_display_point(&display_map).row()
 3311            {
 3312                self.available_code_actions.take();
 3313            }
 3314            self.refresh_code_actions(window, cx);
 3315            self.refresh_document_highlights(cx);
 3316            refresh_linked_ranges(self, window, cx);
 3317
 3318            self.refresh_selected_text_highlights(false, window, cx);
 3319            self.refresh_matching_bracket_highlights(window, cx);
 3320            self.update_visible_edit_prediction(window, cx);
 3321            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3322            self.inline_blame_popover.take();
 3323            if self.git_blame_inline_enabled {
 3324                self.start_inline_blame_timer(window, cx);
 3325            }
 3326        }
 3327
 3328        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3329        cx.emit(EditorEvent::SelectionsChanged { local });
 3330
 3331        let selections = &self.selections.disjoint_anchors_arc();
 3332        if selections.len() == 1 {
 3333            cx.emit(SearchEvent::ActiveMatchChanged)
 3334        }
 3335        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3336            let inmemory_selections = selections
 3337                .iter()
 3338                .map(|s| {
 3339                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3340                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3341                })
 3342                .collect();
 3343            self.update_restoration_data(cx, |data| {
 3344                data.selections = inmemory_selections;
 3345            });
 3346
 3347            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3348                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3349            {
 3350                let snapshot = self.buffer().read(cx).snapshot(cx);
 3351                let selections = selections.clone();
 3352                let background_executor = cx.background_executor().clone();
 3353                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3354                self.serialize_selections = cx.background_spawn(async move {
 3355                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3356                    let db_selections = selections
 3357                        .iter()
 3358                        .map(|selection| {
 3359                            (
 3360                                selection.start.to_offset(&snapshot).0,
 3361                                selection.end.to_offset(&snapshot).0,
 3362                            )
 3363                        })
 3364                        .collect();
 3365
 3366                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3367                        .await
 3368                        .with_context(|| {
 3369                            format!(
 3370                                "persisting editor selections for editor {editor_id}, \
 3371                                workspace {workspace_id:?}"
 3372                            )
 3373                        })
 3374                        .log_err();
 3375                });
 3376            }
 3377        }
 3378
 3379        cx.notify();
 3380    }
 3381
 3382    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3383        use text::ToOffset as _;
 3384        use text::ToPoint as _;
 3385
 3386        if self.mode.is_minimap()
 3387            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3388        {
 3389            return;
 3390        }
 3391
 3392        if !self.buffer().read(cx).is_singleton() {
 3393            return;
 3394        }
 3395
 3396        let display_snapshot = self
 3397            .display_map
 3398            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3399        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3400            return;
 3401        };
 3402        let inmemory_folds = display_snapshot
 3403            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3404            .map(|fold| {
 3405                fold.range.start.text_anchor.to_point(&snapshot)
 3406                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3407            })
 3408            .collect();
 3409        self.update_restoration_data(cx, |data| {
 3410            data.folds = inmemory_folds;
 3411        });
 3412
 3413        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3414            return;
 3415        };
 3416        let background_executor = cx.background_executor().clone();
 3417        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3418        let db_folds = display_snapshot
 3419            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3420            .map(|fold| {
 3421                (
 3422                    fold.range.start.text_anchor.to_offset(&snapshot),
 3423                    fold.range.end.text_anchor.to_offset(&snapshot),
 3424                )
 3425            })
 3426            .collect();
 3427        self.serialize_folds = cx.background_spawn(async move {
 3428            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3429            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3430                .await
 3431                .with_context(|| {
 3432                    format!(
 3433                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3434                    )
 3435                })
 3436                .log_err();
 3437        });
 3438    }
 3439
 3440    pub fn sync_selections(
 3441        &mut self,
 3442        other: Entity<Editor>,
 3443        cx: &mut Context<Self>,
 3444    ) -> gpui::Subscription {
 3445        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3446        if !other_selections.is_empty() {
 3447            self.selections
 3448                .change_with(&self.display_snapshot(cx), |selections| {
 3449                    selections.select_anchors(other_selections);
 3450                });
 3451        }
 3452
 3453        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3454            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3455                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3456                if other_selections.is_empty() {
 3457                    return;
 3458                }
 3459                let snapshot = this.display_snapshot(cx);
 3460                this.selections.change_with(&snapshot, |selections| {
 3461                    selections.select_anchors(other_selections);
 3462                });
 3463            }
 3464        });
 3465
 3466        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3467            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3468                let these_selections = this.selections.disjoint_anchors().to_vec();
 3469                if these_selections.is_empty() {
 3470                    return;
 3471                }
 3472                other.update(cx, |other_editor, cx| {
 3473                    let snapshot = other_editor.display_snapshot(cx);
 3474                    other_editor
 3475                        .selections
 3476                        .change_with(&snapshot, |selections| {
 3477                            selections.select_anchors(these_selections);
 3478                        })
 3479                });
 3480            }
 3481        });
 3482
 3483        Subscription::join(other_subscription, this_subscription)
 3484    }
 3485
 3486    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3487        if self.buffer().read(cx).is_singleton() {
 3488            return;
 3489        }
 3490        let snapshot = self.buffer.read(cx).snapshot(cx);
 3491        let buffer_ids: HashSet<BufferId> = self
 3492            .selections
 3493            .disjoint_anchor_ranges()
 3494            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3495            .collect();
 3496        for buffer_id in buffer_ids {
 3497            self.unfold_buffer(buffer_id, cx);
 3498        }
 3499    }
 3500
 3501    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3502    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3503    /// effects of selection change occur at the end of the transaction.
 3504    pub fn change_selections<R>(
 3505        &mut self,
 3506        effects: SelectionEffects,
 3507        window: &mut Window,
 3508        cx: &mut Context<Self>,
 3509        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3510    ) -> R {
 3511        let snapshot = self.display_snapshot(cx);
 3512        if let Some(state) = &mut self.deferred_selection_effects_state {
 3513            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3514            state.effects.completions = effects.completions;
 3515            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3516            let (changed, result) = self.selections.change_with(&snapshot, change);
 3517            state.changed |= changed;
 3518            return result;
 3519        }
 3520        let mut state = DeferredSelectionEffectsState {
 3521            changed: false,
 3522            effects,
 3523            old_cursor_position: self.selections.newest_anchor().head(),
 3524            history_entry: SelectionHistoryEntry {
 3525                selections: self.selections.disjoint_anchors_arc(),
 3526                select_next_state: self.select_next_state.clone(),
 3527                select_prev_state: self.select_prev_state.clone(),
 3528                add_selections_state: self.add_selections_state.clone(),
 3529            },
 3530        };
 3531        let (changed, result) = self.selections.change_with(&snapshot, change);
 3532        state.changed = state.changed || changed;
 3533        if self.defer_selection_effects {
 3534            self.deferred_selection_effects_state = Some(state);
 3535        } else {
 3536            self.apply_selection_effects(state, window, cx);
 3537        }
 3538        result
 3539    }
 3540
 3541    /// Defers the effects of selection change, so that the effects of multiple calls to
 3542    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3543    /// to selection history and the state of popovers based on selection position aren't
 3544    /// erroneously updated.
 3545    pub fn with_selection_effects_deferred<R>(
 3546        &mut self,
 3547        window: &mut Window,
 3548        cx: &mut Context<Self>,
 3549        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3550    ) -> R {
 3551        let already_deferred = self.defer_selection_effects;
 3552        self.defer_selection_effects = true;
 3553        let result = update(self, window, cx);
 3554        if !already_deferred {
 3555            self.defer_selection_effects = false;
 3556            if let Some(state) = self.deferred_selection_effects_state.take() {
 3557                self.apply_selection_effects(state, window, cx);
 3558            }
 3559        }
 3560        result
 3561    }
 3562
 3563    fn apply_selection_effects(
 3564        &mut self,
 3565        state: DeferredSelectionEffectsState,
 3566        window: &mut Window,
 3567        cx: &mut Context<Self>,
 3568    ) {
 3569        if state.changed {
 3570            self.selection_history.push(state.history_entry);
 3571
 3572            if let Some(autoscroll) = state.effects.scroll {
 3573                self.request_autoscroll(autoscroll, cx);
 3574            }
 3575
 3576            let old_cursor_position = &state.old_cursor_position;
 3577
 3578            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3579
 3580            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3581                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3582            }
 3583        }
 3584    }
 3585
 3586    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3587    where
 3588        I: IntoIterator<Item = (Range<S>, T)>,
 3589        S: ToOffset,
 3590        T: Into<Arc<str>>,
 3591    {
 3592        if self.read_only(cx) {
 3593            return;
 3594        }
 3595
 3596        self.buffer
 3597            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3598    }
 3599
 3600    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3601    where
 3602        I: IntoIterator<Item = (Range<S>, T)>,
 3603        S: ToOffset,
 3604        T: Into<Arc<str>>,
 3605    {
 3606        if self.read_only(cx) {
 3607            return;
 3608        }
 3609
 3610        self.buffer.update(cx, |buffer, cx| {
 3611            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3612        });
 3613    }
 3614
 3615    pub fn edit_with_block_indent<I, S, T>(
 3616        &mut self,
 3617        edits: I,
 3618        original_indent_columns: Vec<Option<u32>>,
 3619        cx: &mut Context<Self>,
 3620    ) where
 3621        I: IntoIterator<Item = (Range<S>, T)>,
 3622        S: ToOffset,
 3623        T: Into<Arc<str>>,
 3624    {
 3625        if self.read_only(cx) {
 3626            return;
 3627        }
 3628
 3629        self.buffer.update(cx, |buffer, cx| {
 3630            buffer.edit(
 3631                edits,
 3632                Some(AutoindentMode::Block {
 3633                    original_indent_columns,
 3634                }),
 3635                cx,
 3636            )
 3637        });
 3638    }
 3639
 3640    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3641        self.hide_context_menu(window, cx);
 3642
 3643        match phase {
 3644            SelectPhase::Begin {
 3645                position,
 3646                add,
 3647                click_count,
 3648            } => self.begin_selection(position, add, click_count, window, cx),
 3649            SelectPhase::BeginColumnar {
 3650                position,
 3651                goal_column,
 3652                reset,
 3653                mode,
 3654            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3655            SelectPhase::Extend {
 3656                position,
 3657                click_count,
 3658            } => self.extend_selection(position, click_count, window, cx),
 3659            SelectPhase::Update {
 3660                position,
 3661                goal_column,
 3662                scroll_delta,
 3663            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3664            SelectPhase::End => self.end_selection(window, cx),
 3665        }
 3666    }
 3667
 3668    fn extend_selection(
 3669        &mut self,
 3670        position: DisplayPoint,
 3671        click_count: usize,
 3672        window: &mut Window,
 3673        cx: &mut Context<Self>,
 3674    ) {
 3675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3676        let tail = self
 3677            .selections
 3678            .newest::<MultiBufferOffset>(&display_map)
 3679            .tail();
 3680        let click_count = click_count.max(match self.selections.select_mode() {
 3681            SelectMode::Character => 1,
 3682            SelectMode::Word(_) => 2,
 3683            SelectMode::Line(_) => 3,
 3684            SelectMode::All => 4,
 3685        });
 3686        self.begin_selection(position, false, click_count, window, cx);
 3687
 3688        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3689
 3690        let current_selection = match self.selections.select_mode() {
 3691            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3692            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3693        };
 3694
 3695        let mut pending_selection = self
 3696            .selections
 3697            .pending_anchor()
 3698            .cloned()
 3699            .expect("extend_selection not called with pending selection");
 3700
 3701        if pending_selection
 3702            .start
 3703            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3704            == Ordering::Greater
 3705        {
 3706            pending_selection.start = current_selection.start;
 3707        }
 3708        if pending_selection
 3709            .end
 3710            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3711            == Ordering::Less
 3712        {
 3713            pending_selection.end = current_selection.end;
 3714            pending_selection.reversed = true;
 3715        }
 3716
 3717        let mut pending_mode = self.selections.pending_mode().unwrap();
 3718        match &mut pending_mode {
 3719            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3720            _ => {}
 3721        }
 3722
 3723        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3724            SelectionEffects::scroll(Autoscroll::fit())
 3725        } else {
 3726            SelectionEffects::no_scroll()
 3727        };
 3728
 3729        self.change_selections(effects, window, cx, |s| {
 3730            s.set_pending(pending_selection.clone(), pending_mode);
 3731            s.set_is_extending(true);
 3732        });
 3733    }
 3734
 3735    fn begin_selection(
 3736        &mut self,
 3737        position: DisplayPoint,
 3738        add: bool,
 3739        click_count: usize,
 3740        window: &mut Window,
 3741        cx: &mut Context<Self>,
 3742    ) {
 3743        if !self.focus_handle.is_focused(window) {
 3744            self.last_focused_descendant = None;
 3745            window.focus(&self.focus_handle);
 3746        }
 3747
 3748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3749        let buffer = display_map.buffer_snapshot();
 3750        let position = display_map.clip_point(position, Bias::Left);
 3751
 3752        let start;
 3753        let end;
 3754        let mode;
 3755        let mut auto_scroll;
 3756        match click_count {
 3757            1 => {
 3758                start = buffer.anchor_before(position.to_point(&display_map));
 3759                end = start;
 3760                mode = SelectMode::Character;
 3761                auto_scroll = true;
 3762            }
 3763            2 => {
 3764                let position = display_map
 3765                    .clip_point(position, Bias::Left)
 3766                    .to_offset(&display_map, Bias::Left);
 3767                let (range, _) = buffer.surrounding_word(position, None);
 3768                start = buffer.anchor_before(range.start);
 3769                end = buffer.anchor_before(range.end);
 3770                mode = SelectMode::Word(start..end);
 3771                auto_scroll = true;
 3772            }
 3773            3 => {
 3774                let position = display_map
 3775                    .clip_point(position, Bias::Left)
 3776                    .to_point(&display_map);
 3777                let line_start = display_map.prev_line_boundary(position).0;
 3778                let next_line_start = buffer.clip_point(
 3779                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3780                    Bias::Left,
 3781                );
 3782                start = buffer.anchor_before(line_start);
 3783                end = buffer.anchor_before(next_line_start);
 3784                mode = SelectMode::Line(start..end);
 3785                auto_scroll = true;
 3786            }
 3787            _ => {
 3788                start = buffer.anchor_before(MultiBufferOffset(0));
 3789                end = buffer.anchor_before(buffer.len());
 3790                mode = SelectMode::All;
 3791                auto_scroll = false;
 3792            }
 3793        }
 3794        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3795
 3796        let point_to_delete: Option<usize> = {
 3797            let selected_points: Vec<Selection<Point>> =
 3798                self.selections.disjoint_in_range(start..end, &display_map);
 3799
 3800            if !add || click_count > 1 {
 3801                None
 3802            } else if !selected_points.is_empty() {
 3803                Some(selected_points[0].id)
 3804            } else {
 3805                let clicked_point_already_selected =
 3806                    self.selections.disjoint_anchors().iter().find(|selection| {
 3807                        selection.start.to_point(buffer) == start.to_point(buffer)
 3808                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3809                    });
 3810
 3811                clicked_point_already_selected.map(|selection| selection.id)
 3812            }
 3813        };
 3814
 3815        let selections_count = self.selections.count();
 3816        let effects = if auto_scroll {
 3817            SelectionEffects::default()
 3818        } else {
 3819            SelectionEffects::no_scroll()
 3820        };
 3821
 3822        self.change_selections(effects, window, cx, |s| {
 3823            if let Some(point_to_delete) = point_to_delete {
 3824                s.delete(point_to_delete);
 3825
 3826                if selections_count == 1 {
 3827                    s.set_pending_anchor_range(start..end, mode);
 3828                }
 3829            } else {
 3830                if !add {
 3831                    s.clear_disjoint();
 3832                }
 3833
 3834                s.set_pending_anchor_range(start..end, mode);
 3835            }
 3836        });
 3837    }
 3838
 3839    fn begin_columnar_selection(
 3840        &mut self,
 3841        position: DisplayPoint,
 3842        goal_column: u32,
 3843        reset: bool,
 3844        mode: ColumnarMode,
 3845        window: &mut Window,
 3846        cx: &mut Context<Self>,
 3847    ) {
 3848        if !self.focus_handle.is_focused(window) {
 3849            self.last_focused_descendant = None;
 3850            window.focus(&self.focus_handle);
 3851        }
 3852
 3853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3854
 3855        if reset {
 3856            let pointer_position = display_map
 3857                .buffer_snapshot()
 3858                .anchor_before(position.to_point(&display_map));
 3859
 3860            self.change_selections(
 3861                SelectionEffects::scroll(Autoscroll::newest()),
 3862                window,
 3863                cx,
 3864                |s| {
 3865                    s.clear_disjoint();
 3866                    s.set_pending_anchor_range(
 3867                        pointer_position..pointer_position,
 3868                        SelectMode::Character,
 3869                    );
 3870                },
 3871            );
 3872        };
 3873
 3874        let tail = self.selections.newest::<Point>(&display_map).tail();
 3875        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3876        self.columnar_selection_state = match mode {
 3877            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3878                selection_tail: selection_anchor,
 3879                display_point: if reset {
 3880                    if position.column() != goal_column {
 3881                        Some(DisplayPoint::new(position.row(), goal_column))
 3882                    } else {
 3883                        None
 3884                    }
 3885                } else {
 3886                    None
 3887                },
 3888            }),
 3889            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3890                selection_tail: selection_anchor,
 3891            }),
 3892        };
 3893
 3894        if !reset {
 3895            self.select_columns(position, goal_column, &display_map, window, cx);
 3896        }
 3897    }
 3898
 3899    fn update_selection(
 3900        &mut self,
 3901        position: DisplayPoint,
 3902        goal_column: u32,
 3903        scroll_delta: gpui::Point<f32>,
 3904        window: &mut Window,
 3905        cx: &mut Context<Self>,
 3906    ) {
 3907        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3908
 3909        if self.columnar_selection_state.is_some() {
 3910            self.select_columns(position, goal_column, &display_map, window, cx);
 3911        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3912            let buffer = display_map.buffer_snapshot();
 3913            let head;
 3914            let tail;
 3915            let mode = self.selections.pending_mode().unwrap();
 3916            match &mode {
 3917                SelectMode::Character => {
 3918                    head = position.to_point(&display_map);
 3919                    tail = pending.tail().to_point(buffer);
 3920                }
 3921                SelectMode::Word(original_range) => {
 3922                    let offset = display_map
 3923                        .clip_point(position, Bias::Left)
 3924                        .to_offset(&display_map, Bias::Left);
 3925                    let original_range = original_range.to_offset(buffer);
 3926
 3927                    let head_offset = if buffer.is_inside_word(offset, None)
 3928                        || original_range.contains(&offset)
 3929                    {
 3930                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3931                        if word_range.start < original_range.start {
 3932                            word_range.start
 3933                        } else {
 3934                            word_range.end
 3935                        }
 3936                    } else {
 3937                        offset
 3938                    };
 3939
 3940                    head = head_offset.to_point(buffer);
 3941                    if head_offset <= original_range.start {
 3942                        tail = original_range.end.to_point(buffer);
 3943                    } else {
 3944                        tail = original_range.start.to_point(buffer);
 3945                    }
 3946                }
 3947                SelectMode::Line(original_range) => {
 3948                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3949
 3950                    let position = display_map
 3951                        .clip_point(position, Bias::Left)
 3952                        .to_point(&display_map);
 3953                    let line_start = display_map.prev_line_boundary(position).0;
 3954                    let next_line_start = buffer.clip_point(
 3955                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3956                        Bias::Left,
 3957                    );
 3958
 3959                    if line_start < original_range.start {
 3960                        head = line_start
 3961                    } else {
 3962                        head = next_line_start
 3963                    }
 3964
 3965                    if head <= original_range.start {
 3966                        tail = original_range.end;
 3967                    } else {
 3968                        tail = original_range.start;
 3969                    }
 3970                }
 3971                SelectMode::All => {
 3972                    return;
 3973                }
 3974            };
 3975
 3976            if head < tail {
 3977                pending.start = buffer.anchor_before(head);
 3978                pending.end = buffer.anchor_before(tail);
 3979                pending.reversed = true;
 3980            } else {
 3981                pending.start = buffer.anchor_before(tail);
 3982                pending.end = buffer.anchor_before(head);
 3983                pending.reversed = false;
 3984            }
 3985
 3986            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3987                s.set_pending(pending.clone(), mode);
 3988            });
 3989        } else {
 3990            log::error!("update_selection dispatched with no pending selection");
 3991            return;
 3992        }
 3993
 3994        self.apply_scroll_delta(scroll_delta, window, cx);
 3995        cx.notify();
 3996    }
 3997
 3998    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3999        self.columnar_selection_state.take();
 4000        if let Some(pending_mode) = self.selections.pending_mode() {
 4001            let selections = self
 4002                .selections
 4003                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4004            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4005                s.select(selections);
 4006                s.clear_pending();
 4007                if s.is_extending() {
 4008                    s.set_is_extending(false);
 4009                } else {
 4010                    s.set_select_mode(pending_mode);
 4011                }
 4012            });
 4013        }
 4014    }
 4015
 4016    fn select_columns(
 4017        &mut self,
 4018        head: DisplayPoint,
 4019        goal_column: u32,
 4020        display_map: &DisplaySnapshot,
 4021        window: &mut Window,
 4022        cx: &mut Context<Self>,
 4023    ) {
 4024        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4025            return;
 4026        };
 4027
 4028        let tail = match columnar_state {
 4029            ColumnarSelectionState::FromMouse {
 4030                selection_tail,
 4031                display_point,
 4032            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4033            ColumnarSelectionState::FromSelection { selection_tail } => {
 4034                selection_tail.to_display_point(display_map)
 4035            }
 4036        };
 4037
 4038        let start_row = cmp::min(tail.row(), head.row());
 4039        let end_row = cmp::max(tail.row(), head.row());
 4040        let start_column = cmp::min(tail.column(), goal_column);
 4041        let end_column = cmp::max(tail.column(), goal_column);
 4042        let reversed = start_column < tail.column();
 4043
 4044        let selection_ranges = (start_row.0..=end_row.0)
 4045            .map(DisplayRow)
 4046            .filter_map(|row| {
 4047                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4048                    || start_column <= display_map.line_len(row))
 4049                    && !display_map.is_block_line(row)
 4050                {
 4051                    let start = display_map
 4052                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4053                        .to_point(display_map);
 4054                    let end = display_map
 4055                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4056                        .to_point(display_map);
 4057                    if reversed {
 4058                        Some(end..start)
 4059                    } else {
 4060                        Some(start..end)
 4061                    }
 4062                } else {
 4063                    None
 4064                }
 4065            })
 4066            .collect::<Vec<_>>();
 4067        if selection_ranges.is_empty() {
 4068            return;
 4069        }
 4070
 4071        let ranges = match columnar_state {
 4072            ColumnarSelectionState::FromMouse { .. } => {
 4073                let mut non_empty_ranges = selection_ranges
 4074                    .iter()
 4075                    .filter(|selection_range| selection_range.start != selection_range.end)
 4076                    .peekable();
 4077                if non_empty_ranges.peek().is_some() {
 4078                    non_empty_ranges.cloned().collect()
 4079                } else {
 4080                    selection_ranges
 4081                }
 4082            }
 4083            _ => selection_ranges,
 4084        };
 4085
 4086        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4087            s.select_ranges(ranges);
 4088        });
 4089        cx.notify();
 4090    }
 4091
 4092    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4093        self.selections
 4094            .all_adjusted(snapshot)
 4095            .iter()
 4096            .any(|selection| !selection.is_empty())
 4097    }
 4098
 4099    pub fn has_pending_nonempty_selection(&self) -> bool {
 4100        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4101            Some(Selection { start, end, .. }) => start != end,
 4102            None => false,
 4103        };
 4104
 4105        pending_nonempty_selection
 4106            || (self.columnar_selection_state.is_some()
 4107                && self.selections.disjoint_anchors().len() > 1)
 4108    }
 4109
 4110    pub fn has_pending_selection(&self) -> bool {
 4111        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4112    }
 4113
 4114    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4115        self.selection_mark_mode = false;
 4116        self.selection_drag_state = SelectionDragState::None;
 4117
 4118        if self.dismiss_menus_and_popups(true, window, cx) {
 4119            cx.notify();
 4120            return;
 4121        }
 4122        if self.clear_expanded_diff_hunks(cx) {
 4123            cx.notify();
 4124            return;
 4125        }
 4126        if self.show_git_blame_gutter {
 4127            self.show_git_blame_gutter = false;
 4128            cx.notify();
 4129            return;
 4130        }
 4131
 4132        if self.mode.is_full()
 4133            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4134        {
 4135            cx.notify();
 4136            return;
 4137        }
 4138
 4139        cx.propagate();
 4140    }
 4141
 4142    pub fn dismiss_menus_and_popups(
 4143        &mut self,
 4144        is_user_requested: bool,
 4145        window: &mut Window,
 4146        cx: &mut Context<Self>,
 4147    ) -> bool {
 4148        let mut dismissed = false;
 4149
 4150        dismissed |= self.take_rename(false, window, cx).is_some();
 4151        dismissed |= self.hide_blame_popover(true, cx);
 4152        dismissed |= hide_hover(self, cx);
 4153        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4154        dismissed |= self.hide_context_menu(window, cx).is_some();
 4155        dismissed |= self.mouse_context_menu.take().is_some();
 4156        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4157        dismissed |= self.snippet_stack.pop().is_some();
 4158
 4159        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4160            self.dismiss_diagnostics(cx);
 4161            dismissed = true;
 4162        }
 4163
 4164        dismissed
 4165    }
 4166
 4167    fn linked_editing_ranges_for(
 4168        &self,
 4169        selection: Range<text::Anchor>,
 4170        cx: &App,
 4171    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4172        if self.linked_edit_ranges.is_empty() {
 4173            return None;
 4174        }
 4175        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4176            selection.end.buffer_id.and_then(|end_buffer_id| {
 4177                if selection.start.buffer_id != Some(end_buffer_id) {
 4178                    return None;
 4179                }
 4180                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4181                let snapshot = buffer.read(cx).snapshot();
 4182                self.linked_edit_ranges
 4183                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4184                    .map(|ranges| (ranges, snapshot, buffer))
 4185            })?;
 4186        use text::ToOffset as TO;
 4187        // find offset from the start of current range to current cursor position
 4188        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4189
 4190        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4191        let start_difference = start_offset - start_byte_offset;
 4192        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4193        let end_difference = end_offset - start_byte_offset;
 4194        // Current range has associated linked ranges.
 4195        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4196        for range in linked_ranges.iter() {
 4197            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4198            let end_offset = start_offset + end_difference;
 4199            let start_offset = start_offset + start_difference;
 4200            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4201                continue;
 4202            }
 4203            if self.selections.disjoint_anchor_ranges().any(|s| {
 4204                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4205                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4206                {
 4207                    return false;
 4208                }
 4209                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4210                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4211            }) {
 4212                continue;
 4213            }
 4214            let start = buffer_snapshot.anchor_after(start_offset);
 4215            let end = buffer_snapshot.anchor_after(end_offset);
 4216            linked_edits
 4217                .entry(buffer.clone())
 4218                .or_default()
 4219                .push(start..end);
 4220        }
 4221        Some(linked_edits)
 4222    }
 4223
 4224    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4225        let text: Arc<str> = text.into();
 4226
 4227        if self.read_only(cx) {
 4228            return;
 4229        }
 4230
 4231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4232
 4233        self.unfold_buffers_with_selections(cx);
 4234
 4235        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4236        let mut bracket_inserted = false;
 4237        let mut edits = Vec::new();
 4238        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4239        let mut new_selections = Vec::with_capacity(selections.len());
 4240        let mut new_autoclose_regions = Vec::new();
 4241        let snapshot = self.buffer.read(cx).read(cx);
 4242        let mut clear_linked_edit_ranges = false;
 4243
 4244        for (selection, autoclose_region) in
 4245            self.selections_with_autoclose_regions(selections, &snapshot)
 4246        {
 4247            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4248                // Determine if the inserted text matches the opening or closing
 4249                // bracket of any of this language's bracket pairs.
 4250                let mut bracket_pair = None;
 4251                let mut is_bracket_pair_start = false;
 4252                let mut is_bracket_pair_end = false;
 4253                if !text.is_empty() {
 4254                    let mut bracket_pair_matching_end = None;
 4255                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4256                    //  and they are removing the character that triggered IME popup.
 4257                    for (pair, enabled) in scope.brackets() {
 4258                        if !pair.close && !pair.surround {
 4259                            continue;
 4260                        }
 4261
 4262                        if enabled && pair.start.ends_with(text.as_ref()) {
 4263                            let prefix_len = pair.start.len() - text.len();
 4264                            let preceding_text_matches_prefix = prefix_len == 0
 4265                                || (selection.start.column >= (prefix_len as u32)
 4266                                    && snapshot.contains_str_at(
 4267                                        Point::new(
 4268                                            selection.start.row,
 4269                                            selection.start.column - (prefix_len as u32),
 4270                                        ),
 4271                                        &pair.start[..prefix_len],
 4272                                    ));
 4273                            if preceding_text_matches_prefix {
 4274                                bracket_pair = Some(pair.clone());
 4275                                is_bracket_pair_start = true;
 4276                                break;
 4277                            }
 4278                        }
 4279                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4280                        {
 4281                            // take first bracket pair matching end, but don't break in case a later bracket
 4282                            // pair matches start
 4283                            bracket_pair_matching_end = Some(pair.clone());
 4284                        }
 4285                    }
 4286                    if let Some(end) = bracket_pair_matching_end
 4287                        && bracket_pair.is_none()
 4288                    {
 4289                        bracket_pair = Some(end);
 4290                        is_bracket_pair_end = true;
 4291                    }
 4292                }
 4293
 4294                if let Some(bracket_pair) = bracket_pair {
 4295                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4296                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4297                    let auto_surround =
 4298                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4299                    if selection.is_empty() {
 4300                        if is_bracket_pair_start {
 4301                            // If the inserted text is a suffix of an opening bracket and the
 4302                            // selection is preceded by the rest of the opening bracket, then
 4303                            // insert the closing bracket.
 4304                            let following_text_allows_autoclose = snapshot
 4305                                .chars_at(selection.start)
 4306                                .next()
 4307                                .is_none_or(|c| scope.should_autoclose_before(c));
 4308
 4309                            let preceding_text_allows_autoclose = selection.start.column == 0
 4310                                || snapshot
 4311                                    .reversed_chars_at(selection.start)
 4312                                    .next()
 4313                                    .is_none_or(|c| {
 4314                                        bracket_pair.start != bracket_pair.end
 4315                                            || !snapshot
 4316                                                .char_classifier_at(selection.start)
 4317                                                .is_word(c)
 4318                                    });
 4319
 4320                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4321                                && bracket_pair.start.len() == 1
 4322                            {
 4323                                let target = bracket_pair.start.chars().next().unwrap();
 4324                                let current_line_count = snapshot
 4325                                    .reversed_chars_at(selection.start)
 4326                                    .take_while(|&c| c != '\n')
 4327                                    .filter(|&c| c == target)
 4328                                    .count();
 4329                                current_line_count % 2 == 1
 4330                            } else {
 4331                                false
 4332                            };
 4333
 4334                            if autoclose
 4335                                && bracket_pair.close
 4336                                && following_text_allows_autoclose
 4337                                && preceding_text_allows_autoclose
 4338                                && !is_closing_quote
 4339                            {
 4340                                let anchor = snapshot.anchor_before(selection.end);
 4341                                new_selections.push((selection.map(|_| anchor), text.len()));
 4342                                new_autoclose_regions.push((
 4343                                    anchor,
 4344                                    text.len(),
 4345                                    selection.id,
 4346                                    bracket_pair.clone(),
 4347                                ));
 4348                                edits.push((
 4349                                    selection.range(),
 4350                                    format!("{}{}", text, bracket_pair.end).into(),
 4351                                ));
 4352                                bracket_inserted = true;
 4353                                continue;
 4354                            }
 4355                        }
 4356
 4357                        if let Some(region) = autoclose_region {
 4358                            // If the selection is followed by an auto-inserted closing bracket,
 4359                            // then don't insert that closing bracket again; just move the selection
 4360                            // past the closing bracket.
 4361                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4362                                && text.as_ref() == region.pair.end.as_str()
 4363                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4364                            if should_skip {
 4365                                let anchor = snapshot.anchor_after(selection.end);
 4366                                new_selections
 4367                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4368                                continue;
 4369                            }
 4370                        }
 4371
 4372                        let always_treat_brackets_as_autoclosed = snapshot
 4373                            .language_settings_at(selection.start, cx)
 4374                            .always_treat_brackets_as_autoclosed;
 4375                        if always_treat_brackets_as_autoclosed
 4376                            && is_bracket_pair_end
 4377                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4378                        {
 4379                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4380                            // and the inserted text is a closing bracket and the selection is followed
 4381                            // by the closing bracket then move the selection past the closing bracket.
 4382                            let anchor = snapshot.anchor_after(selection.end);
 4383                            new_selections.push((selection.map(|_| anchor), text.len()));
 4384                            continue;
 4385                        }
 4386                    }
 4387                    // If an opening bracket is 1 character long and is typed while
 4388                    // text is selected, then surround that text with the bracket pair.
 4389                    else if auto_surround
 4390                        && bracket_pair.surround
 4391                        && is_bracket_pair_start
 4392                        && bracket_pair.start.chars().count() == 1
 4393                    {
 4394                        edits.push((selection.start..selection.start, text.clone()));
 4395                        edits.push((
 4396                            selection.end..selection.end,
 4397                            bracket_pair.end.as_str().into(),
 4398                        ));
 4399                        bracket_inserted = true;
 4400                        new_selections.push((
 4401                            Selection {
 4402                                id: selection.id,
 4403                                start: snapshot.anchor_after(selection.start),
 4404                                end: snapshot.anchor_before(selection.end),
 4405                                reversed: selection.reversed,
 4406                                goal: selection.goal,
 4407                            },
 4408                            0,
 4409                        ));
 4410                        continue;
 4411                    }
 4412                }
 4413            }
 4414
 4415            if self.auto_replace_emoji_shortcode
 4416                && selection.is_empty()
 4417                && text.as_ref().ends_with(':')
 4418                && let Some(possible_emoji_short_code) =
 4419                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4420                && !possible_emoji_short_code.is_empty()
 4421                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4422            {
 4423                let emoji_shortcode_start = Point::new(
 4424                    selection.start.row,
 4425                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4426                );
 4427
 4428                // Remove shortcode from buffer
 4429                edits.push((
 4430                    emoji_shortcode_start..selection.start,
 4431                    "".to_string().into(),
 4432                ));
 4433                new_selections.push((
 4434                    Selection {
 4435                        id: selection.id,
 4436                        start: snapshot.anchor_after(emoji_shortcode_start),
 4437                        end: snapshot.anchor_before(selection.start),
 4438                        reversed: selection.reversed,
 4439                        goal: selection.goal,
 4440                    },
 4441                    0,
 4442                ));
 4443
 4444                // Insert emoji
 4445                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4446                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4447                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4448
 4449                continue;
 4450            }
 4451
 4452            // If not handling any auto-close operation, then just replace the selected
 4453            // text with the given input and move the selection to the end of the
 4454            // newly inserted text.
 4455            let anchor = snapshot.anchor_after(selection.end);
 4456            if !self.linked_edit_ranges.is_empty() {
 4457                let start_anchor = snapshot.anchor_before(selection.start);
 4458
 4459                let is_word_char = text.chars().next().is_none_or(|char| {
 4460                    let classifier = snapshot
 4461                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4462                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4463                    classifier.is_word(char)
 4464                });
 4465
 4466                if is_word_char {
 4467                    if let Some(ranges) = self
 4468                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4469                    {
 4470                        for (buffer, edits) in ranges {
 4471                            linked_edits
 4472                                .entry(buffer.clone())
 4473                                .or_default()
 4474                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4475                        }
 4476                    }
 4477                } else {
 4478                    clear_linked_edit_ranges = true;
 4479                }
 4480            }
 4481
 4482            new_selections.push((selection.map(|_| anchor), 0));
 4483            edits.push((selection.start..selection.end, text.clone()));
 4484        }
 4485
 4486        drop(snapshot);
 4487
 4488        self.transact(window, cx, |this, window, cx| {
 4489            if clear_linked_edit_ranges {
 4490                this.linked_edit_ranges.clear();
 4491            }
 4492            let initial_buffer_versions =
 4493                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4494
 4495            this.buffer.update(cx, |buffer, cx| {
 4496                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4497            });
 4498            for (buffer, edits) in linked_edits {
 4499                buffer.update(cx, |buffer, cx| {
 4500                    let snapshot = buffer.snapshot();
 4501                    let edits = edits
 4502                        .into_iter()
 4503                        .map(|(range, text)| {
 4504                            use text::ToPoint as TP;
 4505                            let end_point = TP::to_point(&range.end, &snapshot);
 4506                            let start_point = TP::to_point(&range.start, &snapshot);
 4507                            (start_point..end_point, text)
 4508                        })
 4509                        .sorted_by_key(|(range, _)| range.start);
 4510                    buffer.edit(edits, None, cx);
 4511                })
 4512            }
 4513            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4514            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4515            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4516            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4517                new_anchor_selections,
 4518                &map,
 4519            )
 4520            .zip(new_selection_deltas)
 4521            .map(|(selection, delta)| Selection {
 4522                id: selection.id,
 4523                start: selection.start + delta,
 4524                end: selection.end + delta,
 4525                reversed: selection.reversed,
 4526                goal: SelectionGoal::None,
 4527            })
 4528            .collect::<Vec<_>>();
 4529
 4530            let mut i = 0;
 4531            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4532                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4533                let start = map.buffer_snapshot().anchor_before(position);
 4534                let end = map.buffer_snapshot().anchor_after(position);
 4535                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4536                    match existing_state
 4537                        .range
 4538                        .start
 4539                        .cmp(&start, map.buffer_snapshot())
 4540                    {
 4541                        Ordering::Less => i += 1,
 4542                        Ordering::Greater => break,
 4543                        Ordering::Equal => {
 4544                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4545                                Ordering::Less => i += 1,
 4546                                Ordering::Equal => break,
 4547                                Ordering::Greater => break,
 4548                            }
 4549                        }
 4550                    }
 4551                }
 4552                this.autoclose_regions.insert(
 4553                    i,
 4554                    AutocloseRegion {
 4555                        selection_id,
 4556                        range: start..end,
 4557                        pair,
 4558                    },
 4559                );
 4560            }
 4561
 4562            let had_active_edit_prediction = this.has_active_edit_prediction();
 4563            this.change_selections(
 4564                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4565                window,
 4566                cx,
 4567                |s| s.select(new_selections),
 4568            );
 4569
 4570            if !bracket_inserted
 4571                && let Some(on_type_format_task) =
 4572                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4573            {
 4574                on_type_format_task.detach_and_log_err(cx);
 4575            }
 4576
 4577            let editor_settings = EditorSettings::get_global(cx);
 4578            if bracket_inserted
 4579                && (editor_settings.auto_signature_help
 4580                    || editor_settings.show_signature_help_after_edits)
 4581            {
 4582                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4583            }
 4584
 4585            let trigger_in_words =
 4586                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4587            if this.hard_wrap.is_some() {
 4588                let latest: Range<Point> = this.selections.newest(&map).range();
 4589                if latest.is_empty()
 4590                    && this
 4591                        .buffer()
 4592                        .read(cx)
 4593                        .snapshot(cx)
 4594                        .line_len(MultiBufferRow(latest.start.row))
 4595                        == latest.start.column
 4596                {
 4597                    this.rewrap_impl(
 4598                        RewrapOptions {
 4599                            override_language_settings: true,
 4600                            preserve_existing_whitespace: true,
 4601                        },
 4602                        cx,
 4603                    )
 4604                }
 4605            }
 4606            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4607            refresh_linked_ranges(this, window, cx);
 4608            this.refresh_edit_prediction(true, false, window, cx);
 4609            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4610        });
 4611    }
 4612
 4613    fn find_possible_emoji_shortcode_at_position(
 4614        snapshot: &MultiBufferSnapshot,
 4615        position: Point,
 4616    ) -> Option<String> {
 4617        let mut chars = Vec::new();
 4618        let mut found_colon = false;
 4619        for char in snapshot.reversed_chars_at(position).take(100) {
 4620            // Found a possible emoji shortcode in the middle of the buffer
 4621            if found_colon {
 4622                if char.is_whitespace() {
 4623                    chars.reverse();
 4624                    return Some(chars.iter().collect());
 4625                }
 4626                // If the previous character is not a whitespace, we are in the middle of a word
 4627                // and we only want to complete the shortcode if the word is made up of other emojis
 4628                let mut containing_word = String::new();
 4629                for ch in snapshot
 4630                    .reversed_chars_at(position)
 4631                    .skip(chars.len() + 1)
 4632                    .take(100)
 4633                {
 4634                    if ch.is_whitespace() {
 4635                        break;
 4636                    }
 4637                    containing_word.push(ch);
 4638                }
 4639                let containing_word = containing_word.chars().rev().collect::<String>();
 4640                if util::word_consists_of_emojis(containing_word.as_str()) {
 4641                    chars.reverse();
 4642                    return Some(chars.iter().collect());
 4643                }
 4644            }
 4645
 4646            if char.is_whitespace() || !char.is_ascii() {
 4647                return None;
 4648            }
 4649            if char == ':' {
 4650                found_colon = true;
 4651            } else {
 4652                chars.push(char);
 4653            }
 4654        }
 4655        // Found a possible emoji shortcode at the beginning of the buffer
 4656        chars.reverse();
 4657        Some(chars.iter().collect())
 4658    }
 4659
 4660    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4662        self.transact(window, cx, |this, window, cx| {
 4663            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4664                let selections = this
 4665                    .selections
 4666                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4667                let multi_buffer = this.buffer.read(cx);
 4668                let buffer = multi_buffer.snapshot(cx);
 4669                selections
 4670                    .iter()
 4671                    .map(|selection| {
 4672                        let start_point = selection.start.to_point(&buffer);
 4673                        let mut existing_indent =
 4674                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4675                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4676                        let start = selection.start;
 4677                        let end = selection.end;
 4678                        let selection_is_empty = start == end;
 4679                        let language_scope = buffer.language_scope_at(start);
 4680                        let (
 4681                            comment_delimiter,
 4682                            doc_delimiter,
 4683                            insert_extra_newline,
 4684                            indent_on_newline,
 4685                            indent_on_extra_newline,
 4686                        ) = if let Some(language) = &language_scope {
 4687                            let mut insert_extra_newline =
 4688                                insert_extra_newline_brackets(&buffer, start..end, language)
 4689                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4690
 4691                            // Comment extension on newline is allowed only for cursor selections
 4692                            let comment_delimiter = maybe!({
 4693                                if !selection_is_empty {
 4694                                    return None;
 4695                                }
 4696
 4697                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4698                                    return None;
 4699                                }
 4700
 4701                                let delimiters = language.line_comment_prefixes();
 4702                                let max_len_of_delimiter =
 4703                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4704                                let (snapshot, range) =
 4705                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4706
 4707                                let num_of_whitespaces = snapshot
 4708                                    .chars_for_range(range.clone())
 4709                                    .take_while(|c| c.is_whitespace())
 4710                                    .count();
 4711                                let comment_candidate = snapshot
 4712                                    .chars_for_range(range.clone())
 4713                                    .skip(num_of_whitespaces)
 4714                                    .take(max_len_of_delimiter)
 4715                                    .collect::<String>();
 4716                                let (delimiter, trimmed_len) = delimiters
 4717                                    .iter()
 4718                                    .filter_map(|delimiter| {
 4719                                        let prefix = delimiter.trim_end();
 4720                                        if comment_candidate.starts_with(prefix) {
 4721                                            Some((delimiter, prefix.len()))
 4722                                        } else {
 4723                                            None
 4724                                        }
 4725                                    })
 4726                                    .max_by_key(|(_, len)| *len)?;
 4727
 4728                                if let Some(BlockCommentConfig {
 4729                                    start: block_start, ..
 4730                                }) = language.block_comment()
 4731                                {
 4732                                    let block_start_trimmed = block_start.trim_end();
 4733                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4734                                        let line_content = snapshot
 4735                                            .chars_for_range(range)
 4736                                            .skip(num_of_whitespaces)
 4737                                            .take(block_start_trimmed.len())
 4738                                            .collect::<String>();
 4739
 4740                                        if line_content.starts_with(block_start_trimmed) {
 4741                                            return None;
 4742                                        }
 4743                                    }
 4744                                }
 4745
 4746                                let cursor_is_placed_after_comment_marker =
 4747                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4748                                if cursor_is_placed_after_comment_marker {
 4749                                    Some(delimiter.clone())
 4750                                } else {
 4751                                    None
 4752                                }
 4753                            });
 4754
 4755                            let mut indent_on_newline = IndentSize::spaces(0);
 4756                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4757
 4758                            let doc_delimiter = maybe!({
 4759                                if !selection_is_empty {
 4760                                    return None;
 4761                                }
 4762
 4763                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4764                                    return None;
 4765                                }
 4766
 4767                                let BlockCommentConfig {
 4768                                    start: start_tag,
 4769                                    end: end_tag,
 4770                                    prefix: delimiter,
 4771                                    tab_size: len,
 4772                                } = language.documentation_comment()?;
 4773                                let is_within_block_comment = buffer
 4774                                    .language_scope_at(start_point)
 4775                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4776                                if !is_within_block_comment {
 4777                                    return None;
 4778                                }
 4779
 4780                                let (snapshot, range) =
 4781                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4782
 4783                                let num_of_whitespaces = snapshot
 4784                                    .chars_for_range(range.clone())
 4785                                    .take_while(|c| c.is_whitespace())
 4786                                    .count();
 4787
 4788                                // 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.
 4789                                let column = start_point.column;
 4790                                let cursor_is_after_start_tag = {
 4791                                    let start_tag_len = start_tag.len();
 4792                                    let start_tag_line = snapshot
 4793                                        .chars_for_range(range.clone())
 4794                                        .skip(num_of_whitespaces)
 4795                                        .take(start_tag_len)
 4796                                        .collect::<String>();
 4797                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4798                                        num_of_whitespaces + start_tag_len <= column as usize
 4799                                    } else {
 4800                                        false
 4801                                    }
 4802                                };
 4803
 4804                                let cursor_is_after_delimiter = {
 4805                                    let delimiter_trim = delimiter.trim_end();
 4806                                    let delimiter_line = snapshot
 4807                                        .chars_for_range(range.clone())
 4808                                        .skip(num_of_whitespaces)
 4809                                        .take(delimiter_trim.len())
 4810                                        .collect::<String>();
 4811                                    if delimiter_line.starts_with(delimiter_trim) {
 4812                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4813                                    } else {
 4814                                        false
 4815                                    }
 4816                                };
 4817
 4818                                let cursor_is_before_end_tag_if_exists = {
 4819                                    let mut char_position = 0u32;
 4820                                    let mut end_tag_offset = None;
 4821
 4822                                    'outer: for chunk in snapshot.text_for_range(range) {
 4823                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4824                                            let chars_before_match =
 4825                                                chunk[..byte_pos].chars().count() as u32;
 4826                                            end_tag_offset =
 4827                                                Some(char_position + chars_before_match);
 4828                                            break 'outer;
 4829                                        }
 4830                                        char_position += chunk.chars().count() as u32;
 4831                                    }
 4832
 4833                                    if let Some(end_tag_offset) = end_tag_offset {
 4834                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4835                                        if cursor_is_after_start_tag {
 4836                                            if cursor_is_before_end_tag {
 4837                                                insert_extra_newline = true;
 4838                                            }
 4839                                            let cursor_is_at_start_of_end_tag =
 4840                                                column == end_tag_offset;
 4841                                            if cursor_is_at_start_of_end_tag {
 4842                                                indent_on_extra_newline.len = *len;
 4843                                            }
 4844                                        }
 4845                                        cursor_is_before_end_tag
 4846                                    } else {
 4847                                        true
 4848                                    }
 4849                                };
 4850
 4851                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4852                                    && cursor_is_before_end_tag_if_exists
 4853                                {
 4854                                    if cursor_is_after_start_tag {
 4855                                        indent_on_newline.len = *len;
 4856                                    }
 4857                                    Some(delimiter.clone())
 4858                                } else {
 4859                                    None
 4860                                }
 4861                            });
 4862
 4863                            (
 4864                                comment_delimiter,
 4865                                doc_delimiter,
 4866                                insert_extra_newline,
 4867                                indent_on_newline,
 4868                                indent_on_extra_newline,
 4869                            )
 4870                        } else {
 4871                            (
 4872                                None,
 4873                                None,
 4874                                false,
 4875                                IndentSize::default(),
 4876                                IndentSize::default(),
 4877                            )
 4878                        };
 4879
 4880                        let prevent_auto_indent = doc_delimiter.is_some();
 4881                        let delimiter = comment_delimiter.or(doc_delimiter);
 4882
 4883                        let capacity_for_delimiter =
 4884                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4885                        let mut new_text = String::with_capacity(
 4886                            1 + capacity_for_delimiter
 4887                                + existing_indent.len as usize
 4888                                + indent_on_newline.len as usize
 4889                                + indent_on_extra_newline.len as usize,
 4890                        );
 4891                        new_text.push('\n');
 4892                        new_text.extend(existing_indent.chars());
 4893                        new_text.extend(indent_on_newline.chars());
 4894
 4895                        if let Some(delimiter) = &delimiter {
 4896                            new_text.push_str(delimiter);
 4897                        }
 4898
 4899                        if insert_extra_newline {
 4900                            new_text.push('\n');
 4901                            new_text.extend(existing_indent.chars());
 4902                            new_text.extend(indent_on_extra_newline.chars());
 4903                        }
 4904
 4905                        let anchor = buffer.anchor_after(end);
 4906                        let new_selection = selection.map(|_| anchor);
 4907                        (
 4908                            ((start..end, new_text), prevent_auto_indent),
 4909                            (insert_extra_newline, new_selection),
 4910                        )
 4911                    })
 4912                    .unzip()
 4913            };
 4914
 4915            let mut auto_indent_edits = Vec::new();
 4916            let mut edits = Vec::new();
 4917            for (edit, prevent_auto_indent) in edits_with_flags {
 4918                if prevent_auto_indent {
 4919                    edits.push(edit);
 4920                } else {
 4921                    auto_indent_edits.push(edit);
 4922                }
 4923            }
 4924            if !edits.is_empty() {
 4925                this.edit(edits, cx);
 4926            }
 4927            if !auto_indent_edits.is_empty() {
 4928                this.edit_with_autoindent(auto_indent_edits, cx);
 4929            }
 4930
 4931            let buffer = this.buffer.read(cx).snapshot(cx);
 4932            let new_selections = selection_info
 4933                .into_iter()
 4934                .map(|(extra_newline_inserted, new_selection)| {
 4935                    let mut cursor = new_selection.end.to_point(&buffer);
 4936                    if extra_newline_inserted {
 4937                        cursor.row -= 1;
 4938                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4939                    }
 4940                    new_selection.map(|_| cursor)
 4941                })
 4942                .collect();
 4943
 4944            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4945            this.refresh_edit_prediction(true, false, window, cx);
 4946        });
 4947    }
 4948
 4949    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4951
 4952        let buffer = self.buffer.read(cx);
 4953        let snapshot = buffer.snapshot(cx);
 4954
 4955        let mut edits = Vec::new();
 4956        let mut rows = Vec::new();
 4957
 4958        for (rows_inserted, selection) in self
 4959            .selections
 4960            .all_adjusted(&self.display_snapshot(cx))
 4961            .into_iter()
 4962            .enumerate()
 4963        {
 4964            let cursor = selection.head();
 4965            let row = cursor.row;
 4966
 4967            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4968
 4969            let newline = "\n".to_string();
 4970            edits.push((start_of_line..start_of_line, newline));
 4971
 4972            rows.push(row + rows_inserted as u32);
 4973        }
 4974
 4975        self.transact(window, cx, |editor, window, cx| {
 4976            editor.edit(edits, cx);
 4977
 4978            editor.change_selections(Default::default(), window, cx, |s| {
 4979                let mut index = 0;
 4980                s.move_cursors_with(|map, _, _| {
 4981                    let row = rows[index];
 4982                    index += 1;
 4983
 4984                    let point = Point::new(row, 0);
 4985                    let boundary = map.next_line_boundary(point).1;
 4986                    let clipped = map.clip_point(boundary, Bias::Left);
 4987
 4988                    (clipped, SelectionGoal::None)
 4989                });
 4990            });
 4991
 4992            let mut indent_edits = Vec::new();
 4993            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4994            for row in rows {
 4995                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4996                for (row, indent) in indents {
 4997                    if indent.len == 0 {
 4998                        continue;
 4999                    }
 5000
 5001                    let text = match indent.kind {
 5002                        IndentKind::Space => " ".repeat(indent.len as usize),
 5003                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5004                    };
 5005                    let point = Point::new(row.0, 0);
 5006                    indent_edits.push((point..point, text));
 5007                }
 5008            }
 5009            editor.edit(indent_edits, cx);
 5010        });
 5011    }
 5012
 5013    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5015
 5016        let buffer = self.buffer.read(cx);
 5017        let snapshot = buffer.snapshot(cx);
 5018
 5019        let mut edits = Vec::new();
 5020        let mut rows = Vec::new();
 5021        let mut rows_inserted = 0;
 5022
 5023        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5024            let cursor = selection.head();
 5025            let row = cursor.row;
 5026
 5027            let point = Point::new(row + 1, 0);
 5028            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5029
 5030            let newline = "\n".to_string();
 5031            edits.push((start_of_line..start_of_line, newline));
 5032
 5033            rows_inserted += 1;
 5034            rows.push(row + rows_inserted);
 5035        }
 5036
 5037        self.transact(window, cx, |editor, window, cx| {
 5038            editor.edit(edits, cx);
 5039
 5040            editor.change_selections(Default::default(), window, cx, |s| {
 5041                let mut index = 0;
 5042                s.move_cursors_with(|map, _, _| {
 5043                    let row = rows[index];
 5044                    index += 1;
 5045
 5046                    let point = Point::new(row, 0);
 5047                    let boundary = map.next_line_boundary(point).1;
 5048                    let clipped = map.clip_point(boundary, Bias::Left);
 5049
 5050                    (clipped, SelectionGoal::None)
 5051                });
 5052            });
 5053
 5054            let mut indent_edits = Vec::new();
 5055            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5056            for row in rows {
 5057                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5058                for (row, indent) in indents {
 5059                    if indent.len == 0 {
 5060                        continue;
 5061                    }
 5062
 5063                    let text = match indent.kind {
 5064                        IndentKind::Space => " ".repeat(indent.len as usize),
 5065                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5066                    };
 5067                    let point = Point::new(row.0, 0);
 5068                    indent_edits.push((point..point, text));
 5069                }
 5070            }
 5071            editor.edit(indent_edits, cx);
 5072        });
 5073    }
 5074
 5075    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5076        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5077            original_indent_columns: Vec::new(),
 5078        });
 5079        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5080    }
 5081
 5082    fn insert_with_autoindent_mode(
 5083        &mut self,
 5084        text: &str,
 5085        autoindent_mode: Option<AutoindentMode>,
 5086        window: &mut Window,
 5087        cx: &mut Context<Self>,
 5088    ) {
 5089        if self.read_only(cx) {
 5090            return;
 5091        }
 5092
 5093        let text: Arc<str> = text.into();
 5094        self.transact(window, cx, |this, window, cx| {
 5095            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5096            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5097                let anchors = {
 5098                    let snapshot = buffer.read(cx);
 5099                    old_selections
 5100                        .iter()
 5101                        .map(|s| {
 5102                            let anchor = snapshot.anchor_after(s.head());
 5103                            s.map(|_| anchor)
 5104                        })
 5105                        .collect::<Vec<_>>()
 5106                };
 5107                buffer.edit(
 5108                    old_selections
 5109                        .iter()
 5110                        .map(|s| (s.start..s.end, text.clone())),
 5111                    autoindent_mode,
 5112                    cx,
 5113                );
 5114                anchors
 5115            });
 5116
 5117            this.change_selections(Default::default(), window, cx, |s| {
 5118                s.select_anchors(selection_anchors);
 5119            });
 5120
 5121            cx.notify();
 5122        });
 5123    }
 5124
 5125    fn trigger_completion_on_input(
 5126        &mut self,
 5127        text: &str,
 5128        trigger_in_words: bool,
 5129        window: &mut Window,
 5130        cx: &mut Context<Self>,
 5131    ) {
 5132        let completions_source = self
 5133            .context_menu
 5134            .borrow()
 5135            .as_ref()
 5136            .and_then(|menu| match menu {
 5137                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5138                CodeContextMenu::CodeActions(_) => None,
 5139            });
 5140
 5141        match completions_source {
 5142            Some(CompletionsMenuSource::Words { .. }) => {
 5143                self.open_or_update_completions_menu(
 5144                    Some(CompletionsMenuSource::Words {
 5145                        ignore_threshold: false,
 5146                    }),
 5147                    None,
 5148                    trigger_in_words,
 5149                    window,
 5150                    cx,
 5151                );
 5152            }
 5153            _ => self.open_or_update_completions_menu(
 5154                None,
 5155                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5156                true,
 5157                window,
 5158                cx,
 5159            ),
 5160        }
 5161    }
 5162
 5163    /// If any empty selections is touching the start of its innermost containing autoclose
 5164    /// region, expand it to select the brackets.
 5165    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5166        let selections = self
 5167            .selections
 5168            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5169        let buffer = self.buffer.read(cx).read(cx);
 5170        let new_selections = self
 5171            .selections_with_autoclose_regions(selections, &buffer)
 5172            .map(|(mut selection, region)| {
 5173                if !selection.is_empty() {
 5174                    return selection;
 5175                }
 5176
 5177                if let Some(region) = region {
 5178                    let mut range = region.range.to_offset(&buffer);
 5179                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5180                        range.start -= region.pair.start.len();
 5181                        if buffer.contains_str_at(range.start, &region.pair.start)
 5182                            && buffer.contains_str_at(range.end, &region.pair.end)
 5183                        {
 5184                            range.end += region.pair.end.len();
 5185                            selection.start = range.start;
 5186                            selection.end = range.end;
 5187
 5188                            return selection;
 5189                        }
 5190                    }
 5191                }
 5192
 5193                let always_treat_brackets_as_autoclosed = buffer
 5194                    .language_settings_at(selection.start, cx)
 5195                    .always_treat_brackets_as_autoclosed;
 5196
 5197                if !always_treat_brackets_as_autoclosed {
 5198                    return selection;
 5199                }
 5200
 5201                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5202                    for (pair, enabled) in scope.brackets() {
 5203                        if !enabled || !pair.close {
 5204                            continue;
 5205                        }
 5206
 5207                        if buffer.contains_str_at(selection.start, &pair.end) {
 5208                            let pair_start_len = pair.start.len();
 5209                            if buffer.contains_str_at(
 5210                                selection.start.saturating_sub_usize(pair_start_len),
 5211                                &pair.start,
 5212                            ) {
 5213                                selection.start -= pair_start_len;
 5214                                selection.end += pair.end.len();
 5215
 5216                                return selection;
 5217                            }
 5218                        }
 5219                    }
 5220                }
 5221
 5222                selection
 5223            })
 5224            .collect();
 5225
 5226        drop(buffer);
 5227        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5228            selections.select(new_selections)
 5229        });
 5230    }
 5231
 5232    /// Iterate the given selections, and for each one, find the smallest surrounding
 5233    /// autoclose region. This uses the ordering of the selections and the autoclose
 5234    /// regions to avoid repeated comparisons.
 5235    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5236        &'a self,
 5237        selections: impl IntoIterator<Item = Selection<D>>,
 5238        buffer: &'a MultiBufferSnapshot,
 5239    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5240        let mut i = 0;
 5241        let mut regions = self.autoclose_regions.as_slice();
 5242        selections.into_iter().map(move |selection| {
 5243            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5244
 5245            let mut enclosing = None;
 5246            while let Some(pair_state) = regions.get(i) {
 5247                if pair_state.range.end.to_offset(buffer) < range.start {
 5248                    regions = &regions[i + 1..];
 5249                    i = 0;
 5250                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5251                    break;
 5252                } else {
 5253                    if pair_state.selection_id == selection.id {
 5254                        enclosing = Some(pair_state);
 5255                    }
 5256                    i += 1;
 5257                }
 5258            }
 5259
 5260            (selection, enclosing)
 5261        })
 5262    }
 5263
 5264    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5265    fn invalidate_autoclose_regions(
 5266        &mut self,
 5267        mut selections: &[Selection<Anchor>],
 5268        buffer: &MultiBufferSnapshot,
 5269    ) {
 5270        self.autoclose_regions.retain(|state| {
 5271            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5272                return false;
 5273            }
 5274
 5275            let mut i = 0;
 5276            while let Some(selection) = selections.get(i) {
 5277                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5278                    selections = &selections[1..];
 5279                    continue;
 5280                }
 5281                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5282                    break;
 5283                }
 5284                if selection.id == state.selection_id {
 5285                    return true;
 5286                } else {
 5287                    i += 1;
 5288                }
 5289            }
 5290            false
 5291        });
 5292    }
 5293
 5294    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5295        let offset = position.to_offset(buffer);
 5296        let (word_range, kind) =
 5297            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5298        if offset > word_range.start && kind == Some(CharKind::Word) {
 5299            Some(
 5300                buffer
 5301                    .text_for_range(word_range.start..offset)
 5302                    .collect::<String>(),
 5303            )
 5304        } else {
 5305            None
 5306        }
 5307    }
 5308
 5309    pub fn visible_excerpts(
 5310        &self,
 5311        cx: &mut Context<Editor>,
 5312    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5313        let Some(project) = self.project() else {
 5314            return HashMap::default();
 5315        };
 5316        let project = project.read(cx);
 5317        let multi_buffer = self.buffer().read(cx);
 5318        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5319        let multi_buffer_visible_start = self
 5320            .scroll_manager
 5321            .anchor()
 5322            .anchor
 5323            .to_point(&multi_buffer_snapshot);
 5324        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5325            multi_buffer_visible_start
 5326                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5327            Bias::Left,
 5328        );
 5329        multi_buffer_snapshot
 5330            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5331            .into_iter()
 5332            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5333            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5334                let buffer_file = project::File::from_dyn(buffer.file())?;
 5335                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5336                let worktree_entry = buffer_worktree
 5337                    .read(cx)
 5338                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5339                if worktree_entry.is_ignored {
 5340                    None
 5341                } else {
 5342                    Some((
 5343                        excerpt_id,
 5344                        (
 5345                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5346                            buffer.version().clone(),
 5347                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5348                        ),
 5349                    ))
 5350                }
 5351            })
 5352            .collect()
 5353    }
 5354
 5355    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5356        TextLayoutDetails {
 5357            text_system: window.text_system().clone(),
 5358            editor_style: self.style.clone().unwrap(),
 5359            rem_size: window.rem_size(),
 5360            scroll_anchor: self.scroll_manager.anchor(),
 5361            visible_rows: self.visible_line_count(),
 5362            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5363        }
 5364    }
 5365
 5366    fn trigger_on_type_formatting(
 5367        &self,
 5368        input: String,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) -> Option<Task<Result<()>>> {
 5372        if input.len() != 1 {
 5373            return None;
 5374        }
 5375
 5376        let project = self.project()?;
 5377        let position = self.selections.newest_anchor().head();
 5378        let (buffer, buffer_position) = self
 5379            .buffer
 5380            .read(cx)
 5381            .text_anchor_for_position(position, cx)?;
 5382
 5383        let settings = language_settings::language_settings(
 5384            buffer
 5385                .read(cx)
 5386                .language_at(buffer_position)
 5387                .map(|l| l.name()),
 5388            buffer.read(cx).file(),
 5389            cx,
 5390        );
 5391        if !settings.use_on_type_format {
 5392            return None;
 5393        }
 5394
 5395        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5396        // hence we do LSP request & edit on host side only — add formats to host's history.
 5397        let push_to_lsp_host_history = true;
 5398        // If this is not the host, append its history with new edits.
 5399        let push_to_client_history = project.read(cx).is_via_collab();
 5400
 5401        let on_type_formatting = project.update(cx, |project, cx| {
 5402            project.on_type_format(
 5403                buffer.clone(),
 5404                buffer_position,
 5405                input,
 5406                push_to_lsp_host_history,
 5407                cx,
 5408            )
 5409        });
 5410        Some(cx.spawn_in(window, async move |editor, cx| {
 5411            if let Some(transaction) = on_type_formatting.await? {
 5412                if push_to_client_history {
 5413                    buffer
 5414                        .update(cx, |buffer, _| {
 5415                            buffer.push_transaction(transaction, Instant::now());
 5416                            buffer.finalize_last_transaction();
 5417                        })
 5418                        .ok();
 5419                }
 5420                editor.update(cx, |editor, cx| {
 5421                    editor.refresh_document_highlights(cx);
 5422                })?;
 5423            }
 5424            Ok(())
 5425        }))
 5426    }
 5427
 5428    pub fn show_word_completions(
 5429        &mut self,
 5430        _: &ShowWordCompletions,
 5431        window: &mut Window,
 5432        cx: &mut Context<Self>,
 5433    ) {
 5434        self.open_or_update_completions_menu(
 5435            Some(CompletionsMenuSource::Words {
 5436                ignore_threshold: true,
 5437            }),
 5438            None,
 5439            false,
 5440            window,
 5441            cx,
 5442        );
 5443    }
 5444
 5445    pub fn show_completions(
 5446        &mut self,
 5447        _: &ShowCompletions,
 5448        window: &mut Window,
 5449        cx: &mut Context<Self>,
 5450    ) {
 5451        self.open_or_update_completions_menu(None, None, false, window, cx);
 5452    }
 5453
 5454    fn open_or_update_completions_menu(
 5455        &mut self,
 5456        requested_source: Option<CompletionsMenuSource>,
 5457        trigger: Option<String>,
 5458        trigger_in_words: bool,
 5459        window: &mut Window,
 5460        cx: &mut Context<Self>,
 5461    ) {
 5462        if self.pending_rename.is_some() {
 5463            return;
 5464        }
 5465
 5466        let completions_source = self
 5467            .context_menu
 5468            .borrow()
 5469            .as_ref()
 5470            .and_then(|menu| match menu {
 5471                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5472                CodeContextMenu::CodeActions(_) => None,
 5473            });
 5474
 5475        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5476
 5477        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5478        // inserted and selected. To handle that case, the start of the selection is used so that
 5479        // the menu starts with all choices.
 5480        let position = self
 5481            .selections
 5482            .newest_anchor()
 5483            .start
 5484            .bias_right(&multibuffer_snapshot);
 5485        if position.diff_base_anchor.is_some() {
 5486            return;
 5487        }
 5488        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5489        let Some(buffer) = buffer_position
 5490            .text_anchor
 5491            .buffer_id
 5492            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5493        else {
 5494            return;
 5495        };
 5496        let buffer_snapshot = buffer.read(cx).snapshot();
 5497
 5498        let query: Option<Arc<String>> =
 5499            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5500                .map(|query| query.into());
 5501
 5502        drop(multibuffer_snapshot);
 5503
 5504        // Hide the current completions menu when query is empty. Without this, cached
 5505        // completions from before the trigger char may be reused (#32774).
 5506        if query.is_none() {
 5507            let menu_is_open = matches!(
 5508                self.context_menu.borrow().as_ref(),
 5509                Some(CodeContextMenu::Completions(_))
 5510            );
 5511            if menu_is_open {
 5512                self.hide_context_menu(window, cx);
 5513            }
 5514        }
 5515
 5516        let mut ignore_word_threshold = false;
 5517        let provider = match requested_source {
 5518            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5519            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5520                ignore_word_threshold = ignore_threshold;
 5521                None
 5522            }
 5523            Some(CompletionsMenuSource::SnippetChoices)
 5524            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5525                log::error!("bug: SnippetChoices requested_source is not handled");
 5526                None
 5527            }
 5528        };
 5529
 5530        let sort_completions = provider
 5531            .as_ref()
 5532            .is_some_and(|provider| provider.sort_completions());
 5533
 5534        let filter_completions = provider
 5535            .as_ref()
 5536            .is_none_or(|provider| provider.filter_completions());
 5537
 5538        let was_snippets_only = matches!(
 5539            completions_source,
 5540            Some(CompletionsMenuSource::SnippetsOnly)
 5541        );
 5542
 5543        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5544            if filter_completions {
 5545                menu.filter(
 5546                    query.clone().unwrap_or_default(),
 5547                    buffer_position.text_anchor,
 5548                    &buffer,
 5549                    provider.clone(),
 5550                    window,
 5551                    cx,
 5552                );
 5553            }
 5554            // When `is_incomplete` is false, no need to re-query completions when the current query
 5555            // is a suffix of the initial query.
 5556            let was_complete = !menu.is_incomplete;
 5557            if was_complete && !was_snippets_only {
 5558                // If the new query is a suffix of the old query (typing more characters) and
 5559                // the previous result was complete, the existing completions can be filtered.
 5560                //
 5561                // Note that snippet completions are always complete.
 5562                let query_matches = match (&menu.initial_query, &query) {
 5563                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5564                    (None, _) => true,
 5565                    _ => false,
 5566                };
 5567                if query_matches {
 5568                    let position_matches = if menu.initial_position == position {
 5569                        true
 5570                    } else {
 5571                        let snapshot = self.buffer.read(cx).read(cx);
 5572                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5573                    };
 5574                    if position_matches {
 5575                        return;
 5576                    }
 5577                }
 5578            }
 5579        };
 5580
 5581        let Anchor {
 5582            excerpt_id: buffer_excerpt_id,
 5583            text_anchor: buffer_position,
 5584            ..
 5585        } = buffer_position;
 5586
 5587        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5588            buffer_snapshot.surrounding_word(buffer_position, None)
 5589        {
 5590            let word_to_exclude = buffer_snapshot
 5591                .text_for_range(word_range.clone())
 5592                .collect::<String>();
 5593            (
 5594                buffer_snapshot.anchor_before(word_range.start)
 5595                    ..buffer_snapshot.anchor_after(buffer_position),
 5596                Some(word_to_exclude),
 5597            )
 5598        } else {
 5599            (buffer_position..buffer_position, None)
 5600        };
 5601
 5602        let language = buffer_snapshot
 5603            .language_at(buffer_position)
 5604            .map(|language| language.name());
 5605
 5606        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5607            .completions
 5608            .clone();
 5609
 5610        let show_completion_documentation = buffer_snapshot
 5611            .settings_at(buffer_position, cx)
 5612            .show_completion_documentation;
 5613
 5614        // The document can be large, so stay in reasonable bounds when searching for words,
 5615        // otherwise completion pop-up might be slow to appear.
 5616        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5617        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5618        let min_word_search = buffer_snapshot.clip_point(
 5619            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5620            Bias::Left,
 5621        );
 5622        let max_word_search = buffer_snapshot.clip_point(
 5623            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5624            Bias::Right,
 5625        );
 5626        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5627            ..buffer_snapshot.point_to_offset(max_word_search);
 5628
 5629        let skip_digits = query
 5630            .as_ref()
 5631            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5632
 5633        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5634            trigger.as_ref().is_none_or(|trigger| {
 5635                provider.is_completion_trigger(
 5636                    &buffer,
 5637                    position.text_anchor,
 5638                    trigger,
 5639                    trigger_in_words,
 5640                    completions_source.is_some(),
 5641                    cx,
 5642                )
 5643            })
 5644        });
 5645
 5646        let provider_responses = if let Some(provider) = &provider
 5647            && load_provider_completions
 5648        {
 5649            let trigger_character =
 5650                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5651            let completion_context = CompletionContext {
 5652                trigger_kind: match &trigger_character {
 5653                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5654                    None => CompletionTriggerKind::INVOKED,
 5655                },
 5656                trigger_character,
 5657            };
 5658
 5659            provider.completions(
 5660                buffer_excerpt_id,
 5661                &buffer,
 5662                buffer_position,
 5663                completion_context,
 5664                window,
 5665                cx,
 5666            )
 5667        } else {
 5668            Task::ready(Ok(Vec::new()))
 5669        };
 5670
 5671        let load_word_completions = if !self.word_completions_enabled {
 5672            false
 5673        } else if requested_source
 5674            == Some(CompletionsMenuSource::Words {
 5675                ignore_threshold: true,
 5676            })
 5677        {
 5678            true
 5679        } else {
 5680            load_provider_completions
 5681                && completion_settings.words != WordsCompletionMode::Disabled
 5682                && (ignore_word_threshold || {
 5683                    let words_min_length = completion_settings.words_min_length;
 5684                    // check whether word has at least `words_min_length` characters
 5685                    let query_chars = query.iter().flat_map(|q| q.chars());
 5686                    query_chars.take(words_min_length).count() == words_min_length
 5687                })
 5688        };
 5689
 5690        let mut words = if load_word_completions {
 5691            cx.background_spawn({
 5692                let buffer_snapshot = buffer_snapshot.clone();
 5693                async move {
 5694                    buffer_snapshot.words_in_range(WordsQuery {
 5695                        fuzzy_contents: None,
 5696                        range: word_search_range,
 5697                        skip_digits,
 5698                    })
 5699                }
 5700            })
 5701        } else {
 5702            Task::ready(BTreeMap::default())
 5703        };
 5704
 5705        let snippets = if let Some(provider) = &provider
 5706            && provider.show_snippets()
 5707            && let Some(project) = self.project()
 5708        {
 5709            let char_classifier = buffer_snapshot
 5710                .char_classifier_at(buffer_position)
 5711                .scope_context(Some(CharScopeContext::Completion));
 5712            project.update(cx, |project, cx| {
 5713                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5714            })
 5715        } else {
 5716            Task::ready(Ok(CompletionResponse {
 5717                completions: Vec::new(),
 5718                display_options: Default::default(),
 5719                is_incomplete: false,
 5720            }))
 5721        };
 5722
 5723        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5724
 5725        let id = post_inc(&mut self.next_completion_id);
 5726        let task = cx.spawn_in(window, async move |editor, cx| {
 5727            let Ok(()) = editor.update(cx, |this, _| {
 5728                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5729            }) else {
 5730                return;
 5731            };
 5732
 5733            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5734            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5735            let mut completions = Vec::new();
 5736            let mut is_incomplete = false;
 5737            let mut display_options: Option<CompletionDisplayOptions> = None;
 5738            if let Some(provider_responses) = provider_responses.await.log_err()
 5739                && !provider_responses.is_empty()
 5740            {
 5741                for response in provider_responses {
 5742                    completions.extend(response.completions);
 5743                    is_incomplete = is_incomplete || response.is_incomplete;
 5744                    match display_options.as_mut() {
 5745                        None => {
 5746                            display_options = Some(response.display_options);
 5747                        }
 5748                        Some(options) => options.merge(&response.display_options),
 5749                    }
 5750                }
 5751                if completion_settings.words == WordsCompletionMode::Fallback {
 5752                    words = Task::ready(BTreeMap::default());
 5753                }
 5754            }
 5755            let display_options = display_options.unwrap_or_default();
 5756
 5757            let mut words = words.await;
 5758            if let Some(word_to_exclude) = &word_to_exclude {
 5759                words.remove(word_to_exclude);
 5760            }
 5761            for lsp_completion in &completions {
 5762                words.remove(&lsp_completion.new_text);
 5763            }
 5764            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5765                replace_range: word_replace_range.clone(),
 5766                new_text: word.clone(),
 5767                label: CodeLabel::plain(word, None),
 5768                match_start: None,
 5769                snippet_deduplication_key: None,
 5770                icon_path: None,
 5771                documentation: None,
 5772                source: CompletionSource::BufferWord {
 5773                    word_range,
 5774                    resolved: false,
 5775                },
 5776                insert_text_mode: Some(InsertTextMode::AS_IS),
 5777                confirm: None,
 5778            }));
 5779
 5780            completions.extend(
 5781                snippets
 5782                    .await
 5783                    .into_iter()
 5784                    .flat_map(|response| response.completions),
 5785            );
 5786
 5787            let menu = if completions.is_empty() {
 5788                None
 5789            } else {
 5790                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5791                    let languages = editor
 5792                        .workspace
 5793                        .as_ref()
 5794                        .and_then(|(workspace, _)| workspace.upgrade())
 5795                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5796                    let menu = CompletionsMenu::new(
 5797                        id,
 5798                        requested_source.unwrap_or(if load_provider_completions {
 5799                            CompletionsMenuSource::Normal
 5800                        } else {
 5801                            CompletionsMenuSource::SnippetsOnly
 5802                        }),
 5803                        sort_completions,
 5804                        show_completion_documentation,
 5805                        position,
 5806                        query.clone(),
 5807                        is_incomplete,
 5808                        buffer.clone(),
 5809                        completions.into(),
 5810                        display_options,
 5811                        snippet_sort_order,
 5812                        languages,
 5813                        language,
 5814                        cx,
 5815                    );
 5816
 5817                    let query = if filter_completions { query } else { None };
 5818                    let matches_task = menu.do_async_filtering(
 5819                        query.unwrap_or_default(),
 5820                        buffer_position,
 5821                        &buffer,
 5822                        cx,
 5823                    );
 5824                    (menu, matches_task)
 5825                }) else {
 5826                    return;
 5827                };
 5828
 5829                let matches = matches_task.await;
 5830
 5831                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5832                    // Newer menu already set, so exit.
 5833                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5834                        editor.context_menu.borrow().as_ref()
 5835                        && prev_menu.id > id
 5836                    {
 5837                        return;
 5838                    };
 5839
 5840                    // Only valid to take prev_menu because either the new menu is immediately set
 5841                    // below, or the menu is hidden.
 5842                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5843                        editor.context_menu.borrow_mut().take()
 5844                    {
 5845                        let position_matches =
 5846                            if prev_menu.initial_position == menu.initial_position {
 5847                                true
 5848                            } else {
 5849                                let snapshot = editor.buffer.read(cx).read(cx);
 5850                                prev_menu.initial_position.to_offset(&snapshot)
 5851                                    == menu.initial_position.to_offset(&snapshot)
 5852                            };
 5853                        if position_matches {
 5854                            // Preserve markdown cache before `set_filter_results` because it will
 5855                            // try to populate the documentation cache.
 5856                            menu.preserve_markdown_cache(prev_menu);
 5857                        }
 5858                    };
 5859
 5860                    menu.set_filter_results(matches, provider, window, cx);
 5861                }) else {
 5862                    return;
 5863                };
 5864
 5865                menu.visible().then_some(menu)
 5866            };
 5867
 5868            editor
 5869                .update_in(cx, |editor, window, cx| {
 5870                    if editor.focus_handle.is_focused(window)
 5871                        && let Some(menu) = menu
 5872                    {
 5873                        *editor.context_menu.borrow_mut() =
 5874                            Some(CodeContextMenu::Completions(menu));
 5875
 5876                        crate::hover_popover::hide_hover(editor, cx);
 5877                        if editor.show_edit_predictions_in_menu() {
 5878                            editor.update_visible_edit_prediction(window, cx);
 5879                        } else {
 5880                            editor.discard_edit_prediction(false, cx);
 5881                        }
 5882
 5883                        cx.notify();
 5884                        return;
 5885                    }
 5886
 5887                    if editor.completion_tasks.len() <= 1 {
 5888                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5889                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5890                        // If it was already hidden and we don't show edit predictions in the menu,
 5891                        // we should also show the edit prediction when available.
 5892                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5893                            editor.update_visible_edit_prediction(window, cx);
 5894                        }
 5895                    }
 5896                })
 5897                .ok();
 5898        });
 5899
 5900        self.completion_tasks.push((id, task));
 5901    }
 5902
 5903    #[cfg(feature = "test-support")]
 5904    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5905        let menu = self.context_menu.borrow();
 5906        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5907            let completions = menu.completions.borrow();
 5908            Some(completions.to_vec())
 5909        } else {
 5910            None
 5911        }
 5912    }
 5913
 5914    pub fn with_completions_menu_matching_id<R>(
 5915        &self,
 5916        id: CompletionId,
 5917        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5918    ) -> R {
 5919        let mut context_menu = self.context_menu.borrow_mut();
 5920        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5921            return f(None);
 5922        };
 5923        if completions_menu.id != id {
 5924            return f(None);
 5925        }
 5926        f(Some(completions_menu))
 5927    }
 5928
 5929    pub fn confirm_completion(
 5930        &mut self,
 5931        action: &ConfirmCompletion,
 5932        window: &mut Window,
 5933        cx: &mut Context<Self>,
 5934    ) -> Option<Task<Result<()>>> {
 5935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5936        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5937    }
 5938
 5939    pub fn confirm_completion_insert(
 5940        &mut self,
 5941        _: &ConfirmCompletionInsert,
 5942        window: &mut Window,
 5943        cx: &mut Context<Self>,
 5944    ) -> Option<Task<Result<()>>> {
 5945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5946        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5947    }
 5948
 5949    pub fn confirm_completion_replace(
 5950        &mut self,
 5951        _: &ConfirmCompletionReplace,
 5952        window: &mut Window,
 5953        cx: &mut Context<Self>,
 5954    ) -> Option<Task<Result<()>>> {
 5955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5956        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5957    }
 5958
 5959    pub fn compose_completion(
 5960        &mut self,
 5961        action: &ComposeCompletion,
 5962        window: &mut Window,
 5963        cx: &mut Context<Self>,
 5964    ) -> Option<Task<Result<()>>> {
 5965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5966        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5967    }
 5968
 5969    fn do_completion(
 5970        &mut self,
 5971        item_ix: Option<usize>,
 5972        intent: CompletionIntent,
 5973        window: &mut Window,
 5974        cx: &mut Context<Editor>,
 5975    ) -> Option<Task<Result<()>>> {
 5976        use language::ToOffset as _;
 5977
 5978        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5979        else {
 5980            return None;
 5981        };
 5982
 5983        let candidate_id = {
 5984            let entries = completions_menu.entries.borrow();
 5985            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5986            if self.show_edit_predictions_in_menu() {
 5987                self.discard_edit_prediction(true, cx);
 5988            }
 5989            mat.candidate_id
 5990        };
 5991
 5992        let completion = completions_menu
 5993            .completions
 5994            .borrow()
 5995            .get(candidate_id)?
 5996            .clone();
 5997        cx.stop_propagation();
 5998
 5999        let buffer_handle = completions_menu.buffer.clone();
 6000
 6001        let CompletionEdit {
 6002            new_text,
 6003            snippet,
 6004            replace_range,
 6005        } = process_completion_for_edit(
 6006            &completion,
 6007            intent,
 6008            &buffer_handle,
 6009            &completions_menu.initial_position.text_anchor,
 6010            cx,
 6011        );
 6012
 6013        let buffer = buffer_handle.read(cx);
 6014        let snapshot = self.buffer.read(cx).snapshot(cx);
 6015        let newest_anchor = self.selections.newest_anchor();
 6016        let replace_range_multibuffer = {
 6017            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6018            excerpt.map_range_from_buffer(replace_range.clone())
 6019        };
 6020        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6021            return None;
 6022        }
 6023
 6024        let old_text = buffer
 6025            .text_for_range(replace_range.clone())
 6026            .collect::<String>();
 6027        let lookbehind = newest_anchor
 6028            .start
 6029            .text_anchor
 6030            .to_offset(buffer)
 6031            .saturating_sub(replace_range.start.0);
 6032        let lookahead = replace_range
 6033            .end
 6034            .0
 6035            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6036        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6037        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6038
 6039        let selections = self
 6040            .selections
 6041            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6042        let mut ranges = Vec::new();
 6043        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6044
 6045        for selection in &selections {
 6046            let range = if selection.id == newest_anchor.id {
 6047                replace_range_multibuffer.clone()
 6048            } else {
 6049                let mut range = selection.range();
 6050
 6051                // if prefix is present, don't duplicate it
 6052                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6053                    range.start = range.start.saturating_sub_usize(lookbehind);
 6054
 6055                    // if suffix is also present, mimic the newest cursor and replace it
 6056                    if selection.id != newest_anchor.id
 6057                        && snapshot.contains_str_at(range.end, suffix)
 6058                    {
 6059                        range.end += lookahead;
 6060                    }
 6061                }
 6062                range
 6063            };
 6064
 6065            ranges.push(range.clone());
 6066
 6067            if !self.linked_edit_ranges.is_empty() {
 6068                let start_anchor = snapshot.anchor_before(range.start);
 6069                let end_anchor = snapshot.anchor_after(range.end);
 6070                if let Some(ranges) = self
 6071                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6072                {
 6073                    for (buffer, edits) in ranges {
 6074                        linked_edits
 6075                            .entry(buffer.clone())
 6076                            .or_default()
 6077                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6078                    }
 6079                }
 6080            }
 6081        }
 6082
 6083        let common_prefix_len = old_text
 6084            .chars()
 6085            .zip(new_text.chars())
 6086            .take_while(|(a, b)| a == b)
 6087            .map(|(a, _)| a.len_utf8())
 6088            .sum::<usize>();
 6089
 6090        cx.emit(EditorEvent::InputHandled {
 6091            utf16_range_to_replace: None,
 6092            text: new_text[common_prefix_len..].into(),
 6093        });
 6094
 6095        self.transact(window, cx, |editor, window, cx| {
 6096            if let Some(mut snippet) = snippet {
 6097                snippet.text = new_text.to_string();
 6098                editor
 6099                    .insert_snippet(&ranges, snippet, window, cx)
 6100                    .log_err();
 6101            } else {
 6102                editor.buffer.update(cx, |multi_buffer, cx| {
 6103                    let auto_indent = match completion.insert_text_mode {
 6104                        Some(InsertTextMode::AS_IS) => None,
 6105                        _ => editor.autoindent_mode.clone(),
 6106                    };
 6107                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6108                    multi_buffer.edit(edits, auto_indent, cx);
 6109                });
 6110            }
 6111            for (buffer, edits) in linked_edits {
 6112                buffer.update(cx, |buffer, cx| {
 6113                    let snapshot = buffer.snapshot();
 6114                    let edits = edits
 6115                        .into_iter()
 6116                        .map(|(range, text)| {
 6117                            use text::ToPoint as TP;
 6118                            let end_point = TP::to_point(&range.end, &snapshot);
 6119                            let start_point = TP::to_point(&range.start, &snapshot);
 6120                            (start_point..end_point, text)
 6121                        })
 6122                        .sorted_by_key(|(range, _)| range.start);
 6123                    buffer.edit(edits, None, cx);
 6124                })
 6125            }
 6126
 6127            editor.refresh_edit_prediction(true, false, window, cx);
 6128        });
 6129        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6130
 6131        let show_new_completions_on_confirm = completion
 6132            .confirm
 6133            .as_ref()
 6134            .is_some_and(|confirm| confirm(intent, window, cx));
 6135        if show_new_completions_on_confirm {
 6136            self.open_or_update_completions_menu(None, None, false, window, cx);
 6137        }
 6138
 6139        let provider = self.completion_provider.as_ref()?;
 6140        drop(completion);
 6141        let apply_edits = provider.apply_additional_edits_for_completion(
 6142            buffer_handle,
 6143            completions_menu.completions.clone(),
 6144            candidate_id,
 6145            true,
 6146            cx,
 6147        );
 6148
 6149        let editor_settings = EditorSettings::get_global(cx);
 6150        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6151            // After the code completion is finished, users often want to know what signatures are needed.
 6152            // so we should automatically call signature_help
 6153            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6154        }
 6155
 6156        Some(cx.foreground_executor().spawn(async move {
 6157            apply_edits.await?;
 6158            Ok(())
 6159        }))
 6160    }
 6161
 6162    pub fn toggle_code_actions(
 6163        &mut self,
 6164        action: &ToggleCodeActions,
 6165        window: &mut Window,
 6166        cx: &mut Context<Self>,
 6167    ) {
 6168        let quick_launch = action.quick_launch;
 6169        let mut context_menu = self.context_menu.borrow_mut();
 6170        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6171            if code_actions.deployed_from == action.deployed_from {
 6172                // Toggle if we're selecting the same one
 6173                *context_menu = None;
 6174                cx.notify();
 6175                return;
 6176            } else {
 6177                // Otherwise, clear it and start a new one
 6178                *context_menu = None;
 6179                cx.notify();
 6180            }
 6181        }
 6182        drop(context_menu);
 6183        let snapshot = self.snapshot(window, cx);
 6184        let deployed_from = action.deployed_from.clone();
 6185        let action = action.clone();
 6186        self.completion_tasks.clear();
 6187        self.discard_edit_prediction(false, cx);
 6188
 6189        let multibuffer_point = match &action.deployed_from {
 6190            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6191                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6192            }
 6193            _ => self
 6194                .selections
 6195                .newest::<Point>(&snapshot.display_snapshot)
 6196                .head(),
 6197        };
 6198        let Some((buffer, buffer_row)) = snapshot
 6199            .buffer_snapshot()
 6200            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6201            .and_then(|(buffer_snapshot, range)| {
 6202                self.buffer()
 6203                    .read(cx)
 6204                    .buffer(buffer_snapshot.remote_id())
 6205                    .map(|buffer| (buffer, range.start.row))
 6206            })
 6207        else {
 6208            return;
 6209        };
 6210        let buffer_id = buffer.read(cx).remote_id();
 6211        let tasks = self
 6212            .tasks
 6213            .get(&(buffer_id, buffer_row))
 6214            .map(|t| Arc::new(t.to_owned()));
 6215
 6216        if !self.focus_handle.is_focused(window) {
 6217            return;
 6218        }
 6219        let project = self.project.clone();
 6220
 6221        let code_actions_task = match deployed_from {
 6222            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6223            _ => self.code_actions(buffer_row, window, cx),
 6224        };
 6225
 6226        let runnable_task = match deployed_from {
 6227            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6228            _ => {
 6229                let mut task_context_task = Task::ready(None);
 6230                if let Some(tasks) = &tasks
 6231                    && let Some(project) = project
 6232                {
 6233                    task_context_task =
 6234                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6235                }
 6236
 6237                cx.spawn_in(window, {
 6238                    let buffer = buffer.clone();
 6239                    async move |editor, cx| {
 6240                        let task_context = task_context_task.await;
 6241
 6242                        let resolved_tasks =
 6243                            tasks
 6244                                .zip(task_context.clone())
 6245                                .map(|(tasks, task_context)| ResolvedTasks {
 6246                                    templates: tasks.resolve(&task_context).collect(),
 6247                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6248                                        multibuffer_point.row,
 6249                                        tasks.column,
 6250                                    )),
 6251                                });
 6252                        let debug_scenarios = editor
 6253                            .update(cx, |editor, cx| {
 6254                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6255                            })?
 6256                            .await;
 6257                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6258                    }
 6259                })
 6260            }
 6261        };
 6262
 6263        cx.spawn_in(window, async move |editor, cx| {
 6264            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6265            let code_actions = code_actions_task.await;
 6266            let spawn_straight_away = quick_launch
 6267                && resolved_tasks
 6268                    .as_ref()
 6269                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6270                && code_actions
 6271                    .as_ref()
 6272                    .is_none_or(|actions| actions.is_empty())
 6273                && debug_scenarios.is_empty();
 6274
 6275            editor.update_in(cx, |editor, window, cx| {
 6276                crate::hover_popover::hide_hover(editor, cx);
 6277                let actions = CodeActionContents::new(
 6278                    resolved_tasks,
 6279                    code_actions,
 6280                    debug_scenarios,
 6281                    task_context.unwrap_or_default(),
 6282                );
 6283
 6284                // Don't show the menu if there are no actions available
 6285                if actions.is_empty() {
 6286                    cx.notify();
 6287                    return Task::ready(Ok(()));
 6288                }
 6289
 6290                *editor.context_menu.borrow_mut() =
 6291                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6292                        buffer,
 6293                        actions,
 6294                        selected_item: Default::default(),
 6295                        scroll_handle: UniformListScrollHandle::default(),
 6296                        deployed_from,
 6297                    }));
 6298                cx.notify();
 6299                if spawn_straight_away
 6300                    && let Some(task) = editor.confirm_code_action(
 6301                        &ConfirmCodeAction { item_ix: Some(0) },
 6302                        window,
 6303                        cx,
 6304                    )
 6305                {
 6306                    return task;
 6307                }
 6308
 6309                Task::ready(Ok(()))
 6310            })
 6311        })
 6312        .detach_and_log_err(cx);
 6313    }
 6314
 6315    fn debug_scenarios(
 6316        &mut self,
 6317        resolved_tasks: &Option<ResolvedTasks>,
 6318        buffer: &Entity<Buffer>,
 6319        cx: &mut App,
 6320    ) -> Task<Vec<task::DebugScenario>> {
 6321        maybe!({
 6322            let project = self.project()?;
 6323            let dap_store = project.read(cx).dap_store();
 6324            let mut scenarios = vec![];
 6325            let resolved_tasks = resolved_tasks.as_ref()?;
 6326            let buffer = buffer.read(cx);
 6327            let language = buffer.language()?;
 6328            let file = buffer.file();
 6329            let debug_adapter = language_settings(language.name().into(), file, cx)
 6330                .debuggers
 6331                .first()
 6332                .map(SharedString::from)
 6333                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6334
 6335            dap_store.update(cx, |dap_store, cx| {
 6336                for (_, task) in &resolved_tasks.templates {
 6337                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6338                        task.original_task().clone(),
 6339                        debug_adapter.clone().into(),
 6340                        task.display_label().to_owned().into(),
 6341                        cx,
 6342                    );
 6343                    scenarios.push(maybe_scenario);
 6344                }
 6345            });
 6346            Some(cx.background_spawn(async move {
 6347                futures::future::join_all(scenarios)
 6348                    .await
 6349                    .into_iter()
 6350                    .flatten()
 6351                    .collect::<Vec<_>>()
 6352            }))
 6353        })
 6354        .unwrap_or_else(|| Task::ready(vec![]))
 6355    }
 6356
 6357    fn code_actions(
 6358        &mut self,
 6359        buffer_row: u32,
 6360        window: &mut Window,
 6361        cx: &mut Context<Self>,
 6362    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6363        let mut task = self.code_actions_task.take();
 6364        cx.spawn_in(window, async move |editor, cx| {
 6365            while let Some(prev_task) = task {
 6366                prev_task.await.log_err();
 6367                task = editor
 6368                    .update(cx, |this, _| this.code_actions_task.take())
 6369                    .ok()?;
 6370            }
 6371
 6372            editor
 6373                .update(cx, |editor, cx| {
 6374                    editor
 6375                        .available_code_actions
 6376                        .clone()
 6377                        .and_then(|(location, code_actions)| {
 6378                            let snapshot = location.buffer.read(cx).snapshot();
 6379                            let point_range = location.range.to_point(&snapshot);
 6380                            let point_range = point_range.start.row..=point_range.end.row;
 6381                            if point_range.contains(&buffer_row) {
 6382                                Some(code_actions)
 6383                            } else {
 6384                                None
 6385                            }
 6386                        })
 6387                })
 6388                .ok()
 6389                .flatten()
 6390        })
 6391    }
 6392
 6393    pub fn confirm_code_action(
 6394        &mut self,
 6395        action: &ConfirmCodeAction,
 6396        window: &mut Window,
 6397        cx: &mut Context<Self>,
 6398    ) -> Option<Task<Result<()>>> {
 6399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6400
 6401        let actions_menu =
 6402            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6403                menu
 6404            } else {
 6405                return None;
 6406            };
 6407
 6408        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6409        let action = actions_menu.actions.get(action_ix)?;
 6410        let title = action.label();
 6411        let buffer = actions_menu.buffer;
 6412        let workspace = self.workspace()?;
 6413
 6414        match action {
 6415            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6416                workspace.update(cx, |workspace, cx| {
 6417                    workspace.schedule_resolved_task(
 6418                        task_source_kind,
 6419                        resolved_task,
 6420                        false,
 6421                        window,
 6422                        cx,
 6423                    );
 6424
 6425                    Some(Task::ready(Ok(())))
 6426                })
 6427            }
 6428            CodeActionsItem::CodeAction {
 6429                excerpt_id,
 6430                action,
 6431                provider,
 6432            } => {
 6433                let apply_code_action =
 6434                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6435                let workspace = workspace.downgrade();
 6436                Some(cx.spawn_in(window, async move |editor, cx| {
 6437                    let project_transaction = apply_code_action.await?;
 6438                    Self::open_project_transaction(
 6439                        &editor,
 6440                        workspace,
 6441                        project_transaction,
 6442                        title,
 6443                        cx,
 6444                    )
 6445                    .await
 6446                }))
 6447            }
 6448            CodeActionsItem::DebugScenario(scenario) => {
 6449                let context = actions_menu.actions.context;
 6450
 6451                workspace.update(cx, |workspace, cx| {
 6452                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6453                    workspace.start_debug_session(
 6454                        scenario,
 6455                        context,
 6456                        Some(buffer),
 6457                        None,
 6458                        window,
 6459                        cx,
 6460                    );
 6461                });
 6462                Some(Task::ready(Ok(())))
 6463            }
 6464        }
 6465    }
 6466
 6467    pub async fn open_project_transaction(
 6468        editor: &WeakEntity<Editor>,
 6469        workspace: WeakEntity<Workspace>,
 6470        transaction: ProjectTransaction,
 6471        title: String,
 6472        cx: &mut AsyncWindowContext,
 6473    ) -> Result<()> {
 6474        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6475        cx.update(|_, cx| {
 6476            entries.sort_unstable_by_key(|(buffer, _)| {
 6477                buffer.read(cx).file().map(|f| f.path().clone())
 6478            });
 6479        })?;
 6480        if entries.is_empty() {
 6481            return Ok(());
 6482        }
 6483
 6484        // If the project transaction's edits are all contained within this editor, then
 6485        // avoid opening a new editor to display them.
 6486
 6487        if let [(buffer, transaction)] = &*entries {
 6488            let excerpt = editor.update(cx, |editor, cx| {
 6489                editor
 6490                    .buffer()
 6491                    .read(cx)
 6492                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6493            })?;
 6494            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6495                && excerpted_buffer == *buffer
 6496            {
 6497                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6498                    let excerpt_range = excerpt_range.to_offset(buffer);
 6499                    buffer
 6500                        .edited_ranges_for_transaction::<usize>(transaction)
 6501                        .all(|range| {
 6502                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6503                        })
 6504                })?;
 6505
 6506                if all_edits_within_excerpt {
 6507                    return Ok(());
 6508                }
 6509            }
 6510        }
 6511
 6512        let mut ranges_to_highlight = Vec::new();
 6513        let excerpt_buffer = cx.new(|cx| {
 6514            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6515            for (buffer_handle, transaction) in &entries {
 6516                let edited_ranges = buffer_handle
 6517                    .read(cx)
 6518                    .edited_ranges_for_transaction::<Point>(transaction)
 6519                    .collect::<Vec<_>>();
 6520                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6521                    PathKey::for_buffer(buffer_handle, cx),
 6522                    buffer_handle.clone(),
 6523                    edited_ranges,
 6524                    multibuffer_context_lines(cx),
 6525                    cx,
 6526                );
 6527
 6528                ranges_to_highlight.extend(ranges);
 6529            }
 6530            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6531            multibuffer
 6532        })?;
 6533
 6534        workspace.update_in(cx, |workspace, window, cx| {
 6535            let project = workspace.project().clone();
 6536            let editor =
 6537                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6538            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6539            editor.update(cx, |editor, cx| {
 6540                editor.highlight_background::<Self>(
 6541                    &ranges_to_highlight,
 6542                    |theme| theme.colors().editor_highlighted_line_background,
 6543                    cx,
 6544                );
 6545            });
 6546        })?;
 6547
 6548        Ok(())
 6549    }
 6550
 6551    pub fn clear_code_action_providers(&mut self) {
 6552        self.code_action_providers.clear();
 6553        self.available_code_actions.take();
 6554    }
 6555
 6556    pub fn add_code_action_provider(
 6557        &mut self,
 6558        provider: Rc<dyn CodeActionProvider>,
 6559        window: &mut Window,
 6560        cx: &mut Context<Self>,
 6561    ) {
 6562        if self
 6563            .code_action_providers
 6564            .iter()
 6565            .any(|existing_provider| existing_provider.id() == provider.id())
 6566        {
 6567            return;
 6568        }
 6569
 6570        self.code_action_providers.push(provider);
 6571        self.refresh_code_actions(window, cx);
 6572    }
 6573
 6574    pub fn remove_code_action_provider(
 6575        &mut self,
 6576        id: Arc<str>,
 6577        window: &mut Window,
 6578        cx: &mut Context<Self>,
 6579    ) {
 6580        self.code_action_providers
 6581            .retain(|provider| provider.id() != id);
 6582        self.refresh_code_actions(window, cx);
 6583    }
 6584
 6585    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6586        !self.code_action_providers.is_empty()
 6587            && EditorSettings::get_global(cx).toolbar.code_actions
 6588    }
 6589
 6590    pub fn has_available_code_actions(&self) -> bool {
 6591        self.available_code_actions
 6592            .as_ref()
 6593            .is_some_and(|(_, actions)| !actions.is_empty())
 6594    }
 6595
 6596    fn render_inline_code_actions(
 6597        &self,
 6598        icon_size: ui::IconSize,
 6599        display_row: DisplayRow,
 6600        is_active: bool,
 6601        cx: &mut Context<Self>,
 6602    ) -> AnyElement {
 6603        let show_tooltip = !self.context_menu_visible();
 6604        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6605            .icon_size(icon_size)
 6606            .shape(ui::IconButtonShape::Square)
 6607            .icon_color(ui::Color::Hidden)
 6608            .toggle_state(is_active)
 6609            .when(show_tooltip, |this| {
 6610                this.tooltip({
 6611                    let focus_handle = self.focus_handle.clone();
 6612                    move |_window, cx| {
 6613                        Tooltip::for_action_in(
 6614                            "Toggle Code Actions",
 6615                            &ToggleCodeActions {
 6616                                deployed_from: None,
 6617                                quick_launch: false,
 6618                            },
 6619                            &focus_handle,
 6620                            cx,
 6621                        )
 6622                    }
 6623                })
 6624            })
 6625            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6626                window.focus(&editor.focus_handle(cx));
 6627                editor.toggle_code_actions(
 6628                    &crate::actions::ToggleCodeActions {
 6629                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6630                            display_row,
 6631                        )),
 6632                        quick_launch: false,
 6633                    },
 6634                    window,
 6635                    cx,
 6636                );
 6637            }))
 6638            .into_any_element()
 6639    }
 6640
 6641    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6642        &self.context_menu
 6643    }
 6644
 6645    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6646        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6647            cx.background_executor()
 6648                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6649                .await;
 6650
 6651            let (start_buffer, start, _, end, newest_selection) = this
 6652                .update(cx, |this, cx| {
 6653                    let newest_selection = this.selections.newest_anchor().clone();
 6654                    if newest_selection.head().diff_base_anchor.is_some() {
 6655                        return None;
 6656                    }
 6657                    let display_snapshot = this.display_snapshot(cx);
 6658                    let newest_selection_adjusted =
 6659                        this.selections.newest_adjusted(&display_snapshot);
 6660                    let buffer = this.buffer.read(cx);
 6661
 6662                    let (start_buffer, start) =
 6663                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6664                    let (end_buffer, end) =
 6665                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6666
 6667                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6668                })?
 6669                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6670                .context(
 6671                    "Expected selection to lie in a single buffer when refreshing code actions",
 6672                )?;
 6673            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6674                let providers = this.code_action_providers.clone();
 6675                let tasks = this
 6676                    .code_action_providers
 6677                    .iter()
 6678                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6679                    .collect::<Vec<_>>();
 6680                (providers, tasks)
 6681            })?;
 6682
 6683            let mut actions = Vec::new();
 6684            for (provider, provider_actions) in
 6685                providers.into_iter().zip(future::join_all(tasks).await)
 6686            {
 6687                if let Some(provider_actions) = provider_actions.log_err() {
 6688                    actions.extend(provider_actions.into_iter().map(|action| {
 6689                        AvailableCodeAction {
 6690                            excerpt_id: newest_selection.start.excerpt_id,
 6691                            action,
 6692                            provider: provider.clone(),
 6693                        }
 6694                    }));
 6695                }
 6696            }
 6697
 6698            this.update(cx, |this, cx| {
 6699                this.available_code_actions = if actions.is_empty() {
 6700                    None
 6701                } else {
 6702                    Some((
 6703                        Location {
 6704                            buffer: start_buffer,
 6705                            range: start..end,
 6706                        },
 6707                        actions.into(),
 6708                    ))
 6709                };
 6710                cx.notify();
 6711            })
 6712        }));
 6713    }
 6714
 6715    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6716        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6717            self.show_git_blame_inline = false;
 6718
 6719            self.show_git_blame_inline_delay_task =
 6720                Some(cx.spawn_in(window, async move |this, cx| {
 6721                    cx.background_executor().timer(delay).await;
 6722
 6723                    this.update(cx, |this, cx| {
 6724                        this.show_git_blame_inline = true;
 6725                        cx.notify();
 6726                    })
 6727                    .log_err();
 6728                }));
 6729        }
 6730    }
 6731
 6732    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6733        let snapshot = self.snapshot(window, cx);
 6734        let cursor = self
 6735            .selections
 6736            .newest::<Point>(&snapshot.display_snapshot)
 6737            .head();
 6738        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6739        else {
 6740            return;
 6741        };
 6742
 6743        let Some(blame) = self.blame.as_ref() else {
 6744            return;
 6745        };
 6746
 6747        let row_info = RowInfo {
 6748            buffer_id: Some(buffer.remote_id()),
 6749            buffer_row: Some(point.row),
 6750            ..Default::default()
 6751        };
 6752        let Some((buffer, blame_entry)) = blame
 6753            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6754            .flatten()
 6755        else {
 6756            return;
 6757        };
 6758
 6759        let anchor = self.selections.newest_anchor().head();
 6760        let position = self.to_pixel_point(anchor, &snapshot, window);
 6761        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6762            self.show_blame_popover(
 6763                buffer,
 6764                &blame_entry,
 6765                position + last_bounds.origin,
 6766                true,
 6767                cx,
 6768            );
 6769        };
 6770    }
 6771
 6772    fn show_blame_popover(
 6773        &mut self,
 6774        buffer: BufferId,
 6775        blame_entry: &BlameEntry,
 6776        position: gpui::Point<Pixels>,
 6777        ignore_timeout: bool,
 6778        cx: &mut Context<Self>,
 6779    ) {
 6780        if let Some(state) = &mut self.inline_blame_popover {
 6781            state.hide_task.take();
 6782        } else {
 6783            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6784            let blame_entry = blame_entry.clone();
 6785            let show_task = cx.spawn(async move |editor, cx| {
 6786                if !ignore_timeout {
 6787                    cx.background_executor()
 6788                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6789                        .await;
 6790                }
 6791                editor
 6792                    .update(cx, |editor, cx| {
 6793                        editor.inline_blame_popover_show_task.take();
 6794                        let Some(blame) = editor.blame.as_ref() else {
 6795                            return;
 6796                        };
 6797                        let blame = blame.read(cx);
 6798                        let details = blame.details_for_entry(buffer, &blame_entry);
 6799                        let markdown = cx.new(|cx| {
 6800                            Markdown::new(
 6801                                details
 6802                                    .as_ref()
 6803                                    .map(|message| message.message.clone())
 6804                                    .unwrap_or_default(),
 6805                                None,
 6806                                None,
 6807                                cx,
 6808                            )
 6809                        });
 6810                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6811                            position,
 6812                            hide_task: None,
 6813                            popover_bounds: None,
 6814                            popover_state: InlineBlamePopoverState {
 6815                                scroll_handle: ScrollHandle::new(),
 6816                                commit_message: details,
 6817                                markdown,
 6818                            },
 6819                            keyboard_grace: ignore_timeout,
 6820                        });
 6821                        cx.notify();
 6822                    })
 6823                    .ok();
 6824            });
 6825            self.inline_blame_popover_show_task = Some(show_task);
 6826        }
 6827    }
 6828
 6829    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6830        self.inline_blame_popover_show_task.take();
 6831        if let Some(state) = &mut self.inline_blame_popover {
 6832            let hide_task = cx.spawn(async move |editor, cx| {
 6833                if !ignore_timeout {
 6834                    cx.background_executor()
 6835                        .timer(std::time::Duration::from_millis(100))
 6836                        .await;
 6837                }
 6838                editor
 6839                    .update(cx, |editor, cx| {
 6840                        editor.inline_blame_popover.take();
 6841                        cx.notify();
 6842                    })
 6843                    .ok();
 6844            });
 6845            state.hide_task = Some(hide_task);
 6846            true
 6847        } else {
 6848            false
 6849        }
 6850    }
 6851
 6852    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6853        if self.pending_rename.is_some() {
 6854            return None;
 6855        }
 6856
 6857        let provider = self.semantics_provider.clone()?;
 6858        let buffer = self.buffer.read(cx);
 6859        let newest_selection = self.selections.newest_anchor().clone();
 6860        let cursor_position = newest_selection.head();
 6861        let (cursor_buffer, cursor_buffer_position) =
 6862            buffer.text_anchor_for_position(cursor_position, cx)?;
 6863        let (tail_buffer, tail_buffer_position) =
 6864            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6865        if cursor_buffer != tail_buffer {
 6866            return None;
 6867        }
 6868
 6869        let snapshot = cursor_buffer.read(cx).snapshot();
 6870        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6871        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6872        if start_word_range != end_word_range {
 6873            self.document_highlights_task.take();
 6874            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6875            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6876            return None;
 6877        }
 6878
 6879        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6880        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6881            cx.background_executor()
 6882                .timer(Duration::from_millis(debounce))
 6883                .await;
 6884
 6885            let highlights = if let Some(highlights) = cx
 6886                .update(|cx| {
 6887                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6888                })
 6889                .ok()
 6890                .flatten()
 6891            {
 6892                highlights.await.log_err()
 6893            } else {
 6894                None
 6895            };
 6896
 6897            if let Some(highlights) = highlights {
 6898                this.update(cx, |this, cx| {
 6899                    if this.pending_rename.is_some() {
 6900                        return;
 6901                    }
 6902
 6903                    let buffer = this.buffer.read(cx);
 6904                    if buffer
 6905                        .text_anchor_for_position(cursor_position, cx)
 6906                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6907                    {
 6908                        return;
 6909                    }
 6910
 6911                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6912                    let mut write_ranges = Vec::new();
 6913                    let mut read_ranges = Vec::new();
 6914                    for highlight in highlights {
 6915                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6916                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6917                        {
 6918                            let start = highlight
 6919                                .range
 6920                                .start
 6921                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6922                            let end = highlight
 6923                                .range
 6924                                .end
 6925                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6926                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6927                                continue;
 6928                            }
 6929
 6930                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6931                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6932                                write_ranges.push(range);
 6933                            } else {
 6934                                read_ranges.push(range);
 6935                            }
 6936                        }
 6937                    }
 6938
 6939                    this.highlight_background::<DocumentHighlightRead>(
 6940                        &read_ranges,
 6941                        |theme| theme.colors().editor_document_highlight_read_background,
 6942                        cx,
 6943                    );
 6944                    this.highlight_background::<DocumentHighlightWrite>(
 6945                        &write_ranges,
 6946                        |theme| theme.colors().editor_document_highlight_write_background,
 6947                        cx,
 6948                    );
 6949                    cx.notify();
 6950                })
 6951                .log_err();
 6952            }
 6953        }));
 6954        None
 6955    }
 6956
 6957    fn prepare_highlight_query_from_selection(
 6958        &mut self,
 6959        window: &Window,
 6960        cx: &mut Context<Editor>,
 6961    ) -> Option<(String, Range<Anchor>)> {
 6962        if matches!(self.mode, EditorMode::SingleLine) {
 6963            return None;
 6964        }
 6965        if !EditorSettings::get_global(cx).selection_highlight {
 6966            return None;
 6967        }
 6968        if self.selections.count() != 1 || self.selections.line_mode() {
 6969            return None;
 6970        }
 6971        let snapshot = self.snapshot(window, cx);
 6972        let selection = self.selections.newest::<Point>(&snapshot);
 6973        // If the selection spans multiple rows OR it is empty
 6974        if selection.start.row != selection.end.row
 6975            || selection.start.column == selection.end.column
 6976        {
 6977            return None;
 6978        }
 6979        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6980        let query = snapshot
 6981            .buffer_snapshot()
 6982            .text_for_range(selection_anchor_range.clone())
 6983            .collect::<String>();
 6984        if query.trim().is_empty() {
 6985            return None;
 6986        }
 6987        Some((query, selection_anchor_range))
 6988    }
 6989
 6990    fn update_selection_occurrence_highlights(
 6991        &mut self,
 6992        query_text: String,
 6993        query_range: Range<Anchor>,
 6994        multi_buffer_range_to_query: Range<Point>,
 6995        use_debounce: bool,
 6996        window: &mut Window,
 6997        cx: &mut Context<Editor>,
 6998    ) -> Task<()> {
 6999        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7000        cx.spawn_in(window, async move |editor, cx| {
 7001            if use_debounce {
 7002                cx.background_executor()
 7003                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7004                    .await;
 7005            }
 7006            let match_task = cx.background_spawn(async move {
 7007                let buffer_ranges = multi_buffer_snapshot
 7008                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7009                    .into_iter()
 7010                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7011                let mut match_ranges = Vec::new();
 7012                let Ok(regex) = project::search::SearchQuery::text(
 7013                    query_text.clone(),
 7014                    false,
 7015                    false,
 7016                    false,
 7017                    Default::default(),
 7018                    Default::default(),
 7019                    false,
 7020                    None,
 7021                ) else {
 7022                    return Vec::default();
 7023                };
 7024                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7025                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7026                    match_ranges.extend(
 7027                        regex
 7028                            .search(
 7029                                buffer_snapshot,
 7030                                Some(search_range.start.0..search_range.end.0),
 7031                            )
 7032                            .await
 7033                            .into_iter()
 7034                            .filter_map(|match_range| {
 7035                                let match_start = buffer_snapshot
 7036                                    .anchor_after(search_range.start + match_range.start);
 7037                                let match_end = buffer_snapshot
 7038                                    .anchor_before(search_range.start + match_range.end);
 7039                                let match_anchor_range =
 7040                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7041                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7042                            }),
 7043                    );
 7044                }
 7045                match_ranges
 7046            });
 7047            let match_ranges = match_task.await;
 7048            editor
 7049                .update_in(cx, |editor, _, cx| {
 7050                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7051                    if !match_ranges.is_empty() {
 7052                        editor.highlight_background::<SelectedTextHighlight>(
 7053                            &match_ranges,
 7054                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7055                            cx,
 7056                        )
 7057                    }
 7058                })
 7059                .log_err();
 7060        })
 7061    }
 7062
 7063    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7064        struct NewlineFold;
 7065        let type_id = std::any::TypeId::of::<NewlineFold>();
 7066        if !self.mode.is_single_line() {
 7067            return;
 7068        }
 7069        let snapshot = self.snapshot(window, cx);
 7070        if snapshot.buffer_snapshot().max_point().row == 0 {
 7071            return;
 7072        }
 7073        let task = cx.background_spawn(async move {
 7074            let new_newlines = snapshot
 7075                .buffer_chars_at(MultiBufferOffset(0))
 7076                .filter_map(|(c, i)| {
 7077                    if c == '\n' {
 7078                        Some(
 7079                            snapshot.buffer_snapshot().anchor_after(i)
 7080                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7081                        )
 7082                    } else {
 7083                        None
 7084                    }
 7085                })
 7086                .collect::<Vec<_>>();
 7087            let existing_newlines = snapshot
 7088                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7089                .filter_map(|fold| {
 7090                    if fold.placeholder.type_tag == Some(type_id) {
 7091                        Some(fold.range.start..fold.range.end)
 7092                    } else {
 7093                        None
 7094                    }
 7095                })
 7096                .collect::<Vec<_>>();
 7097
 7098            (new_newlines, existing_newlines)
 7099        });
 7100        self.folding_newlines = cx.spawn(async move |this, cx| {
 7101            let (new_newlines, existing_newlines) = task.await;
 7102            if new_newlines == existing_newlines {
 7103                return;
 7104            }
 7105            let placeholder = FoldPlaceholder {
 7106                render: Arc::new(move |_, _, cx| {
 7107                    div()
 7108                        .bg(cx.theme().status().hint_background)
 7109                        .border_b_1()
 7110                        .size_full()
 7111                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7112                        .border_color(cx.theme().status().hint)
 7113                        .child("\\n")
 7114                        .into_any()
 7115                }),
 7116                constrain_width: false,
 7117                merge_adjacent: false,
 7118                type_tag: Some(type_id),
 7119            };
 7120            let creases = new_newlines
 7121                .into_iter()
 7122                .map(|range| Crease::simple(range, placeholder.clone()))
 7123                .collect();
 7124            this.update(cx, |this, cx| {
 7125                this.display_map.update(cx, |display_map, cx| {
 7126                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7127                    display_map.fold(creases, cx);
 7128                });
 7129            })
 7130            .ok();
 7131        });
 7132    }
 7133
 7134    fn refresh_selected_text_highlights(
 7135        &mut self,
 7136        on_buffer_edit: bool,
 7137        window: &mut Window,
 7138        cx: &mut Context<Editor>,
 7139    ) {
 7140        let Some((query_text, query_range)) =
 7141            self.prepare_highlight_query_from_selection(window, cx)
 7142        else {
 7143            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7144            self.quick_selection_highlight_task.take();
 7145            self.debounced_selection_highlight_task.take();
 7146            return;
 7147        };
 7148        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7149        if on_buffer_edit
 7150            || self
 7151                .quick_selection_highlight_task
 7152                .as_ref()
 7153                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7154        {
 7155            let multi_buffer_visible_start = self
 7156                .scroll_manager
 7157                .anchor()
 7158                .anchor
 7159                .to_point(&multi_buffer_snapshot);
 7160            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7161                multi_buffer_visible_start
 7162                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7163                Bias::Left,
 7164            );
 7165            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7166            self.quick_selection_highlight_task = Some((
 7167                query_range.clone(),
 7168                self.update_selection_occurrence_highlights(
 7169                    query_text.clone(),
 7170                    query_range.clone(),
 7171                    multi_buffer_visible_range,
 7172                    false,
 7173                    window,
 7174                    cx,
 7175                ),
 7176            ));
 7177        }
 7178        if on_buffer_edit
 7179            || self
 7180                .debounced_selection_highlight_task
 7181                .as_ref()
 7182                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7183        {
 7184            let multi_buffer_start = multi_buffer_snapshot
 7185                .anchor_before(MultiBufferOffset(0))
 7186                .to_point(&multi_buffer_snapshot);
 7187            let multi_buffer_end = multi_buffer_snapshot
 7188                .anchor_after(multi_buffer_snapshot.len())
 7189                .to_point(&multi_buffer_snapshot);
 7190            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7191            self.debounced_selection_highlight_task = Some((
 7192                query_range.clone(),
 7193                self.update_selection_occurrence_highlights(
 7194                    query_text,
 7195                    query_range,
 7196                    multi_buffer_full_range,
 7197                    true,
 7198                    window,
 7199                    cx,
 7200                ),
 7201            ));
 7202        }
 7203    }
 7204
 7205    pub fn refresh_edit_prediction(
 7206        &mut self,
 7207        debounce: bool,
 7208        user_requested: bool,
 7209        window: &mut Window,
 7210        cx: &mut Context<Self>,
 7211    ) -> Option<()> {
 7212        if DisableAiSettings::get_global(cx).disable_ai {
 7213            return None;
 7214        }
 7215
 7216        let provider = self.edit_prediction_provider()?;
 7217        let cursor = self.selections.newest_anchor().head();
 7218        let (buffer, cursor_buffer_position) =
 7219            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7220
 7221        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7222            self.discard_edit_prediction(false, cx);
 7223            return None;
 7224        }
 7225
 7226        self.update_visible_edit_prediction(window, cx);
 7227
 7228        if !user_requested
 7229            && (!self.should_show_edit_predictions()
 7230                || !self.is_focused(window)
 7231                || buffer.read(cx).is_empty())
 7232        {
 7233            self.discard_edit_prediction(false, cx);
 7234            return None;
 7235        }
 7236
 7237        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7238        Some(())
 7239    }
 7240
 7241    fn show_edit_predictions_in_menu(&self) -> bool {
 7242        match self.edit_prediction_settings {
 7243            EditPredictionSettings::Disabled => false,
 7244            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7245        }
 7246    }
 7247
 7248    pub fn edit_predictions_enabled(&self) -> bool {
 7249        match self.edit_prediction_settings {
 7250            EditPredictionSettings::Disabled => false,
 7251            EditPredictionSettings::Enabled { .. } => true,
 7252        }
 7253    }
 7254
 7255    fn edit_prediction_requires_modifier(&self) -> bool {
 7256        match self.edit_prediction_settings {
 7257            EditPredictionSettings::Disabled => false,
 7258            EditPredictionSettings::Enabled {
 7259                preview_requires_modifier,
 7260                ..
 7261            } => preview_requires_modifier,
 7262        }
 7263    }
 7264
 7265    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7266        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7267            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7268            self.discard_edit_prediction(false, cx);
 7269        } else {
 7270            let selection = self.selections.newest_anchor();
 7271            let cursor = selection.head();
 7272
 7273            if let Some((buffer, cursor_buffer_position)) =
 7274                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7275            {
 7276                self.edit_prediction_settings =
 7277                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7278            }
 7279        }
 7280    }
 7281
 7282    fn edit_prediction_settings_at_position(
 7283        &self,
 7284        buffer: &Entity<Buffer>,
 7285        buffer_position: language::Anchor,
 7286        cx: &App,
 7287    ) -> EditPredictionSettings {
 7288        if !self.mode.is_full()
 7289            || !self.show_edit_predictions_override.unwrap_or(true)
 7290            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7291        {
 7292            return EditPredictionSettings::Disabled;
 7293        }
 7294
 7295        let buffer = buffer.read(cx);
 7296
 7297        let file = buffer.file();
 7298
 7299        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7300            return EditPredictionSettings::Disabled;
 7301        };
 7302
 7303        let by_provider = matches!(
 7304            self.menu_edit_predictions_policy,
 7305            MenuEditPredictionsPolicy::ByProvider
 7306        );
 7307
 7308        let show_in_menu = by_provider
 7309            && self
 7310                .edit_prediction_provider
 7311                .as_ref()
 7312                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7313
 7314        let preview_requires_modifier =
 7315            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7316
 7317        EditPredictionSettings::Enabled {
 7318            show_in_menu,
 7319            preview_requires_modifier,
 7320        }
 7321    }
 7322
 7323    fn should_show_edit_predictions(&self) -> bool {
 7324        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7325    }
 7326
 7327    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7328        matches!(
 7329            self.edit_prediction_preview,
 7330            EditPredictionPreview::Active { .. }
 7331        )
 7332    }
 7333
 7334    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7335        let cursor = self.selections.newest_anchor().head();
 7336        if let Some((buffer, cursor_position)) =
 7337            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7338        {
 7339            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7340        } else {
 7341            false
 7342        }
 7343    }
 7344
 7345    pub fn supports_minimap(&self, cx: &App) -> bool {
 7346        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7347    }
 7348
 7349    fn edit_predictions_enabled_in_buffer(
 7350        &self,
 7351        buffer: &Entity<Buffer>,
 7352        buffer_position: language::Anchor,
 7353        cx: &App,
 7354    ) -> bool {
 7355        maybe!({
 7356            if self.read_only(cx) {
 7357                return Some(false);
 7358            }
 7359            let provider = self.edit_prediction_provider()?;
 7360            if !provider.is_enabled(buffer, buffer_position, cx) {
 7361                return Some(false);
 7362            }
 7363            let buffer = buffer.read(cx);
 7364            let Some(file) = buffer.file() else {
 7365                return Some(true);
 7366            };
 7367            let settings = all_language_settings(Some(file), cx);
 7368            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7369        })
 7370        .unwrap_or(false)
 7371    }
 7372
 7373    fn cycle_edit_prediction(
 7374        &mut self,
 7375        direction: Direction,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) -> Option<()> {
 7379        let provider = self.edit_prediction_provider()?;
 7380        let cursor = self.selections.newest_anchor().head();
 7381        let (buffer, cursor_buffer_position) =
 7382            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7383        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7384            return None;
 7385        }
 7386
 7387        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7388        self.update_visible_edit_prediction(window, cx);
 7389
 7390        Some(())
 7391    }
 7392
 7393    pub fn show_edit_prediction(
 7394        &mut self,
 7395        _: &ShowEditPrediction,
 7396        window: &mut Window,
 7397        cx: &mut Context<Self>,
 7398    ) {
 7399        if !self.has_active_edit_prediction() {
 7400            self.refresh_edit_prediction(false, true, window, cx);
 7401            return;
 7402        }
 7403
 7404        self.update_visible_edit_prediction(window, cx);
 7405    }
 7406
 7407    pub fn display_cursor_names(
 7408        &mut self,
 7409        _: &DisplayCursorNames,
 7410        window: &mut Window,
 7411        cx: &mut Context<Self>,
 7412    ) {
 7413        self.show_cursor_names(window, cx);
 7414    }
 7415
 7416    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7417        self.show_cursor_names = true;
 7418        cx.notify();
 7419        cx.spawn_in(window, async move |this, cx| {
 7420            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7421            this.update(cx, |this, cx| {
 7422                this.show_cursor_names = false;
 7423                cx.notify()
 7424            })
 7425            .ok()
 7426        })
 7427        .detach();
 7428    }
 7429
 7430    pub fn next_edit_prediction(
 7431        &mut self,
 7432        _: &NextEditPrediction,
 7433        window: &mut Window,
 7434        cx: &mut Context<Self>,
 7435    ) {
 7436        if self.has_active_edit_prediction() {
 7437            self.cycle_edit_prediction(Direction::Next, window, cx);
 7438        } else {
 7439            let is_copilot_disabled = self
 7440                .refresh_edit_prediction(false, true, window, cx)
 7441                .is_none();
 7442            if is_copilot_disabled {
 7443                cx.propagate();
 7444            }
 7445        }
 7446    }
 7447
 7448    pub fn previous_edit_prediction(
 7449        &mut self,
 7450        _: &PreviousEditPrediction,
 7451        window: &mut Window,
 7452        cx: &mut Context<Self>,
 7453    ) {
 7454        if self.has_active_edit_prediction() {
 7455            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7456        } else {
 7457            let is_copilot_disabled = self
 7458                .refresh_edit_prediction(false, true, window, cx)
 7459                .is_none();
 7460            if is_copilot_disabled {
 7461                cx.propagate();
 7462            }
 7463        }
 7464    }
 7465
 7466    pub fn accept_edit_prediction(
 7467        &mut self,
 7468        _: &AcceptEditPrediction,
 7469        window: &mut Window,
 7470        cx: &mut Context<Self>,
 7471    ) {
 7472        if self.show_edit_predictions_in_menu() {
 7473            self.hide_context_menu(window, cx);
 7474        }
 7475
 7476        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7477            return;
 7478        };
 7479
 7480        match &active_edit_prediction.completion {
 7481            EditPrediction::MoveWithin { target, .. } => {
 7482                let target = *target;
 7483
 7484                if let Some(position_map) = &self.last_position_map {
 7485                    if position_map
 7486                        .visible_row_range
 7487                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7488                        || !self.edit_prediction_requires_modifier()
 7489                    {
 7490                        self.unfold_ranges(&[target..target], true, false, cx);
 7491                        // Note that this is also done in vim's handler of the Tab action.
 7492                        self.change_selections(
 7493                            SelectionEffects::scroll(Autoscroll::newest()),
 7494                            window,
 7495                            cx,
 7496                            |selections| {
 7497                                selections.select_anchor_ranges([target..target]);
 7498                            },
 7499                        );
 7500                        self.clear_row_highlights::<EditPredictionPreview>();
 7501
 7502                        self.edit_prediction_preview
 7503                            .set_previous_scroll_position(None);
 7504                    } else {
 7505                        self.edit_prediction_preview
 7506                            .set_previous_scroll_position(Some(
 7507                                position_map.snapshot.scroll_anchor,
 7508                            ));
 7509
 7510                        self.highlight_rows::<EditPredictionPreview>(
 7511                            target..target,
 7512                            cx.theme().colors().editor_highlighted_line_background,
 7513                            RowHighlightOptions {
 7514                                autoscroll: true,
 7515                                ..Default::default()
 7516                            },
 7517                            cx,
 7518                        );
 7519                        self.request_autoscroll(Autoscroll::fit(), cx);
 7520                    }
 7521                }
 7522            }
 7523            EditPrediction::MoveOutside { snapshot, target } => {
 7524                if let Some(workspace) = self.workspace() {
 7525                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7526                        .detach_and_log_err(cx);
 7527                }
 7528            }
 7529            EditPrediction::Edit { edits, .. } => {
 7530                self.report_edit_prediction_event(
 7531                    active_edit_prediction.completion_id.clone(),
 7532                    true,
 7533                    cx,
 7534                );
 7535
 7536                if let Some(provider) = self.edit_prediction_provider() {
 7537                    provider.accept(cx);
 7538                }
 7539
 7540                // Store the transaction ID and selections before applying the edit
 7541                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7542
 7543                let snapshot = self.buffer.read(cx).snapshot(cx);
 7544                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7545
 7546                self.buffer.update(cx, |buffer, cx| {
 7547                    buffer.edit(edits.iter().cloned(), None, cx)
 7548                });
 7549
 7550                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7551                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7552                });
 7553
 7554                let selections = self.selections.disjoint_anchors_arc();
 7555                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7556                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7557                    if has_new_transaction {
 7558                        self.selection_history
 7559                            .insert_transaction(transaction_id_now, selections);
 7560                    }
 7561                }
 7562
 7563                self.update_visible_edit_prediction(window, cx);
 7564                if self.active_edit_prediction.is_none() {
 7565                    self.refresh_edit_prediction(true, true, window, cx);
 7566                }
 7567
 7568                cx.notify();
 7569            }
 7570        }
 7571
 7572        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7573    }
 7574
 7575    pub fn accept_partial_edit_prediction(
 7576        &mut self,
 7577        _: &AcceptPartialEditPrediction,
 7578        window: &mut Window,
 7579        cx: &mut Context<Self>,
 7580    ) {
 7581        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7582            return;
 7583        };
 7584        if self.selections.count() != 1 {
 7585            return;
 7586        }
 7587
 7588        match &active_edit_prediction.completion {
 7589            EditPrediction::MoveWithin { target, .. } => {
 7590                let target = *target;
 7591                self.change_selections(
 7592                    SelectionEffects::scroll(Autoscroll::newest()),
 7593                    window,
 7594                    cx,
 7595                    |selections| {
 7596                        selections.select_anchor_ranges([target..target]);
 7597                    },
 7598                );
 7599            }
 7600            EditPrediction::MoveOutside { snapshot, target } => {
 7601                if let Some(workspace) = self.workspace() {
 7602                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7603                        .detach_and_log_err(cx);
 7604                }
 7605            }
 7606            EditPrediction::Edit { edits, .. } => {
 7607                self.report_edit_prediction_event(
 7608                    active_edit_prediction.completion_id.clone(),
 7609                    true,
 7610                    cx,
 7611                );
 7612
 7613                // Find an insertion that starts at the cursor position.
 7614                let snapshot = self.buffer.read(cx).snapshot(cx);
 7615                let cursor_offset = self
 7616                    .selections
 7617                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7618                    .head();
 7619                let insertion = edits.iter().find_map(|(range, text)| {
 7620                    let range = range.to_offset(&snapshot);
 7621                    if range.is_empty() && range.start == cursor_offset {
 7622                        Some(text)
 7623                    } else {
 7624                        None
 7625                    }
 7626                });
 7627
 7628                if let Some(text) = insertion {
 7629                    let mut partial_completion = text
 7630                        .chars()
 7631                        .by_ref()
 7632                        .take_while(|c| c.is_alphabetic())
 7633                        .collect::<String>();
 7634                    if partial_completion.is_empty() {
 7635                        partial_completion = text
 7636                            .chars()
 7637                            .by_ref()
 7638                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7639                            .collect::<String>();
 7640                    }
 7641
 7642                    cx.emit(EditorEvent::InputHandled {
 7643                        utf16_range_to_replace: None,
 7644                        text: partial_completion.clone().into(),
 7645                    });
 7646
 7647                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7648
 7649                    self.refresh_edit_prediction(true, true, window, cx);
 7650                    cx.notify();
 7651                } else {
 7652                    self.accept_edit_prediction(&Default::default(), window, cx);
 7653                }
 7654            }
 7655        }
 7656    }
 7657
 7658    fn discard_edit_prediction(
 7659        &mut self,
 7660        should_report_edit_prediction_event: bool,
 7661        cx: &mut Context<Self>,
 7662    ) -> bool {
 7663        if should_report_edit_prediction_event {
 7664            let completion_id = self
 7665                .active_edit_prediction
 7666                .as_ref()
 7667                .and_then(|active_completion| active_completion.completion_id.clone());
 7668
 7669            self.report_edit_prediction_event(completion_id, false, cx);
 7670        }
 7671
 7672        if let Some(provider) = self.edit_prediction_provider() {
 7673            provider.discard(cx);
 7674        }
 7675
 7676        self.take_active_edit_prediction(cx)
 7677    }
 7678
 7679    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7680        let Some(provider) = self.edit_prediction_provider() else {
 7681            return;
 7682        };
 7683
 7684        let Some((_, buffer, _)) = self
 7685            .buffer
 7686            .read(cx)
 7687            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7688        else {
 7689            return;
 7690        };
 7691
 7692        let extension = buffer
 7693            .read(cx)
 7694            .file()
 7695            .and_then(|file| Some(file.path().extension()?.to_string()));
 7696
 7697        let event_type = match accepted {
 7698            true => "Edit Prediction Accepted",
 7699            false => "Edit Prediction Discarded",
 7700        };
 7701        telemetry::event!(
 7702            event_type,
 7703            provider = provider.name(),
 7704            prediction_id = id,
 7705            suggestion_accepted = accepted,
 7706            file_extension = extension,
 7707        );
 7708    }
 7709
 7710    fn open_editor_at_anchor(
 7711        snapshot: &language::BufferSnapshot,
 7712        target: language::Anchor,
 7713        workspace: &Entity<Workspace>,
 7714        window: &mut Window,
 7715        cx: &mut App,
 7716    ) -> Task<Result<()>> {
 7717        workspace.update(cx, |workspace, cx| {
 7718            let path = snapshot.file().map(|file| file.full_path(cx));
 7719            let Some(path) =
 7720                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7721            else {
 7722                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7723            };
 7724            let target = text::ToPoint::to_point(&target, snapshot);
 7725            let item = workspace.open_path(path, None, true, window, cx);
 7726            window.spawn(cx, async move |cx| {
 7727                let Some(editor) = item.await?.downcast::<Editor>() else {
 7728                    return Ok(());
 7729                };
 7730                editor
 7731                    .update_in(cx, |editor, window, cx| {
 7732                        editor.go_to_singleton_buffer_point(target, window, cx);
 7733                    })
 7734                    .ok();
 7735                anyhow::Ok(())
 7736            })
 7737        })
 7738    }
 7739
 7740    pub fn has_active_edit_prediction(&self) -> bool {
 7741        self.active_edit_prediction.is_some()
 7742    }
 7743
 7744    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7745        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7746            return false;
 7747        };
 7748
 7749        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7750        self.clear_highlights::<EditPredictionHighlight>(cx);
 7751        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7752        true
 7753    }
 7754
 7755    /// Returns true when we're displaying the edit prediction popover below the cursor
 7756    /// like we are not previewing and the LSP autocomplete menu is visible
 7757    /// or we are in `when_holding_modifier` mode.
 7758    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7759        if self.edit_prediction_preview_is_active()
 7760            || !self.show_edit_predictions_in_menu()
 7761            || !self.edit_predictions_enabled()
 7762        {
 7763            return false;
 7764        }
 7765
 7766        if self.has_visible_completions_menu() {
 7767            return true;
 7768        }
 7769
 7770        has_completion && self.edit_prediction_requires_modifier()
 7771    }
 7772
 7773    fn handle_modifiers_changed(
 7774        &mut self,
 7775        modifiers: Modifiers,
 7776        position_map: &PositionMap,
 7777        window: &mut Window,
 7778        cx: &mut Context<Self>,
 7779    ) {
 7780        // Ensure that the edit prediction preview is updated, even when not
 7781        // enabled, if there's an active edit prediction preview.
 7782        if self.show_edit_predictions_in_menu()
 7783            || matches!(
 7784                self.edit_prediction_preview,
 7785                EditPredictionPreview::Active { .. }
 7786            )
 7787        {
 7788            self.update_edit_prediction_preview(&modifiers, window, cx);
 7789        }
 7790
 7791        self.update_selection_mode(&modifiers, position_map, window, cx);
 7792
 7793        let mouse_position = window.mouse_position();
 7794        if !position_map.text_hitbox.is_hovered(window) {
 7795            return;
 7796        }
 7797
 7798        self.update_hovered_link(
 7799            position_map.point_for_position(mouse_position),
 7800            &position_map.snapshot,
 7801            modifiers,
 7802            window,
 7803            cx,
 7804        )
 7805    }
 7806
 7807    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7808        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7809            MultiCursorModifier::Alt => modifiers.secondary(),
 7810            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7811        }
 7812    }
 7813
 7814    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7815        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7816            MultiCursorModifier::Alt => modifiers.alt,
 7817            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7818        }
 7819    }
 7820
 7821    fn columnar_selection_mode(
 7822        modifiers: &Modifiers,
 7823        cx: &mut Context<Self>,
 7824    ) -> Option<ColumnarMode> {
 7825        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7826            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7827                Some(ColumnarMode::FromMouse)
 7828            } else if Self::is_alt_pressed(modifiers, cx) {
 7829                Some(ColumnarMode::FromSelection)
 7830            } else {
 7831                None
 7832            }
 7833        } else {
 7834            None
 7835        }
 7836    }
 7837
 7838    fn update_selection_mode(
 7839        &mut self,
 7840        modifiers: &Modifiers,
 7841        position_map: &PositionMap,
 7842        window: &mut Window,
 7843        cx: &mut Context<Self>,
 7844    ) {
 7845        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7846            return;
 7847        };
 7848        if self.selections.pending_anchor().is_none() {
 7849            return;
 7850        }
 7851
 7852        let mouse_position = window.mouse_position();
 7853        let point_for_position = position_map.point_for_position(mouse_position);
 7854        let position = point_for_position.previous_valid;
 7855
 7856        self.select(
 7857            SelectPhase::BeginColumnar {
 7858                position,
 7859                reset: false,
 7860                mode,
 7861                goal_column: point_for_position.exact_unclipped.column(),
 7862            },
 7863            window,
 7864            cx,
 7865        );
 7866    }
 7867
 7868    fn update_edit_prediction_preview(
 7869        &mut self,
 7870        modifiers: &Modifiers,
 7871        window: &mut Window,
 7872        cx: &mut Context<Self>,
 7873    ) {
 7874        let mut modifiers_held = false;
 7875        if let Some(accept_keystroke) = self
 7876            .accept_edit_prediction_keybind(false, window, cx)
 7877            .keystroke()
 7878        {
 7879            modifiers_held = modifiers_held
 7880                || (accept_keystroke.modifiers() == modifiers
 7881                    && accept_keystroke.modifiers().modified());
 7882        };
 7883        if let Some(accept_partial_keystroke) = self
 7884            .accept_edit_prediction_keybind(true, window, cx)
 7885            .keystroke()
 7886        {
 7887            modifiers_held = modifiers_held
 7888                || (accept_partial_keystroke.modifiers() == modifiers
 7889                    && accept_partial_keystroke.modifiers().modified());
 7890        }
 7891
 7892        if modifiers_held {
 7893            if matches!(
 7894                self.edit_prediction_preview,
 7895                EditPredictionPreview::Inactive { .. }
 7896            ) {
 7897                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7898                    provider.provider.did_show(cx)
 7899                }
 7900
 7901                self.edit_prediction_preview = EditPredictionPreview::Active {
 7902                    previous_scroll_position: None,
 7903                    since: Instant::now(),
 7904                };
 7905
 7906                self.update_visible_edit_prediction(window, cx);
 7907                cx.notify();
 7908            }
 7909        } else if let EditPredictionPreview::Active {
 7910            previous_scroll_position,
 7911            since,
 7912        } = self.edit_prediction_preview
 7913        {
 7914            if let (Some(previous_scroll_position), Some(position_map)) =
 7915                (previous_scroll_position, self.last_position_map.as_ref())
 7916            {
 7917                self.set_scroll_position(
 7918                    previous_scroll_position
 7919                        .scroll_position(&position_map.snapshot.display_snapshot),
 7920                    window,
 7921                    cx,
 7922                );
 7923            }
 7924
 7925            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7926                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7927            };
 7928            self.clear_row_highlights::<EditPredictionPreview>();
 7929            self.update_visible_edit_prediction(window, cx);
 7930            cx.notify();
 7931        }
 7932    }
 7933
 7934    fn update_visible_edit_prediction(
 7935        &mut self,
 7936        _window: &mut Window,
 7937        cx: &mut Context<Self>,
 7938    ) -> Option<()> {
 7939        if DisableAiSettings::get_global(cx).disable_ai {
 7940            return None;
 7941        }
 7942
 7943        if self.ime_transaction.is_some() {
 7944            self.discard_edit_prediction(false, cx);
 7945            return None;
 7946        }
 7947
 7948        let selection = self.selections.newest_anchor();
 7949        let cursor = selection.head();
 7950        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7951        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7952        let excerpt_id = cursor.excerpt_id;
 7953
 7954        let show_in_menu = self.show_edit_predictions_in_menu();
 7955        let completions_menu_has_precedence = !show_in_menu
 7956            && (self.context_menu.borrow().is_some()
 7957                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7958
 7959        if completions_menu_has_precedence
 7960            || !offset_selection.is_empty()
 7961            || self
 7962                .active_edit_prediction
 7963                .as_ref()
 7964                .is_some_and(|completion| {
 7965                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7966                        return false;
 7967                    };
 7968                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7969                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7970                    !invalidation_range.contains(&offset_selection.head())
 7971                })
 7972        {
 7973            self.discard_edit_prediction(false, cx);
 7974            return None;
 7975        }
 7976
 7977        self.take_active_edit_prediction(cx);
 7978        let Some(provider) = self.edit_prediction_provider() else {
 7979            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7980            return None;
 7981        };
 7982
 7983        let (buffer, cursor_buffer_position) =
 7984            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7985
 7986        self.edit_prediction_settings =
 7987            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7988
 7989        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7990
 7991        if self.edit_prediction_indent_conflict {
 7992            let cursor_point = cursor.to_point(&multibuffer);
 7993
 7994            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7995
 7996            if let Some((_, indent)) = indents.iter().next()
 7997                && indent.len == cursor_point.column
 7998            {
 7999                self.edit_prediction_indent_conflict = false;
 8000            }
 8001        }
 8002
 8003        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8004
 8005        let (completion_id, edits, edit_preview) = match edit_prediction {
 8006            edit_prediction::EditPrediction::Local {
 8007                id,
 8008                edits,
 8009                edit_preview,
 8010            } => (id, edits, edit_preview),
 8011            edit_prediction::EditPrediction::Jump {
 8012                id,
 8013                snapshot,
 8014                target,
 8015            } => {
 8016                self.stale_edit_prediction_in_menu = None;
 8017                self.active_edit_prediction = Some(EditPredictionState {
 8018                    inlay_ids: vec![],
 8019                    completion: EditPrediction::MoveOutside { snapshot, target },
 8020                    completion_id: id,
 8021                    invalidation_range: None,
 8022                });
 8023                cx.notify();
 8024                return Some(());
 8025            }
 8026        };
 8027
 8028        let edits = edits
 8029            .into_iter()
 8030            .flat_map(|(range, new_text)| {
 8031                Some((
 8032                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8033                    new_text,
 8034                ))
 8035            })
 8036            .collect::<Vec<_>>();
 8037        if edits.is_empty() {
 8038            return None;
 8039        }
 8040
 8041        let first_edit_start = edits.first().unwrap().0.start;
 8042        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8043        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8044
 8045        let last_edit_end = edits.last().unwrap().0.end;
 8046        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8047        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8048
 8049        let cursor_row = cursor.to_point(&multibuffer).row;
 8050
 8051        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8052
 8053        let mut inlay_ids = Vec::new();
 8054        let invalidation_row_range;
 8055        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8056            Some(cursor_row..edit_end_row)
 8057        } else if cursor_row > edit_end_row {
 8058            Some(edit_start_row..cursor_row)
 8059        } else {
 8060            None
 8061        };
 8062        let supports_jump = self
 8063            .edit_prediction_provider
 8064            .as_ref()
 8065            .map(|provider| provider.provider.supports_jump_to_edit())
 8066            .unwrap_or(true);
 8067
 8068        let is_move = supports_jump
 8069            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8070        let completion = if is_move {
 8071            invalidation_row_range =
 8072                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8073            let target = first_edit_start;
 8074            EditPrediction::MoveWithin { target, snapshot }
 8075        } else {
 8076            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8077                && !self.edit_predictions_hidden_for_vim_mode;
 8078
 8079            if show_completions_in_buffer {
 8080                if let Some(provider) = &self.edit_prediction_provider {
 8081                    provider.provider.did_show(cx);
 8082                }
 8083                if edits
 8084                    .iter()
 8085                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8086                {
 8087                    let mut inlays = Vec::new();
 8088                    for (range, new_text) in &edits {
 8089                        let inlay = Inlay::edit_prediction(
 8090                            post_inc(&mut self.next_inlay_id),
 8091                            range.start,
 8092                            new_text.as_ref(),
 8093                        );
 8094                        inlay_ids.push(inlay.id);
 8095                        inlays.push(inlay);
 8096                    }
 8097
 8098                    self.splice_inlays(&[], inlays, cx);
 8099                } else {
 8100                    let background_color = cx.theme().status().deleted_background;
 8101                    self.highlight_text::<EditPredictionHighlight>(
 8102                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8103                        HighlightStyle {
 8104                            background_color: Some(background_color),
 8105                            ..Default::default()
 8106                        },
 8107                        cx,
 8108                    );
 8109                }
 8110            }
 8111
 8112            invalidation_row_range = edit_start_row..edit_end_row;
 8113
 8114            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8115                if provider.show_tab_accept_marker() {
 8116                    EditDisplayMode::TabAccept
 8117                } else {
 8118                    EditDisplayMode::Inline
 8119                }
 8120            } else {
 8121                EditDisplayMode::DiffPopover
 8122            };
 8123
 8124            EditPrediction::Edit {
 8125                edits,
 8126                edit_preview,
 8127                display_mode,
 8128                snapshot,
 8129            }
 8130        };
 8131
 8132        let invalidation_range = multibuffer
 8133            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8134            ..multibuffer.anchor_after(Point::new(
 8135                invalidation_row_range.end,
 8136                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8137            ));
 8138
 8139        self.stale_edit_prediction_in_menu = None;
 8140        self.active_edit_prediction = Some(EditPredictionState {
 8141            inlay_ids,
 8142            completion,
 8143            completion_id,
 8144            invalidation_range: Some(invalidation_range),
 8145        });
 8146
 8147        cx.notify();
 8148
 8149        Some(())
 8150    }
 8151
 8152    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8153        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8154    }
 8155
 8156    fn clear_tasks(&mut self) {
 8157        self.tasks.clear()
 8158    }
 8159
 8160    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8161        if self.tasks.insert(key, value).is_some() {
 8162            // This case should hopefully be rare, but just in case...
 8163            log::error!(
 8164                "multiple different run targets found on a single line, only the last target will be rendered"
 8165            )
 8166        }
 8167    }
 8168
 8169    /// Get all display points of breakpoints that will be rendered within editor
 8170    ///
 8171    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8172    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8173    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8174    fn active_breakpoints(
 8175        &self,
 8176        range: Range<DisplayRow>,
 8177        window: &mut Window,
 8178        cx: &mut Context<Self>,
 8179    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8180        let mut breakpoint_display_points = HashMap::default();
 8181
 8182        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8183            return breakpoint_display_points;
 8184        };
 8185
 8186        let snapshot = self.snapshot(window, cx);
 8187
 8188        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8189        let Some(project) = self.project() else {
 8190            return breakpoint_display_points;
 8191        };
 8192
 8193        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8194            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8195
 8196        for (buffer_snapshot, range, excerpt_id) in
 8197            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8198        {
 8199            let Some(buffer) = project
 8200                .read(cx)
 8201                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8202            else {
 8203                continue;
 8204            };
 8205            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8206                &buffer,
 8207                Some(
 8208                    buffer_snapshot.anchor_before(range.start)
 8209                        ..buffer_snapshot.anchor_after(range.end),
 8210                ),
 8211                buffer_snapshot,
 8212                cx,
 8213            );
 8214            for (breakpoint, state) in breakpoints {
 8215                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8216                let position = multi_buffer_anchor
 8217                    .to_point(&multi_buffer_snapshot)
 8218                    .to_display_point(&snapshot);
 8219
 8220                breakpoint_display_points.insert(
 8221                    position.row(),
 8222                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8223                );
 8224            }
 8225        }
 8226
 8227        breakpoint_display_points
 8228    }
 8229
 8230    fn breakpoint_context_menu(
 8231        &self,
 8232        anchor: Anchor,
 8233        window: &mut Window,
 8234        cx: &mut Context<Self>,
 8235    ) -> Entity<ui::ContextMenu> {
 8236        let weak_editor = cx.weak_entity();
 8237        let focus_handle = self.focus_handle(cx);
 8238
 8239        let row = self
 8240            .buffer
 8241            .read(cx)
 8242            .snapshot(cx)
 8243            .summary_for_anchor::<Point>(&anchor)
 8244            .row;
 8245
 8246        let breakpoint = self
 8247            .breakpoint_at_row(row, window, cx)
 8248            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8249
 8250        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8251            "Edit Log Breakpoint"
 8252        } else {
 8253            "Set Log Breakpoint"
 8254        };
 8255
 8256        let condition_breakpoint_msg = if breakpoint
 8257            .as_ref()
 8258            .is_some_and(|bp| bp.1.condition.is_some())
 8259        {
 8260            "Edit Condition Breakpoint"
 8261        } else {
 8262            "Set Condition Breakpoint"
 8263        };
 8264
 8265        let hit_condition_breakpoint_msg = if breakpoint
 8266            .as_ref()
 8267            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8268        {
 8269            "Edit Hit Condition Breakpoint"
 8270        } else {
 8271            "Set Hit Condition Breakpoint"
 8272        };
 8273
 8274        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8275            "Unset Breakpoint"
 8276        } else {
 8277            "Set Breakpoint"
 8278        };
 8279
 8280        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8281
 8282        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8283            BreakpointState::Enabled => Some("Disable"),
 8284            BreakpointState::Disabled => Some("Enable"),
 8285        });
 8286
 8287        let (anchor, breakpoint) =
 8288            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8289
 8290        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8291            menu.on_blur_subscription(Subscription::new(|| {}))
 8292                .context(focus_handle)
 8293                .when(run_to_cursor, |this| {
 8294                    let weak_editor = weak_editor.clone();
 8295                    this.entry("Run to cursor", None, move |window, cx| {
 8296                        weak_editor
 8297                            .update(cx, |editor, cx| {
 8298                                editor.change_selections(
 8299                                    SelectionEffects::no_scroll(),
 8300                                    window,
 8301                                    cx,
 8302                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8303                                );
 8304                            })
 8305                            .ok();
 8306
 8307                        window.dispatch_action(Box::new(RunToCursor), cx);
 8308                    })
 8309                    .separator()
 8310                })
 8311                .when_some(toggle_state_msg, |this, msg| {
 8312                    this.entry(msg, None, {
 8313                        let weak_editor = weak_editor.clone();
 8314                        let breakpoint = breakpoint.clone();
 8315                        move |_window, cx| {
 8316                            weak_editor
 8317                                .update(cx, |this, cx| {
 8318                                    this.edit_breakpoint_at_anchor(
 8319                                        anchor,
 8320                                        breakpoint.as_ref().clone(),
 8321                                        BreakpointEditAction::InvertState,
 8322                                        cx,
 8323                                    );
 8324                                })
 8325                                .log_err();
 8326                        }
 8327                    })
 8328                })
 8329                .entry(set_breakpoint_msg, None, {
 8330                    let weak_editor = weak_editor.clone();
 8331                    let breakpoint = breakpoint.clone();
 8332                    move |_window, cx| {
 8333                        weak_editor
 8334                            .update(cx, |this, cx| {
 8335                                this.edit_breakpoint_at_anchor(
 8336                                    anchor,
 8337                                    breakpoint.as_ref().clone(),
 8338                                    BreakpointEditAction::Toggle,
 8339                                    cx,
 8340                                );
 8341                            })
 8342                            .log_err();
 8343                    }
 8344                })
 8345                .entry(log_breakpoint_msg, None, {
 8346                    let breakpoint = breakpoint.clone();
 8347                    let weak_editor = weak_editor.clone();
 8348                    move |window, cx| {
 8349                        weak_editor
 8350                            .update(cx, |this, cx| {
 8351                                this.add_edit_breakpoint_block(
 8352                                    anchor,
 8353                                    breakpoint.as_ref(),
 8354                                    BreakpointPromptEditAction::Log,
 8355                                    window,
 8356                                    cx,
 8357                                );
 8358                            })
 8359                            .log_err();
 8360                    }
 8361                })
 8362                .entry(condition_breakpoint_msg, None, {
 8363                    let breakpoint = breakpoint.clone();
 8364                    let weak_editor = weak_editor.clone();
 8365                    move |window, cx| {
 8366                        weak_editor
 8367                            .update(cx, |this, cx| {
 8368                                this.add_edit_breakpoint_block(
 8369                                    anchor,
 8370                                    breakpoint.as_ref(),
 8371                                    BreakpointPromptEditAction::Condition,
 8372                                    window,
 8373                                    cx,
 8374                                );
 8375                            })
 8376                            .log_err();
 8377                    }
 8378                })
 8379                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8380                    weak_editor
 8381                        .update(cx, |this, cx| {
 8382                            this.add_edit_breakpoint_block(
 8383                                anchor,
 8384                                breakpoint.as_ref(),
 8385                                BreakpointPromptEditAction::HitCondition,
 8386                                window,
 8387                                cx,
 8388                            );
 8389                        })
 8390                        .log_err();
 8391                })
 8392        })
 8393    }
 8394
 8395    fn render_breakpoint(
 8396        &self,
 8397        position: Anchor,
 8398        row: DisplayRow,
 8399        breakpoint: &Breakpoint,
 8400        state: Option<BreakpointSessionState>,
 8401        cx: &mut Context<Self>,
 8402    ) -> IconButton {
 8403        let is_rejected = state.is_some_and(|s| !s.verified);
 8404        // Is it a breakpoint that shows up when hovering over gutter?
 8405        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8406            (false, false),
 8407            |PhantomBreakpointIndicator {
 8408                 is_active,
 8409                 display_row,
 8410                 collides_with_existing_breakpoint,
 8411             }| {
 8412                (
 8413                    is_active && display_row == row,
 8414                    collides_with_existing_breakpoint,
 8415                )
 8416            },
 8417        );
 8418
 8419        let (color, icon) = {
 8420            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8421                (false, false) => ui::IconName::DebugBreakpoint,
 8422                (true, false) => ui::IconName::DebugLogBreakpoint,
 8423                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8424                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8425            };
 8426
 8427            let color = cx.theme().colors();
 8428
 8429            let color = if is_phantom {
 8430                if collides_with_existing {
 8431                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8432                } else {
 8433                    Color::Hint
 8434                }
 8435            } else if is_rejected {
 8436                Color::Disabled
 8437            } else {
 8438                Color::Debugger
 8439            };
 8440
 8441            (color, icon)
 8442        };
 8443
 8444        let breakpoint = Arc::from(breakpoint.clone());
 8445
 8446        let alt_as_text = gpui::Keystroke {
 8447            modifiers: Modifiers::secondary_key(),
 8448            ..Default::default()
 8449        };
 8450        let primary_action_text = if breakpoint.is_disabled() {
 8451            "Enable breakpoint"
 8452        } else if is_phantom && !collides_with_existing {
 8453            "Set breakpoint"
 8454        } else {
 8455            "Unset breakpoint"
 8456        };
 8457        let focus_handle = self.focus_handle.clone();
 8458
 8459        let meta = if is_rejected {
 8460            SharedString::from("No executable code is associated with this line.")
 8461        } else if collides_with_existing && !breakpoint.is_disabled() {
 8462            SharedString::from(format!(
 8463                "{alt_as_text}-click to disable,\nright-click for more options."
 8464            ))
 8465        } else {
 8466            SharedString::from("Right-click for more options.")
 8467        };
 8468        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8469            .icon_size(IconSize::XSmall)
 8470            .size(ui::ButtonSize::None)
 8471            .when(is_rejected, |this| {
 8472                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8473            })
 8474            .icon_color(color)
 8475            .style(ButtonStyle::Transparent)
 8476            .on_click(cx.listener({
 8477                move |editor, event: &ClickEvent, window, cx| {
 8478                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8479                        BreakpointEditAction::InvertState
 8480                    } else {
 8481                        BreakpointEditAction::Toggle
 8482                    };
 8483
 8484                    window.focus(&editor.focus_handle(cx));
 8485                    editor.edit_breakpoint_at_anchor(
 8486                        position,
 8487                        breakpoint.as_ref().clone(),
 8488                        edit_action,
 8489                        cx,
 8490                    );
 8491                }
 8492            }))
 8493            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8494                editor.set_breakpoint_context_menu(
 8495                    row,
 8496                    Some(position),
 8497                    event.position(),
 8498                    window,
 8499                    cx,
 8500                );
 8501            }))
 8502            .tooltip(move |_window, cx| {
 8503                Tooltip::with_meta_in(
 8504                    primary_action_text,
 8505                    Some(&ToggleBreakpoint),
 8506                    meta.clone(),
 8507                    &focus_handle,
 8508                    cx,
 8509                )
 8510            })
 8511    }
 8512
 8513    fn build_tasks_context(
 8514        project: &Entity<Project>,
 8515        buffer: &Entity<Buffer>,
 8516        buffer_row: u32,
 8517        tasks: &Arc<RunnableTasks>,
 8518        cx: &mut Context<Self>,
 8519    ) -> Task<Option<task::TaskContext>> {
 8520        let position = Point::new(buffer_row, tasks.column);
 8521        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8522        let location = Location {
 8523            buffer: buffer.clone(),
 8524            range: range_start..range_start,
 8525        };
 8526        // Fill in the environmental variables from the tree-sitter captures
 8527        let mut captured_task_variables = TaskVariables::default();
 8528        for (capture_name, value) in tasks.extra_variables.clone() {
 8529            captured_task_variables.insert(
 8530                task::VariableName::Custom(capture_name.into()),
 8531                value.clone(),
 8532            );
 8533        }
 8534        project.update(cx, |project, cx| {
 8535            project.task_store().update(cx, |task_store, cx| {
 8536                task_store.task_context_for_location(captured_task_variables, location, cx)
 8537            })
 8538        })
 8539    }
 8540
 8541    pub fn spawn_nearest_task(
 8542        &mut self,
 8543        action: &SpawnNearestTask,
 8544        window: &mut Window,
 8545        cx: &mut Context<Self>,
 8546    ) {
 8547        let Some((workspace, _)) = self.workspace.clone() else {
 8548            return;
 8549        };
 8550        let Some(project) = self.project.clone() else {
 8551            return;
 8552        };
 8553
 8554        // Try to find a closest, enclosing node using tree-sitter that has a task
 8555        let Some((buffer, buffer_row, tasks)) = self
 8556            .find_enclosing_node_task(cx)
 8557            // Or find the task that's closest in row-distance.
 8558            .or_else(|| self.find_closest_task(cx))
 8559        else {
 8560            return;
 8561        };
 8562
 8563        let reveal_strategy = action.reveal;
 8564        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8565        cx.spawn_in(window, async move |_, cx| {
 8566            let context = task_context.await?;
 8567            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8568
 8569            let resolved = &mut resolved_task.resolved;
 8570            resolved.reveal = reveal_strategy;
 8571
 8572            workspace
 8573                .update_in(cx, |workspace, window, cx| {
 8574                    workspace.schedule_resolved_task(
 8575                        task_source_kind,
 8576                        resolved_task,
 8577                        false,
 8578                        window,
 8579                        cx,
 8580                    );
 8581                })
 8582                .ok()
 8583        })
 8584        .detach();
 8585    }
 8586
 8587    fn find_closest_task(
 8588        &mut self,
 8589        cx: &mut Context<Self>,
 8590    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8591        let cursor_row = self
 8592            .selections
 8593            .newest_adjusted(&self.display_snapshot(cx))
 8594            .head()
 8595            .row;
 8596
 8597        let ((buffer_id, row), tasks) = self
 8598            .tasks
 8599            .iter()
 8600            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8601
 8602        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8603        let tasks = Arc::new(tasks.to_owned());
 8604        Some((buffer, *row, tasks))
 8605    }
 8606
 8607    fn find_enclosing_node_task(
 8608        &mut self,
 8609        cx: &mut Context<Self>,
 8610    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8611        let snapshot = self.buffer.read(cx).snapshot(cx);
 8612        let offset = self
 8613            .selections
 8614            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8615            .head();
 8616        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8617        let offset = excerpt.map_offset_to_buffer(offset);
 8618        let buffer_id = excerpt.buffer().remote_id();
 8619
 8620        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8621        let mut cursor = layer.node().walk();
 8622
 8623        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8624            if cursor.node().end_byte() == offset.0 {
 8625                cursor.goto_next_sibling();
 8626            }
 8627        }
 8628
 8629        // Ascend to the smallest ancestor that contains the range and has a task.
 8630        loop {
 8631            let node = cursor.node();
 8632            let node_range = node.byte_range();
 8633            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8634
 8635            // Check if this node contains our offset
 8636            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8637                // If it contains offset, check for task
 8638                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8639                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8640                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8641                }
 8642            }
 8643
 8644            if !cursor.goto_parent() {
 8645                break;
 8646            }
 8647        }
 8648        None
 8649    }
 8650
 8651    fn render_run_indicator(
 8652        &self,
 8653        _style: &EditorStyle,
 8654        is_active: bool,
 8655        row: DisplayRow,
 8656        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8657        cx: &mut Context<Self>,
 8658    ) -> IconButton {
 8659        let color = Color::Muted;
 8660        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8661
 8662        IconButton::new(
 8663            ("run_indicator", row.0 as usize),
 8664            ui::IconName::PlayOutlined,
 8665        )
 8666        .shape(ui::IconButtonShape::Square)
 8667        .icon_size(IconSize::XSmall)
 8668        .icon_color(color)
 8669        .toggle_state(is_active)
 8670        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8671            let quick_launch = match e {
 8672                ClickEvent::Keyboard(_) => true,
 8673                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8674            };
 8675
 8676            window.focus(&editor.focus_handle(cx));
 8677            editor.toggle_code_actions(
 8678                &ToggleCodeActions {
 8679                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8680                    quick_launch,
 8681                },
 8682                window,
 8683                cx,
 8684            );
 8685        }))
 8686        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8687            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8688        }))
 8689    }
 8690
 8691    pub fn context_menu_visible(&self) -> bool {
 8692        !self.edit_prediction_preview_is_active()
 8693            && self
 8694                .context_menu
 8695                .borrow()
 8696                .as_ref()
 8697                .is_some_and(|menu| menu.visible())
 8698    }
 8699
 8700    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8701        self.context_menu
 8702            .borrow()
 8703            .as_ref()
 8704            .map(|menu| menu.origin())
 8705    }
 8706
 8707    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8708        self.context_menu_options = Some(options);
 8709    }
 8710
 8711    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8712    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8713
 8714    fn render_edit_prediction_popover(
 8715        &mut self,
 8716        text_bounds: &Bounds<Pixels>,
 8717        content_origin: gpui::Point<Pixels>,
 8718        right_margin: Pixels,
 8719        editor_snapshot: &EditorSnapshot,
 8720        visible_row_range: Range<DisplayRow>,
 8721        scroll_top: ScrollOffset,
 8722        scroll_bottom: ScrollOffset,
 8723        line_layouts: &[LineWithInvisibles],
 8724        line_height: Pixels,
 8725        scroll_position: gpui::Point<ScrollOffset>,
 8726        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8727        newest_selection_head: Option<DisplayPoint>,
 8728        editor_width: Pixels,
 8729        style: &EditorStyle,
 8730        window: &mut Window,
 8731        cx: &mut App,
 8732    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8733        if self.mode().is_minimap() {
 8734            return None;
 8735        }
 8736        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8737
 8738        if self.edit_prediction_visible_in_cursor_popover(true) {
 8739            return None;
 8740        }
 8741
 8742        match &active_edit_prediction.completion {
 8743            EditPrediction::MoveWithin { target, .. } => {
 8744                let target_display_point = target.to_display_point(editor_snapshot);
 8745
 8746                if self.edit_prediction_requires_modifier() {
 8747                    if !self.edit_prediction_preview_is_active() {
 8748                        return None;
 8749                    }
 8750
 8751                    self.render_edit_prediction_modifier_jump_popover(
 8752                        text_bounds,
 8753                        content_origin,
 8754                        visible_row_range,
 8755                        line_layouts,
 8756                        line_height,
 8757                        scroll_pixel_position,
 8758                        newest_selection_head,
 8759                        target_display_point,
 8760                        window,
 8761                        cx,
 8762                    )
 8763                } else {
 8764                    self.render_edit_prediction_eager_jump_popover(
 8765                        text_bounds,
 8766                        content_origin,
 8767                        editor_snapshot,
 8768                        visible_row_range,
 8769                        scroll_top,
 8770                        scroll_bottom,
 8771                        line_height,
 8772                        scroll_pixel_position,
 8773                        target_display_point,
 8774                        editor_width,
 8775                        window,
 8776                        cx,
 8777                    )
 8778                }
 8779            }
 8780            EditPrediction::Edit {
 8781                display_mode: EditDisplayMode::Inline,
 8782                ..
 8783            } => None,
 8784            EditPrediction::Edit {
 8785                display_mode: EditDisplayMode::TabAccept,
 8786                edits,
 8787                ..
 8788            } => {
 8789                let range = &edits.first()?.0;
 8790                let target_display_point = range.end.to_display_point(editor_snapshot);
 8791
 8792                self.render_edit_prediction_end_of_line_popover(
 8793                    "Accept",
 8794                    editor_snapshot,
 8795                    visible_row_range,
 8796                    target_display_point,
 8797                    line_height,
 8798                    scroll_pixel_position,
 8799                    content_origin,
 8800                    editor_width,
 8801                    window,
 8802                    cx,
 8803                )
 8804            }
 8805            EditPrediction::Edit {
 8806                edits,
 8807                edit_preview,
 8808                display_mode: EditDisplayMode::DiffPopover,
 8809                snapshot,
 8810            } => self.render_edit_prediction_diff_popover(
 8811                text_bounds,
 8812                content_origin,
 8813                right_margin,
 8814                editor_snapshot,
 8815                visible_row_range,
 8816                line_layouts,
 8817                line_height,
 8818                scroll_position,
 8819                scroll_pixel_position,
 8820                newest_selection_head,
 8821                editor_width,
 8822                style,
 8823                edits,
 8824                edit_preview,
 8825                snapshot,
 8826                window,
 8827                cx,
 8828            ),
 8829            EditPrediction::MoveOutside { snapshot, .. } => {
 8830                let mut element = self
 8831                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8832                    .into_any();
 8833
 8834                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8835                let origin_x = text_bounds.size.width - size.width - px(30.);
 8836                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8837                element.prepaint_at(origin, window, cx);
 8838
 8839                Some((element, origin))
 8840            }
 8841        }
 8842    }
 8843
 8844    fn render_edit_prediction_modifier_jump_popover(
 8845        &mut self,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        visible_row_range: Range<DisplayRow>,
 8849        line_layouts: &[LineWithInvisibles],
 8850        line_height: Pixels,
 8851        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8852        newest_selection_head: Option<DisplayPoint>,
 8853        target_display_point: DisplayPoint,
 8854        window: &mut Window,
 8855        cx: &mut App,
 8856    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8857        let scrolled_content_origin =
 8858            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8859
 8860        const SCROLL_PADDING_Y: Pixels = px(12.);
 8861
 8862        if target_display_point.row() < visible_row_range.start {
 8863            return self.render_edit_prediction_scroll_popover(
 8864                |_| SCROLL_PADDING_Y,
 8865                IconName::ArrowUp,
 8866                visible_row_range,
 8867                line_layouts,
 8868                newest_selection_head,
 8869                scrolled_content_origin,
 8870                window,
 8871                cx,
 8872            );
 8873        } else if target_display_point.row() >= visible_row_range.end {
 8874            return self.render_edit_prediction_scroll_popover(
 8875                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8876                IconName::ArrowDown,
 8877                visible_row_range,
 8878                line_layouts,
 8879                newest_selection_head,
 8880                scrolled_content_origin,
 8881                window,
 8882                cx,
 8883            );
 8884        }
 8885
 8886        const POLE_WIDTH: Pixels = px(2.);
 8887
 8888        let line_layout =
 8889            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8890        let target_column = target_display_point.column() as usize;
 8891
 8892        let target_x = line_layout.x_for_index(target_column);
 8893        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8894            - scroll_pixel_position.y;
 8895
 8896        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8897
 8898        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8899        border_color.l += 0.001;
 8900
 8901        let mut element = v_flex()
 8902            .items_end()
 8903            .when(flag_on_right, |el| el.items_start())
 8904            .child(if flag_on_right {
 8905                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8906                    .rounded_bl(px(0.))
 8907                    .rounded_tl(px(0.))
 8908                    .border_l_2()
 8909                    .border_color(border_color)
 8910            } else {
 8911                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8912                    .rounded_br(px(0.))
 8913                    .rounded_tr(px(0.))
 8914                    .border_r_2()
 8915                    .border_color(border_color)
 8916            })
 8917            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8918            .into_any();
 8919
 8920        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8921
 8922        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8923            - point(
 8924                if flag_on_right {
 8925                    POLE_WIDTH
 8926                } else {
 8927                    size.width - POLE_WIDTH
 8928                },
 8929                size.height - line_height,
 8930            );
 8931
 8932        origin.x = origin.x.max(content_origin.x);
 8933
 8934        element.prepaint_at(origin, window, cx);
 8935
 8936        Some((element, origin))
 8937    }
 8938
 8939    fn render_edit_prediction_scroll_popover(
 8940        &mut self,
 8941        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8942        scroll_icon: IconName,
 8943        visible_row_range: Range<DisplayRow>,
 8944        line_layouts: &[LineWithInvisibles],
 8945        newest_selection_head: Option<DisplayPoint>,
 8946        scrolled_content_origin: gpui::Point<Pixels>,
 8947        window: &mut Window,
 8948        cx: &mut App,
 8949    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8950        let mut element = self
 8951            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8952            .into_any();
 8953
 8954        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8955
 8956        let cursor = newest_selection_head?;
 8957        let cursor_row_layout =
 8958            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8959        let cursor_column = cursor.column() as usize;
 8960
 8961        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8962
 8963        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8964
 8965        element.prepaint_at(origin, window, cx);
 8966        Some((element, origin))
 8967    }
 8968
 8969    fn render_edit_prediction_eager_jump_popover(
 8970        &mut self,
 8971        text_bounds: &Bounds<Pixels>,
 8972        content_origin: gpui::Point<Pixels>,
 8973        editor_snapshot: &EditorSnapshot,
 8974        visible_row_range: Range<DisplayRow>,
 8975        scroll_top: ScrollOffset,
 8976        scroll_bottom: ScrollOffset,
 8977        line_height: Pixels,
 8978        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8979        target_display_point: DisplayPoint,
 8980        editor_width: Pixels,
 8981        window: &mut Window,
 8982        cx: &mut App,
 8983    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8984        if target_display_point.row().as_f64() < scroll_top {
 8985            let mut element = self
 8986                .render_edit_prediction_line_popover(
 8987                    "Jump to Edit",
 8988                    Some(IconName::ArrowUp),
 8989                    window,
 8990                    cx,
 8991                )
 8992                .into_any();
 8993
 8994            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8995            let offset = point(
 8996                (text_bounds.size.width - size.width) / 2.,
 8997                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8998            );
 8999
 9000            let origin = text_bounds.origin + offset;
 9001            element.prepaint_at(origin, window, cx);
 9002            Some((element, origin))
 9003        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9004            let mut element = self
 9005                .render_edit_prediction_line_popover(
 9006                    "Jump to Edit",
 9007                    Some(IconName::ArrowDown),
 9008                    window,
 9009                    cx,
 9010                )
 9011                .into_any();
 9012
 9013            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014            let offset = point(
 9015                (text_bounds.size.width - size.width) / 2.,
 9016                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9017            );
 9018
 9019            let origin = text_bounds.origin + offset;
 9020            element.prepaint_at(origin, window, cx);
 9021            Some((element, origin))
 9022        } else {
 9023            self.render_edit_prediction_end_of_line_popover(
 9024                "Jump to Edit",
 9025                editor_snapshot,
 9026                visible_row_range,
 9027                target_display_point,
 9028                line_height,
 9029                scroll_pixel_position,
 9030                content_origin,
 9031                editor_width,
 9032                window,
 9033                cx,
 9034            )
 9035        }
 9036    }
 9037
 9038    fn render_edit_prediction_end_of_line_popover(
 9039        self: &mut Editor,
 9040        label: &'static str,
 9041        editor_snapshot: &EditorSnapshot,
 9042        visible_row_range: Range<DisplayRow>,
 9043        target_display_point: DisplayPoint,
 9044        line_height: Pixels,
 9045        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9046        content_origin: gpui::Point<Pixels>,
 9047        editor_width: Pixels,
 9048        window: &mut Window,
 9049        cx: &mut App,
 9050    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9051        let target_line_end = DisplayPoint::new(
 9052            target_display_point.row(),
 9053            editor_snapshot.line_len(target_display_point.row()),
 9054        );
 9055
 9056        let mut element = self
 9057            .render_edit_prediction_line_popover(label, None, window, cx)
 9058            .into_any();
 9059
 9060        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9061
 9062        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9063
 9064        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9065        let mut origin = start_point
 9066            + line_origin
 9067            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9068        origin.x = origin.x.max(content_origin.x);
 9069
 9070        let max_x = content_origin.x + editor_width - size.width;
 9071
 9072        if origin.x > max_x {
 9073            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9074
 9075            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9076                origin.y += offset;
 9077                IconName::ArrowUp
 9078            } else {
 9079                origin.y -= offset;
 9080                IconName::ArrowDown
 9081            };
 9082
 9083            element = self
 9084                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9085                .into_any();
 9086
 9087            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9088
 9089            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9090        }
 9091
 9092        element.prepaint_at(origin, window, cx);
 9093        Some((element, origin))
 9094    }
 9095
 9096    fn render_edit_prediction_diff_popover(
 9097        self: &Editor,
 9098        text_bounds: &Bounds<Pixels>,
 9099        content_origin: gpui::Point<Pixels>,
 9100        right_margin: Pixels,
 9101        editor_snapshot: &EditorSnapshot,
 9102        visible_row_range: Range<DisplayRow>,
 9103        line_layouts: &[LineWithInvisibles],
 9104        line_height: Pixels,
 9105        scroll_position: gpui::Point<ScrollOffset>,
 9106        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9107        newest_selection_head: Option<DisplayPoint>,
 9108        editor_width: Pixels,
 9109        style: &EditorStyle,
 9110        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9111        edit_preview: &Option<language::EditPreview>,
 9112        snapshot: &language::BufferSnapshot,
 9113        window: &mut Window,
 9114        cx: &mut App,
 9115    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9116        let edit_start = edits
 9117            .first()
 9118            .unwrap()
 9119            .0
 9120            .start
 9121            .to_display_point(editor_snapshot);
 9122        let edit_end = edits
 9123            .last()
 9124            .unwrap()
 9125            .0
 9126            .end
 9127            .to_display_point(editor_snapshot);
 9128
 9129        let is_visible = visible_row_range.contains(&edit_start.row())
 9130            || visible_row_range.contains(&edit_end.row());
 9131        if !is_visible {
 9132            return None;
 9133        }
 9134
 9135        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9136            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9137        } else {
 9138            // Fallback for providers without edit_preview
 9139            crate::edit_prediction_fallback_text(edits, cx)
 9140        };
 9141
 9142        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9143        let line_count = highlighted_edits.text.lines().count();
 9144
 9145        const BORDER_WIDTH: Pixels = px(1.);
 9146
 9147        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9148        let has_keybind = keybind.is_some();
 9149
 9150        let mut element = h_flex()
 9151            .items_start()
 9152            .child(
 9153                h_flex()
 9154                    .bg(cx.theme().colors().editor_background)
 9155                    .border(BORDER_WIDTH)
 9156                    .shadow_xs()
 9157                    .border_color(cx.theme().colors().border)
 9158                    .rounded_l_lg()
 9159                    .when(line_count > 1, |el| el.rounded_br_lg())
 9160                    .pr_1()
 9161                    .child(styled_text),
 9162            )
 9163            .child(
 9164                h_flex()
 9165                    .h(line_height + BORDER_WIDTH * 2.)
 9166                    .px_1p5()
 9167                    .gap_1()
 9168                    // Workaround: For some reason, there's a gap if we don't do this
 9169                    .ml(-BORDER_WIDTH)
 9170                    .shadow(vec![gpui::BoxShadow {
 9171                        color: gpui::black().opacity(0.05),
 9172                        offset: point(px(1.), px(1.)),
 9173                        blur_radius: px(2.),
 9174                        spread_radius: px(0.),
 9175                    }])
 9176                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9177                    .border(BORDER_WIDTH)
 9178                    .border_color(cx.theme().colors().border)
 9179                    .rounded_r_lg()
 9180                    .id("edit_prediction_diff_popover_keybind")
 9181                    .when(!has_keybind, |el| {
 9182                        let status_colors = cx.theme().status();
 9183
 9184                        el.bg(status_colors.error_background)
 9185                            .border_color(status_colors.error.opacity(0.6))
 9186                            .child(Icon::new(IconName::Info).color(Color::Error))
 9187                            .cursor_default()
 9188                            .hoverable_tooltip(move |_window, cx| {
 9189                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9190                            })
 9191                    })
 9192                    .children(keybind),
 9193            )
 9194            .into_any();
 9195
 9196        let longest_row =
 9197            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9198        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9199            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9200        } else {
 9201            layout_line(
 9202                longest_row,
 9203                editor_snapshot,
 9204                style,
 9205                editor_width,
 9206                |_| false,
 9207                window,
 9208                cx,
 9209            )
 9210            .width
 9211        };
 9212
 9213        let viewport_bounds =
 9214            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9215                right: -right_margin,
 9216                ..Default::default()
 9217            });
 9218
 9219        let x_after_longest = Pixels::from(
 9220            ScrollPixelOffset::from(
 9221                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9222            ) - scroll_pixel_position.x,
 9223        );
 9224
 9225        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9226
 9227        // Fully visible if it can be displayed within the window (allow overlapping other
 9228        // panes). However, this is only allowed if the popover starts within text_bounds.
 9229        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9230            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9231
 9232        let mut origin = if can_position_to_the_right {
 9233            point(
 9234                x_after_longest,
 9235                text_bounds.origin.y
 9236                    + Pixels::from(
 9237                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9238                            - scroll_pixel_position.y,
 9239                    ),
 9240            )
 9241        } else {
 9242            let cursor_row = newest_selection_head.map(|head| head.row());
 9243            let above_edit = edit_start
 9244                .row()
 9245                .0
 9246                .checked_sub(line_count as u32)
 9247                .map(DisplayRow);
 9248            let below_edit = Some(edit_end.row() + 1);
 9249            let above_cursor =
 9250                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9251            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9252
 9253            // Place the edit popover adjacent to the edit if there is a location
 9254            // available that is onscreen and does not obscure the cursor. Otherwise,
 9255            // place it adjacent to the cursor.
 9256            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9257                .into_iter()
 9258                .flatten()
 9259                .find(|&start_row| {
 9260                    let end_row = start_row + line_count as u32;
 9261                    visible_row_range.contains(&start_row)
 9262                        && visible_row_range.contains(&end_row)
 9263                        && cursor_row
 9264                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9265                })?;
 9266
 9267            content_origin
 9268                + point(
 9269                    Pixels::from(-scroll_pixel_position.x),
 9270                    Pixels::from(
 9271                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9272                    ),
 9273                )
 9274        };
 9275
 9276        origin.x -= BORDER_WIDTH;
 9277
 9278        window.defer_draw(element, origin, 1);
 9279
 9280        // Do not return an element, since it will already be drawn due to defer_draw.
 9281        None
 9282    }
 9283
 9284    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9285        px(30.)
 9286    }
 9287
 9288    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9289        if self.read_only(cx) {
 9290            cx.theme().players().read_only()
 9291        } else {
 9292            self.style.as_ref().unwrap().local_player
 9293        }
 9294    }
 9295
 9296    fn render_edit_prediction_accept_keybind(
 9297        &self,
 9298        window: &mut Window,
 9299        cx: &mut App,
 9300    ) -> Option<AnyElement> {
 9301        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9302        let accept_keystroke = accept_binding.keystroke()?;
 9303
 9304        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9305
 9306        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9307            Color::Accent
 9308        } else {
 9309            Color::Muted
 9310        };
 9311
 9312        h_flex()
 9313            .px_0p5()
 9314            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9315            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9316            .text_size(TextSize::XSmall.rems(cx))
 9317            .child(h_flex().children(ui::render_modifiers(
 9318                accept_keystroke.modifiers(),
 9319                PlatformStyle::platform(),
 9320                Some(modifiers_color),
 9321                Some(IconSize::XSmall.rems().into()),
 9322                true,
 9323            )))
 9324            .when(is_platform_style_mac, |parent| {
 9325                parent.child(accept_keystroke.key().to_string())
 9326            })
 9327            .when(!is_platform_style_mac, |parent| {
 9328                parent.child(
 9329                    Key::new(
 9330                        util::capitalize(accept_keystroke.key()),
 9331                        Some(Color::Default),
 9332                    )
 9333                    .size(Some(IconSize::XSmall.rems().into())),
 9334                )
 9335            })
 9336            .into_any()
 9337            .into()
 9338    }
 9339
 9340    fn render_edit_prediction_line_popover(
 9341        &self,
 9342        label: impl Into<SharedString>,
 9343        icon: Option<IconName>,
 9344        window: &mut Window,
 9345        cx: &mut App,
 9346    ) -> Stateful<Div> {
 9347        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9348
 9349        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9350        let has_keybind = keybind.is_some();
 9351
 9352        h_flex()
 9353            .id("ep-line-popover")
 9354            .py_0p5()
 9355            .pl_1()
 9356            .pr(padding_right)
 9357            .gap_1()
 9358            .rounded_md()
 9359            .border_1()
 9360            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9361            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9362            .shadow_xs()
 9363            .when(!has_keybind, |el| {
 9364                let status_colors = cx.theme().status();
 9365
 9366                el.bg(status_colors.error_background)
 9367                    .border_color(status_colors.error.opacity(0.6))
 9368                    .pl_2()
 9369                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9370                    .cursor_default()
 9371                    .hoverable_tooltip(move |_window, cx| {
 9372                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9373                    })
 9374            })
 9375            .children(keybind)
 9376            .child(
 9377                Label::new(label)
 9378                    .size(LabelSize::Small)
 9379                    .when(!has_keybind, |el| {
 9380                        el.color(cx.theme().status().error.into()).strikethrough()
 9381                    }),
 9382            )
 9383            .when(!has_keybind, |el| {
 9384                el.child(
 9385                    h_flex().ml_1().child(
 9386                        Icon::new(IconName::Info)
 9387                            .size(IconSize::Small)
 9388                            .color(cx.theme().status().error.into()),
 9389                    ),
 9390                )
 9391            })
 9392            .when_some(icon, |element, icon| {
 9393                element.child(
 9394                    div()
 9395                        .mt(px(1.5))
 9396                        .child(Icon::new(icon).size(IconSize::Small)),
 9397                )
 9398            })
 9399    }
 9400
 9401    fn render_edit_prediction_jump_outside_popover(
 9402        &self,
 9403        snapshot: &BufferSnapshot,
 9404        window: &mut Window,
 9405        cx: &mut App,
 9406    ) -> Stateful<Div> {
 9407        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9408        let has_keybind = keybind.is_some();
 9409
 9410        let file_name = snapshot
 9411            .file()
 9412            .map(|file| SharedString::new(file.file_name(cx)))
 9413            .unwrap_or(SharedString::new_static("untitled"));
 9414
 9415        h_flex()
 9416            .id("ep-jump-outside-popover")
 9417            .py_1()
 9418            .px_2()
 9419            .gap_1()
 9420            .rounded_md()
 9421            .border_1()
 9422            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9423            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9424            .shadow_xs()
 9425            .when(!has_keybind, |el| {
 9426                let status_colors = cx.theme().status();
 9427
 9428                el.bg(status_colors.error_background)
 9429                    .border_color(status_colors.error.opacity(0.6))
 9430                    .pl_2()
 9431                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9432                    .cursor_default()
 9433                    .hoverable_tooltip(move |_window, cx| {
 9434                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9435                    })
 9436            })
 9437            .children(keybind)
 9438            .child(
 9439                Label::new(file_name)
 9440                    .size(LabelSize::Small)
 9441                    .buffer_font(cx)
 9442                    .when(!has_keybind, |el| {
 9443                        el.color(cx.theme().status().error.into()).strikethrough()
 9444                    }),
 9445            )
 9446            .when(!has_keybind, |el| {
 9447                el.child(
 9448                    h_flex().ml_1().child(
 9449                        Icon::new(IconName::Info)
 9450                            .size(IconSize::Small)
 9451                            .color(cx.theme().status().error.into()),
 9452                    ),
 9453                )
 9454            })
 9455            .child(
 9456                div()
 9457                    .mt(px(1.5))
 9458                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9459            )
 9460    }
 9461
 9462    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9463        let accent_color = cx.theme().colors().text_accent;
 9464        let editor_bg_color = cx.theme().colors().editor_background;
 9465        editor_bg_color.blend(accent_color.opacity(0.1))
 9466    }
 9467
 9468    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9469        let accent_color = cx.theme().colors().text_accent;
 9470        let editor_bg_color = cx.theme().colors().editor_background;
 9471        editor_bg_color.blend(accent_color.opacity(0.6))
 9472    }
 9473    fn get_prediction_provider_icon_name(
 9474        provider: &Option<RegisteredEditPredictionProvider>,
 9475    ) -> IconName {
 9476        match provider {
 9477            Some(provider) => match provider.provider.name() {
 9478                "copilot" => IconName::Copilot,
 9479                "supermaven" => IconName::Supermaven,
 9480                _ => IconName::ZedPredict,
 9481            },
 9482            None => IconName::ZedPredict,
 9483        }
 9484    }
 9485
 9486    fn render_edit_prediction_cursor_popover(
 9487        &self,
 9488        min_width: Pixels,
 9489        max_width: Pixels,
 9490        cursor_point: Point,
 9491        style: &EditorStyle,
 9492        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9493        _window: &Window,
 9494        cx: &mut Context<Editor>,
 9495    ) -> Option<AnyElement> {
 9496        let provider = self.edit_prediction_provider.as_ref()?;
 9497        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9498
 9499        let is_refreshing = provider.provider.is_refreshing(cx);
 9500
 9501        fn pending_completion_container(icon: IconName) -> Div {
 9502            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9503        }
 9504
 9505        let completion = match &self.active_edit_prediction {
 9506            Some(prediction) => {
 9507                if !self.has_visible_completions_menu() {
 9508                    const RADIUS: Pixels = px(6.);
 9509                    const BORDER_WIDTH: Pixels = px(1.);
 9510
 9511                    return Some(
 9512                        h_flex()
 9513                            .elevation_2(cx)
 9514                            .border(BORDER_WIDTH)
 9515                            .border_color(cx.theme().colors().border)
 9516                            .when(accept_keystroke.is_none(), |el| {
 9517                                el.border_color(cx.theme().status().error)
 9518                            })
 9519                            .rounded(RADIUS)
 9520                            .rounded_tl(px(0.))
 9521                            .overflow_hidden()
 9522                            .child(div().px_1p5().child(match &prediction.completion {
 9523                                EditPrediction::MoveWithin { target, snapshot } => {
 9524                                    use text::ToPoint as _;
 9525                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9526                                    {
 9527                                        Icon::new(IconName::ZedPredictDown)
 9528                                    } else {
 9529                                        Icon::new(IconName::ZedPredictUp)
 9530                                    }
 9531                                }
 9532                                EditPrediction::MoveOutside { .. } => {
 9533                                    // TODO [zeta2] custom icon for external jump?
 9534                                    Icon::new(provider_icon)
 9535                                }
 9536                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9537                            }))
 9538                            .child(
 9539                                h_flex()
 9540                                    .gap_1()
 9541                                    .py_1()
 9542                                    .px_2()
 9543                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9544                                    .border_l_1()
 9545                                    .border_color(cx.theme().colors().border)
 9546                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9547                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9548                                        el.child(
 9549                                            Label::new("Hold")
 9550                                                .size(LabelSize::Small)
 9551                                                .when(accept_keystroke.is_none(), |el| {
 9552                                                    el.strikethrough()
 9553                                                })
 9554                                                .line_height_style(LineHeightStyle::UiLabel),
 9555                                        )
 9556                                    })
 9557                                    .id("edit_prediction_cursor_popover_keybind")
 9558                                    .when(accept_keystroke.is_none(), |el| {
 9559                                        let status_colors = cx.theme().status();
 9560
 9561                                        el.bg(status_colors.error_background)
 9562                                            .border_color(status_colors.error.opacity(0.6))
 9563                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9564                                            .cursor_default()
 9565                                            .hoverable_tooltip(move |_window, cx| {
 9566                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9567                                                    .into()
 9568                                            })
 9569                                    })
 9570                                    .when_some(
 9571                                        accept_keystroke.as_ref(),
 9572                                        |el, accept_keystroke| {
 9573                                            el.child(h_flex().children(ui::render_modifiers(
 9574                                                accept_keystroke.modifiers(),
 9575                                                PlatformStyle::platform(),
 9576                                                Some(Color::Default),
 9577                                                Some(IconSize::XSmall.rems().into()),
 9578                                                false,
 9579                                            )))
 9580                                        },
 9581                                    ),
 9582                            )
 9583                            .into_any(),
 9584                    );
 9585                }
 9586
 9587                self.render_edit_prediction_cursor_popover_preview(
 9588                    prediction,
 9589                    cursor_point,
 9590                    style,
 9591                    cx,
 9592                )?
 9593            }
 9594
 9595            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9596                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9597                    stale_completion,
 9598                    cursor_point,
 9599                    style,
 9600                    cx,
 9601                )?,
 9602
 9603                None => pending_completion_container(provider_icon)
 9604                    .child(Label::new("...").size(LabelSize::Small)),
 9605            },
 9606
 9607            None => pending_completion_container(provider_icon)
 9608                .child(Label::new("...").size(LabelSize::Small)),
 9609        };
 9610
 9611        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9612            completion
 9613                .with_animation(
 9614                    "loading-completion",
 9615                    Animation::new(Duration::from_secs(2))
 9616                        .repeat()
 9617                        .with_easing(pulsating_between(0.4, 0.8)),
 9618                    |label, delta| label.opacity(delta),
 9619                )
 9620                .into_any_element()
 9621        } else {
 9622            completion.into_any_element()
 9623        };
 9624
 9625        let has_completion = self.active_edit_prediction.is_some();
 9626
 9627        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9628        Some(
 9629            h_flex()
 9630                .min_w(min_width)
 9631                .max_w(max_width)
 9632                .flex_1()
 9633                .elevation_2(cx)
 9634                .border_color(cx.theme().colors().border)
 9635                .child(
 9636                    div()
 9637                        .flex_1()
 9638                        .py_1()
 9639                        .px_2()
 9640                        .overflow_hidden()
 9641                        .child(completion),
 9642                )
 9643                .when_some(accept_keystroke, |el, accept_keystroke| {
 9644                    if !accept_keystroke.modifiers().modified() {
 9645                        return el;
 9646                    }
 9647
 9648                    el.child(
 9649                        h_flex()
 9650                            .h_full()
 9651                            .border_l_1()
 9652                            .rounded_r_lg()
 9653                            .border_color(cx.theme().colors().border)
 9654                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9655                            .gap_1()
 9656                            .py_1()
 9657                            .px_2()
 9658                            .child(
 9659                                h_flex()
 9660                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9661                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9662                                    .child(h_flex().children(ui::render_modifiers(
 9663                                        accept_keystroke.modifiers(),
 9664                                        PlatformStyle::platform(),
 9665                                        Some(if !has_completion {
 9666                                            Color::Muted
 9667                                        } else {
 9668                                            Color::Default
 9669                                        }),
 9670                                        None,
 9671                                        false,
 9672                                    ))),
 9673                            )
 9674                            .child(Label::new("Preview").into_any_element())
 9675                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9676                    )
 9677                })
 9678                .into_any(),
 9679        )
 9680    }
 9681
 9682    fn render_edit_prediction_cursor_popover_preview(
 9683        &self,
 9684        completion: &EditPredictionState,
 9685        cursor_point: Point,
 9686        style: &EditorStyle,
 9687        cx: &mut Context<Editor>,
 9688    ) -> Option<Div> {
 9689        use text::ToPoint as _;
 9690
 9691        fn render_relative_row_jump(
 9692            prefix: impl Into<String>,
 9693            current_row: u32,
 9694            target_row: u32,
 9695        ) -> Div {
 9696            let (row_diff, arrow) = if target_row < current_row {
 9697                (current_row - target_row, IconName::ArrowUp)
 9698            } else {
 9699                (target_row - current_row, IconName::ArrowDown)
 9700            };
 9701
 9702            h_flex()
 9703                .child(
 9704                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9705                        .color(Color::Muted)
 9706                        .size(LabelSize::Small),
 9707                )
 9708                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9709        }
 9710
 9711        let supports_jump = self
 9712            .edit_prediction_provider
 9713            .as_ref()
 9714            .map(|provider| provider.provider.supports_jump_to_edit())
 9715            .unwrap_or(true);
 9716
 9717        match &completion.completion {
 9718            EditPrediction::MoveWithin {
 9719                target, snapshot, ..
 9720            } => {
 9721                if !supports_jump {
 9722                    return None;
 9723                }
 9724
 9725                Some(
 9726                    h_flex()
 9727                        .px_2()
 9728                        .gap_2()
 9729                        .flex_1()
 9730                        .child(
 9731                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9732                                Icon::new(IconName::ZedPredictDown)
 9733                            } else {
 9734                                Icon::new(IconName::ZedPredictUp)
 9735                            },
 9736                        )
 9737                        .child(Label::new("Jump to Edit")),
 9738                )
 9739            }
 9740            EditPrediction::MoveOutside { snapshot, .. } => {
 9741                let file_name = snapshot
 9742                    .file()
 9743                    .map(|file| file.file_name(cx))
 9744                    .unwrap_or("untitled");
 9745                Some(
 9746                    h_flex()
 9747                        .px_2()
 9748                        .gap_2()
 9749                        .flex_1()
 9750                        .child(Icon::new(IconName::ZedPredict))
 9751                        .child(Label::new(format!("Jump to {file_name}"))),
 9752                )
 9753            }
 9754            EditPrediction::Edit {
 9755                edits,
 9756                edit_preview,
 9757                snapshot,
 9758                display_mode: _,
 9759            } => {
 9760                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9761
 9762                let (highlighted_edits, has_more_lines) =
 9763                    if let Some(edit_preview) = edit_preview.as_ref() {
 9764                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9765                            .first_line_preview()
 9766                    } else {
 9767                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9768                    };
 9769
 9770                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9771                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9772
 9773                let preview = h_flex()
 9774                    .gap_1()
 9775                    .min_w_16()
 9776                    .child(styled_text)
 9777                    .when(has_more_lines, |parent| parent.child(""));
 9778
 9779                let left = if supports_jump && first_edit_row != cursor_point.row {
 9780                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9781                        .into_any_element()
 9782                } else {
 9783                    let icon_name =
 9784                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9785                    Icon::new(icon_name).into_any_element()
 9786                };
 9787
 9788                Some(
 9789                    h_flex()
 9790                        .h_full()
 9791                        .flex_1()
 9792                        .gap_2()
 9793                        .pr_1()
 9794                        .overflow_x_hidden()
 9795                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9796                        .child(left)
 9797                        .child(preview),
 9798                )
 9799            }
 9800        }
 9801    }
 9802
 9803    pub fn render_context_menu(
 9804        &self,
 9805        style: &EditorStyle,
 9806        max_height_in_lines: u32,
 9807        window: &mut Window,
 9808        cx: &mut Context<Editor>,
 9809    ) -> Option<AnyElement> {
 9810        let menu = self.context_menu.borrow();
 9811        let menu = menu.as_ref()?;
 9812        if !menu.visible() {
 9813            return None;
 9814        };
 9815        Some(menu.render(style, max_height_in_lines, window, cx))
 9816    }
 9817
 9818    fn render_context_menu_aside(
 9819        &mut self,
 9820        max_size: Size<Pixels>,
 9821        window: &mut Window,
 9822        cx: &mut Context<Editor>,
 9823    ) -> Option<AnyElement> {
 9824        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9825            if menu.visible() {
 9826                menu.render_aside(max_size, window, cx)
 9827            } else {
 9828                None
 9829            }
 9830        })
 9831    }
 9832
 9833    fn hide_context_menu(
 9834        &mut self,
 9835        window: &mut Window,
 9836        cx: &mut Context<Self>,
 9837    ) -> Option<CodeContextMenu> {
 9838        cx.notify();
 9839        self.completion_tasks.clear();
 9840        let context_menu = self.context_menu.borrow_mut().take();
 9841        self.stale_edit_prediction_in_menu.take();
 9842        self.update_visible_edit_prediction(window, cx);
 9843        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9844            && let Some(completion_provider) = &self.completion_provider
 9845        {
 9846            completion_provider.selection_changed(None, window, cx);
 9847        }
 9848        context_menu
 9849    }
 9850
 9851    fn show_snippet_choices(
 9852        &mut self,
 9853        choices: &Vec<String>,
 9854        selection: Range<Anchor>,
 9855        cx: &mut Context<Self>,
 9856    ) {
 9857        let Some((_, buffer, _)) = self
 9858            .buffer()
 9859            .read(cx)
 9860            .excerpt_containing(selection.start, cx)
 9861        else {
 9862            return;
 9863        };
 9864        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9865        else {
 9866            return;
 9867        };
 9868        if buffer != end_buffer {
 9869            log::error!("expected anchor range to have matching buffer IDs");
 9870            return;
 9871        }
 9872
 9873        let id = post_inc(&mut self.next_completion_id);
 9874        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9875        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9876            CompletionsMenu::new_snippet_choices(
 9877                id,
 9878                true,
 9879                choices,
 9880                selection,
 9881                buffer,
 9882                snippet_sort_order,
 9883            ),
 9884        ));
 9885    }
 9886
 9887    pub fn insert_snippet(
 9888        &mut self,
 9889        insertion_ranges: &[Range<MultiBufferOffset>],
 9890        snippet: Snippet,
 9891        window: &mut Window,
 9892        cx: &mut Context<Self>,
 9893    ) -> Result<()> {
 9894        struct Tabstop<T> {
 9895            is_end_tabstop: bool,
 9896            ranges: Vec<Range<T>>,
 9897            choices: Option<Vec<String>>,
 9898        }
 9899
 9900        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9901            let snippet_text: Arc<str> = snippet.text.clone().into();
 9902            let edits = insertion_ranges
 9903                .iter()
 9904                .cloned()
 9905                .map(|range| (range, snippet_text.clone()));
 9906            let autoindent_mode = AutoindentMode::Block {
 9907                original_indent_columns: Vec::new(),
 9908            };
 9909            buffer.edit(edits, Some(autoindent_mode), cx);
 9910
 9911            let snapshot = &*buffer.read(cx);
 9912            let snippet = &snippet;
 9913            snippet
 9914                .tabstops
 9915                .iter()
 9916                .map(|tabstop| {
 9917                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9918                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9919                    });
 9920                    let mut tabstop_ranges = tabstop
 9921                        .ranges
 9922                        .iter()
 9923                        .flat_map(|tabstop_range| {
 9924                            let mut delta = 0_isize;
 9925                            insertion_ranges.iter().map(move |insertion_range| {
 9926                                let insertion_start = insertion_range.start + delta;
 9927                                delta += snippet.text.len() as isize
 9928                                    - (insertion_range.end - insertion_range.start) as isize;
 9929
 9930                                let start =
 9931                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9932                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9933                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9934                            })
 9935                        })
 9936                        .collect::<Vec<_>>();
 9937                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9938
 9939                    Tabstop {
 9940                        is_end_tabstop,
 9941                        ranges: tabstop_ranges,
 9942                        choices: tabstop.choices.clone(),
 9943                    }
 9944                })
 9945                .collect::<Vec<_>>()
 9946        });
 9947        if let Some(tabstop) = tabstops.first() {
 9948            self.change_selections(Default::default(), window, cx, |s| {
 9949                // Reverse order so that the first range is the newest created selection.
 9950                // Completions will use it and autoscroll will prioritize it.
 9951                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9952            });
 9953
 9954            if let Some(choices) = &tabstop.choices
 9955                && let Some(selection) = tabstop.ranges.first()
 9956            {
 9957                self.show_snippet_choices(choices, selection.clone(), cx)
 9958            }
 9959
 9960            // If we're already at the last tabstop and it's at the end of the snippet,
 9961            // we're done, we don't need to keep the state around.
 9962            if !tabstop.is_end_tabstop {
 9963                let choices = tabstops
 9964                    .iter()
 9965                    .map(|tabstop| tabstop.choices.clone())
 9966                    .collect();
 9967
 9968                let ranges = tabstops
 9969                    .into_iter()
 9970                    .map(|tabstop| tabstop.ranges)
 9971                    .collect::<Vec<_>>();
 9972
 9973                self.snippet_stack.push(SnippetState {
 9974                    active_index: 0,
 9975                    ranges,
 9976                    choices,
 9977                });
 9978            }
 9979
 9980            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9981            if self.autoclose_regions.is_empty() {
 9982                let snapshot = self.buffer.read(cx).snapshot(cx);
 9983                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9984                    let selection_head = selection.head();
 9985                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9986                        continue;
 9987                    };
 9988
 9989                    let mut bracket_pair = None;
 9990                    let max_lookup_length = scope
 9991                        .brackets()
 9992                        .map(|(pair, _)| {
 9993                            pair.start
 9994                                .as_str()
 9995                                .chars()
 9996                                .count()
 9997                                .max(pair.end.as_str().chars().count())
 9998                        })
 9999                        .max();
10000                    if let Some(max_lookup_length) = max_lookup_length {
10001                        let next_text = snapshot
10002                            .chars_at(selection_head)
10003                            .take(max_lookup_length)
10004                            .collect::<String>();
10005                        let prev_text = snapshot
10006                            .reversed_chars_at(selection_head)
10007                            .take(max_lookup_length)
10008                            .collect::<String>();
10009
10010                        for (pair, enabled) in scope.brackets() {
10011                            if enabled
10012                                && pair.close
10013                                && prev_text.starts_with(pair.start.as_str())
10014                                && next_text.starts_with(pair.end.as_str())
10015                            {
10016                                bracket_pair = Some(pair.clone());
10017                                break;
10018                            }
10019                        }
10020                    }
10021
10022                    if let Some(pair) = bracket_pair {
10023                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10024                        let autoclose_enabled =
10025                            self.use_autoclose && snapshot_settings.use_autoclose;
10026                        if autoclose_enabled {
10027                            let start = snapshot.anchor_after(selection_head);
10028                            let end = snapshot.anchor_after(selection_head);
10029                            self.autoclose_regions.push(AutocloseRegion {
10030                                selection_id: selection.id,
10031                                range: start..end,
10032                                pair,
10033                            });
10034                        }
10035                    }
10036                }
10037            }
10038        }
10039        Ok(())
10040    }
10041
10042    pub fn move_to_next_snippet_tabstop(
10043        &mut self,
10044        window: &mut Window,
10045        cx: &mut Context<Self>,
10046    ) -> bool {
10047        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10048    }
10049
10050    pub fn move_to_prev_snippet_tabstop(
10051        &mut self,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) -> bool {
10055        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10056    }
10057
10058    pub fn move_to_snippet_tabstop(
10059        &mut self,
10060        bias: Bias,
10061        window: &mut Window,
10062        cx: &mut Context<Self>,
10063    ) -> bool {
10064        if let Some(mut snippet) = self.snippet_stack.pop() {
10065            match bias {
10066                Bias::Left => {
10067                    if snippet.active_index > 0 {
10068                        snippet.active_index -= 1;
10069                    } else {
10070                        self.snippet_stack.push(snippet);
10071                        return false;
10072                    }
10073                }
10074                Bias::Right => {
10075                    if snippet.active_index + 1 < snippet.ranges.len() {
10076                        snippet.active_index += 1;
10077                    } else {
10078                        self.snippet_stack.push(snippet);
10079                        return false;
10080                    }
10081                }
10082            }
10083            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10084                self.change_selections(Default::default(), window, cx, |s| {
10085                    // Reverse order so that the first range is the newest created selection.
10086                    // Completions will use it and autoscroll will prioritize it.
10087                    s.select_ranges(current_ranges.iter().rev().cloned())
10088                });
10089
10090                if let Some(choices) = &snippet.choices[snippet.active_index]
10091                    && let Some(selection) = current_ranges.first()
10092                {
10093                    self.show_snippet_choices(choices, selection.clone(), cx);
10094                }
10095
10096                // If snippet state is not at the last tabstop, push it back on the stack
10097                if snippet.active_index + 1 < snippet.ranges.len() {
10098                    self.snippet_stack.push(snippet);
10099                }
10100                return true;
10101            }
10102        }
10103
10104        false
10105    }
10106
10107    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10108        self.transact(window, cx, |this, window, cx| {
10109            this.select_all(&SelectAll, window, cx);
10110            this.insert("", window, cx);
10111        });
10112    }
10113
10114    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10115        if self.read_only(cx) {
10116            return;
10117        }
10118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10119        self.transact(window, cx, |this, window, cx| {
10120            this.select_autoclose_pair(window, cx);
10121
10122            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10123
10124            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10125            if !this.linked_edit_ranges.is_empty() {
10126                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10127                let snapshot = this.buffer.read(cx).snapshot(cx);
10128
10129                for selection in selections.iter() {
10130                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10131                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10132                    if selection_start.buffer_id != selection_end.buffer_id {
10133                        continue;
10134                    }
10135                    if let Some(ranges) =
10136                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10137                    {
10138                        for (buffer, entries) in ranges {
10139                            linked_ranges.entry(buffer).or_default().extend(entries);
10140                        }
10141                    }
10142                }
10143            }
10144
10145            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10146            for selection in &mut selections {
10147                if selection.is_empty() {
10148                    let old_head = selection.head();
10149                    let mut new_head =
10150                        movement::left(&display_map, old_head.to_display_point(&display_map))
10151                            .to_point(&display_map);
10152                    if let Some((buffer, line_buffer_range)) = display_map
10153                        .buffer_snapshot()
10154                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10155                    {
10156                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10157                        let indent_len = match indent_size.kind {
10158                            IndentKind::Space => {
10159                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10160                            }
10161                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10162                        };
10163                        if old_head.column <= indent_size.len && old_head.column > 0 {
10164                            let indent_len = indent_len.get();
10165                            new_head = cmp::min(
10166                                new_head,
10167                                MultiBufferPoint::new(
10168                                    old_head.row,
10169                                    ((old_head.column - 1) / indent_len) * indent_len,
10170                                ),
10171                            );
10172                        }
10173                    }
10174
10175                    selection.set_head(new_head, SelectionGoal::None);
10176                }
10177            }
10178
10179            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10180            this.insert("", window, cx);
10181            let empty_str: Arc<str> = Arc::from("");
10182            for (buffer, edits) in linked_ranges {
10183                let snapshot = buffer.read(cx).snapshot();
10184                use text::ToPoint as TP;
10185
10186                let edits = edits
10187                    .into_iter()
10188                    .map(|range| {
10189                        let end_point = TP::to_point(&range.end, &snapshot);
10190                        let mut start_point = TP::to_point(&range.start, &snapshot);
10191
10192                        if end_point == start_point {
10193                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10194                                .saturating_sub(1);
10195                            start_point =
10196                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10197                        };
10198
10199                        (start_point..end_point, empty_str.clone())
10200                    })
10201                    .sorted_by_key(|(range, _)| range.start)
10202                    .collect::<Vec<_>>();
10203                buffer.update(cx, |this, cx| {
10204                    this.edit(edits, None, cx);
10205                })
10206            }
10207            this.refresh_edit_prediction(true, false, window, cx);
10208            refresh_linked_ranges(this, window, cx);
10209        });
10210    }
10211
10212    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10213        if self.read_only(cx) {
10214            return;
10215        }
10216        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10217        self.transact(window, cx, |this, window, cx| {
10218            this.change_selections(Default::default(), window, cx, |s| {
10219                s.move_with(|map, selection| {
10220                    if selection.is_empty() {
10221                        let cursor = movement::right(map, selection.head());
10222                        selection.end = cursor;
10223                        selection.reversed = true;
10224                        selection.goal = SelectionGoal::None;
10225                    }
10226                })
10227            });
10228            this.insert("", window, cx);
10229            this.refresh_edit_prediction(true, false, window, cx);
10230        });
10231    }
10232
10233    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10234        if self.mode.is_single_line() {
10235            cx.propagate();
10236            return;
10237        }
10238
10239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10240        if self.move_to_prev_snippet_tabstop(window, cx) {
10241            return;
10242        }
10243        self.outdent(&Outdent, window, cx);
10244    }
10245
10246    pub fn next_snippet_tabstop(
10247        &mut self,
10248        _: &NextSnippetTabstop,
10249        window: &mut Window,
10250        cx: &mut Context<Self>,
10251    ) {
10252        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10253            cx.propagate();
10254            return;
10255        }
10256
10257        if self.move_to_next_snippet_tabstop(window, cx) {
10258            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10259            return;
10260        }
10261        cx.propagate();
10262    }
10263
10264    pub fn previous_snippet_tabstop(
10265        &mut self,
10266        _: &PreviousSnippetTabstop,
10267        window: &mut Window,
10268        cx: &mut Context<Self>,
10269    ) {
10270        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10271            cx.propagate();
10272            return;
10273        }
10274
10275        if self.move_to_prev_snippet_tabstop(window, cx) {
10276            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10277            return;
10278        }
10279        cx.propagate();
10280    }
10281
10282    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10283        if self.mode.is_single_line() {
10284            cx.propagate();
10285            return;
10286        }
10287
10288        if self.move_to_next_snippet_tabstop(window, cx) {
10289            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10290            return;
10291        }
10292        if self.read_only(cx) {
10293            return;
10294        }
10295        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10296        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10297        let buffer = self.buffer.read(cx);
10298        let snapshot = buffer.snapshot(cx);
10299        let rows_iter = selections.iter().map(|s| s.head().row);
10300        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10301
10302        let has_some_cursor_in_whitespace = selections
10303            .iter()
10304            .filter(|selection| selection.is_empty())
10305            .any(|selection| {
10306                let cursor = selection.head();
10307                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10308                cursor.column < current_indent.len
10309            });
10310
10311        let mut edits = Vec::new();
10312        let mut prev_edited_row = 0;
10313        let mut row_delta = 0;
10314        for selection in &mut selections {
10315            if selection.start.row != prev_edited_row {
10316                row_delta = 0;
10317            }
10318            prev_edited_row = selection.end.row;
10319
10320            // If the selection is non-empty, then increase the indentation of the selected lines.
10321            if !selection.is_empty() {
10322                row_delta =
10323                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10324                continue;
10325            }
10326
10327            let cursor = selection.head();
10328            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10329            if let Some(suggested_indent) =
10330                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10331            {
10332                // Don't do anything if already at suggested indent
10333                // and there is any other cursor which is not
10334                if has_some_cursor_in_whitespace
10335                    && cursor.column == current_indent.len
10336                    && current_indent.len == suggested_indent.len
10337                {
10338                    continue;
10339                }
10340
10341                // Adjust line and move cursor to suggested indent
10342                // if cursor is not at suggested indent
10343                if cursor.column < suggested_indent.len
10344                    && cursor.column <= current_indent.len
10345                    && current_indent.len <= suggested_indent.len
10346                {
10347                    selection.start = Point::new(cursor.row, suggested_indent.len);
10348                    selection.end = selection.start;
10349                    if row_delta == 0 {
10350                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10351                            cursor.row,
10352                            current_indent,
10353                            suggested_indent,
10354                        ));
10355                        row_delta = suggested_indent.len - current_indent.len;
10356                    }
10357                    continue;
10358                }
10359
10360                // If current indent is more than suggested indent
10361                // only move cursor to current indent and skip indent
10362                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10363                    selection.start = Point::new(cursor.row, current_indent.len);
10364                    selection.end = selection.start;
10365                    continue;
10366                }
10367            }
10368
10369            // Otherwise, insert a hard or soft tab.
10370            let settings = buffer.language_settings_at(cursor, cx);
10371            let tab_size = if settings.hard_tabs {
10372                IndentSize::tab()
10373            } else {
10374                let tab_size = settings.tab_size.get();
10375                let indent_remainder = snapshot
10376                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10377                    .flat_map(str::chars)
10378                    .fold(row_delta % tab_size, |counter: u32, c| {
10379                        if c == '\t' {
10380                            0
10381                        } else {
10382                            (counter + 1) % tab_size
10383                        }
10384                    });
10385
10386                let chars_to_next_tab_stop = tab_size - indent_remainder;
10387                IndentSize::spaces(chars_to_next_tab_stop)
10388            };
10389            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10390            selection.end = selection.start;
10391            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10392            row_delta += tab_size.len;
10393        }
10394
10395        self.transact(window, cx, |this, window, cx| {
10396            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10397            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10398            this.refresh_edit_prediction(true, false, window, cx);
10399        });
10400    }
10401
10402    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10403        if self.read_only(cx) {
10404            return;
10405        }
10406        if self.mode.is_single_line() {
10407            cx.propagate();
10408            return;
10409        }
10410
10411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10412        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10413        let mut prev_edited_row = 0;
10414        let mut row_delta = 0;
10415        let mut edits = Vec::new();
10416        let buffer = self.buffer.read(cx);
10417        let snapshot = buffer.snapshot(cx);
10418        for selection in &mut selections {
10419            if selection.start.row != prev_edited_row {
10420                row_delta = 0;
10421            }
10422            prev_edited_row = selection.end.row;
10423
10424            row_delta =
10425                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10426        }
10427
10428        self.transact(window, cx, |this, window, cx| {
10429            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10430            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10431        });
10432    }
10433
10434    fn indent_selection(
10435        buffer: &MultiBuffer,
10436        snapshot: &MultiBufferSnapshot,
10437        selection: &mut Selection<Point>,
10438        edits: &mut Vec<(Range<Point>, String)>,
10439        delta_for_start_row: u32,
10440        cx: &App,
10441    ) -> u32 {
10442        let settings = buffer.language_settings_at(selection.start, cx);
10443        let tab_size = settings.tab_size.get();
10444        let indent_kind = if settings.hard_tabs {
10445            IndentKind::Tab
10446        } else {
10447            IndentKind::Space
10448        };
10449        let mut start_row = selection.start.row;
10450        let mut end_row = selection.end.row + 1;
10451
10452        // If a selection ends at the beginning of a line, don't indent
10453        // that last line.
10454        if selection.end.column == 0 && selection.end.row > selection.start.row {
10455            end_row -= 1;
10456        }
10457
10458        // Avoid re-indenting a row that has already been indented by a
10459        // previous selection, but still update this selection's column
10460        // to reflect that indentation.
10461        if delta_for_start_row > 0 {
10462            start_row += 1;
10463            selection.start.column += delta_for_start_row;
10464            if selection.end.row == selection.start.row {
10465                selection.end.column += delta_for_start_row;
10466            }
10467        }
10468
10469        let mut delta_for_end_row = 0;
10470        let has_multiple_rows = start_row + 1 != end_row;
10471        for row in start_row..end_row {
10472            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10473            let indent_delta = match (current_indent.kind, indent_kind) {
10474                (IndentKind::Space, IndentKind::Space) => {
10475                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10476                    IndentSize::spaces(columns_to_next_tab_stop)
10477                }
10478                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10479                (_, IndentKind::Tab) => IndentSize::tab(),
10480            };
10481
10482            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10483                0
10484            } else {
10485                selection.start.column
10486            };
10487            let row_start = Point::new(row, start);
10488            edits.push((
10489                row_start..row_start,
10490                indent_delta.chars().collect::<String>(),
10491            ));
10492
10493            // Update this selection's endpoints to reflect the indentation.
10494            if row == selection.start.row {
10495                selection.start.column += indent_delta.len;
10496            }
10497            if row == selection.end.row {
10498                selection.end.column += indent_delta.len;
10499                delta_for_end_row = indent_delta.len;
10500            }
10501        }
10502
10503        if selection.start.row == selection.end.row {
10504            delta_for_start_row + delta_for_end_row
10505        } else {
10506            delta_for_end_row
10507        }
10508    }
10509
10510    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10511        if self.read_only(cx) {
10512            return;
10513        }
10514        if self.mode.is_single_line() {
10515            cx.propagate();
10516            return;
10517        }
10518
10519        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10521        let selections = self.selections.all::<Point>(&display_map);
10522        let mut deletion_ranges = Vec::new();
10523        let mut last_outdent = None;
10524        {
10525            let buffer = self.buffer.read(cx);
10526            let snapshot = buffer.snapshot(cx);
10527            for selection in &selections {
10528                let settings = buffer.language_settings_at(selection.start, cx);
10529                let tab_size = settings.tab_size.get();
10530                let mut rows = selection.spanned_rows(false, &display_map);
10531
10532                // Avoid re-outdenting a row that has already been outdented by a
10533                // previous selection.
10534                if let Some(last_row) = last_outdent
10535                    && last_row == rows.start
10536                {
10537                    rows.start = rows.start.next_row();
10538                }
10539                let has_multiple_rows = rows.len() > 1;
10540                for row in rows.iter_rows() {
10541                    let indent_size = snapshot.indent_size_for_line(row);
10542                    if indent_size.len > 0 {
10543                        let deletion_len = match indent_size.kind {
10544                            IndentKind::Space => {
10545                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10546                                if columns_to_prev_tab_stop == 0 {
10547                                    tab_size
10548                                } else {
10549                                    columns_to_prev_tab_stop
10550                                }
10551                            }
10552                            IndentKind::Tab => 1,
10553                        };
10554                        let start = if has_multiple_rows
10555                            || deletion_len > selection.start.column
10556                            || indent_size.len < selection.start.column
10557                        {
10558                            0
10559                        } else {
10560                            selection.start.column - deletion_len
10561                        };
10562                        deletion_ranges.push(
10563                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10564                        );
10565                        last_outdent = Some(row);
10566                    }
10567                }
10568            }
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            this.buffer.update(cx, |buffer, cx| {
10573                let empty_str: Arc<str> = Arc::default();
10574                buffer.edit(
10575                    deletion_ranges
10576                        .into_iter()
10577                        .map(|range| (range, empty_str.clone())),
10578                    None,
10579                    cx,
10580                );
10581            });
10582            let selections = this
10583                .selections
10584                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10585            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10586        });
10587    }
10588
10589    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10590        if self.read_only(cx) {
10591            return;
10592        }
10593        if self.mode.is_single_line() {
10594            cx.propagate();
10595            return;
10596        }
10597
10598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10599        let selections = self
10600            .selections
10601            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10602            .into_iter()
10603            .map(|s| s.range());
10604
10605        self.transact(window, cx, |this, window, cx| {
10606            this.buffer.update(cx, |buffer, cx| {
10607                buffer.autoindent_ranges(selections, cx);
10608            });
10609            let selections = this
10610                .selections
10611                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10612            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10613        });
10614    }
10615
10616    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10617        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10618        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10619        let selections = self.selections.all::<Point>(&display_map);
10620
10621        let mut new_cursors = Vec::new();
10622        let mut edit_ranges = Vec::new();
10623        let mut selections = selections.iter().peekable();
10624        while let Some(selection) = selections.next() {
10625            let mut rows = selection.spanned_rows(false, &display_map);
10626
10627            // Accumulate contiguous regions of rows that we want to delete.
10628            while let Some(next_selection) = selections.peek() {
10629                let next_rows = next_selection.spanned_rows(false, &display_map);
10630                if next_rows.start <= rows.end {
10631                    rows.end = next_rows.end;
10632                    selections.next().unwrap();
10633                } else {
10634                    break;
10635                }
10636            }
10637
10638            let buffer = display_map.buffer_snapshot();
10639            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10640            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10641                // If there's a line after the range, delete the \n from the end of the row range
10642                (
10643                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10644                    rows.end,
10645                )
10646            } else {
10647                // If there isn't a line after the range, delete the \n from the line before the
10648                // start of the row range
10649                edit_start = edit_start.saturating_sub_usize(1);
10650                (buffer.len(), rows.start.previous_row())
10651            };
10652
10653            let text_layout_details = self.text_layout_details(window);
10654            let x = display_map.x_for_display_point(
10655                selection.head().to_display_point(&display_map),
10656                &text_layout_details,
10657            );
10658            let row = Point::new(target_row.0, 0)
10659                .to_display_point(&display_map)
10660                .row();
10661            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10662
10663            new_cursors.push((
10664                selection.id,
10665                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10666                SelectionGoal::None,
10667            ));
10668            edit_ranges.push(edit_start..edit_end);
10669        }
10670
10671        self.transact(window, cx, |this, window, cx| {
10672            let buffer = this.buffer.update(cx, |buffer, cx| {
10673                let empty_str: Arc<str> = Arc::default();
10674                buffer.edit(
10675                    edit_ranges
10676                        .into_iter()
10677                        .map(|range| (range, empty_str.clone())),
10678                    None,
10679                    cx,
10680                );
10681                buffer.snapshot(cx)
10682            });
10683            let new_selections = new_cursors
10684                .into_iter()
10685                .map(|(id, cursor, goal)| {
10686                    let cursor = cursor.to_point(&buffer);
10687                    Selection {
10688                        id,
10689                        start: cursor,
10690                        end: cursor,
10691                        reversed: false,
10692                        goal,
10693                    }
10694                })
10695                .collect();
10696
10697            this.change_selections(Default::default(), window, cx, |s| {
10698                s.select(new_selections);
10699            });
10700        });
10701    }
10702
10703    pub fn join_lines_impl(
10704        &mut self,
10705        insert_whitespace: bool,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) {
10709        if self.read_only(cx) {
10710            return;
10711        }
10712        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10713        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10714            let start = MultiBufferRow(selection.start.row);
10715            // Treat single line selections as if they include the next line. Otherwise this action
10716            // would do nothing for single line selections individual cursors.
10717            let end = if selection.start.row == selection.end.row {
10718                MultiBufferRow(selection.start.row + 1)
10719            } else {
10720                MultiBufferRow(selection.end.row)
10721            };
10722
10723            if let Some(last_row_range) = row_ranges.last_mut()
10724                && start <= last_row_range.end
10725            {
10726                last_row_range.end = end;
10727                continue;
10728            }
10729            row_ranges.push(start..end);
10730        }
10731
10732        let snapshot = self.buffer.read(cx).snapshot(cx);
10733        let mut cursor_positions = Vec::new();
10734        for row_range in &row_ranges {
10735            let anchor = snapshot.anchor_before(Point::new(
10736                row_range.end.previous_row().0,
10737                snapshot.line_len(row_range.end.previous_row()),
10738            ));
10739            cursor_positions.push(anchor..anchor);
10740        }
10741
10742        self.transact(window, cx, |this, window, cx| {
10743            for row_range in row_ranges.into_iter().rev() {
10744                for row in row_range.iter_rows().rev() {
10745                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10746                    let next_line_row = row.next_row();
10747                    let indent = snapshot.indent_size_for_line(next_line_row);
10748                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10749
10750                    let replace =
10751                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10752                            " "
10753                        } else {
10754                            ""
10755                        };
10756
10757                    this.buffer.update(cx, |buffer, cx| {
10758                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10759                    });
10760                }
10761            }
10762
10763            this.change_selections(Default::default(), window, cx, |s| {
10764                s.select_anchor_ranges(cursor_positions)
10765            });
10766        });
10767    }
10768
10769    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10771        self.join_lines_impl(true, window, cx);
10772    }
10773
10774    pub fn sort_lines_case_sensitive(
10775        &mut self,
10776        _: &SortLinesCaseSensitive,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10781    }
10782
10783    pub fn sort_lines_by_length(
10784        &mut self,
10785        _: &SortLinesByLength,
10786        window: &mut Window,
10787        cx: &mut Context<Self>,
10788    ) {
10789        self.manipulate_immutable_lines(window, cx, |lines| {
10790            lines.sort_by_key(|&line| line.chars().count())
10791        })
10792    }
10793
10794    pub fn sort_lines_case_insensitive(
10795        &mut self,
10796        _: &SortLinesCaseInsensitive,
10797        window: &mut Window,
10798        cx: &mut Context<Self>,
10799    ) {
10800        self.manipulate_immutable_lines(window, cx, |lines| {
10801            lines.sort_by_key(|line| line.to_lowercase())
10802        })
10803    }
10804
10805    pub fn unique_lines_case_insensitive(
10806        &mut self,
10807        _: &UniqueLinesCaseInsensitive,
10808        window: &mut Window,
10809        cx: &mut Context<Self>,
10810    ) {
10811        self.manipulate_immutable_lines(window, cx, |lines| {
10812            let mut seen = HashSet::default();
10813            lines.retain(|line| seen.insert(line.to_lowercase()));
10814        })
10815    }
10816
10817    pub fn unique_lines_case_sensitive(
10818        &mut self,
10819        _: &UniqueLinesCaseSensitive,
10820        window: &mut Window,
10821        cx: &mut Context<Self>,
10822    ) {
10823        self.manipulate_immutable_lines(window, cx, |lines| {
10824            let mut seen = HashSet::default();
10825            lines.retain(|line| seen.insert(*line));
10826        })
10827    }
10828
10829    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10830        let snapshot = self.buffer.read(cx).snapshot(cx);
10831        for selection in self.selections.disjoint_anchors_arc().iter() {
10832            if snapshot
10833                .language_at(selection.start)
10834                .and_then(|lang| lang.config().wrap_characters.as_ref())
10835                .is_some()
10836            {
10837                return true;
10838            }
10839        }
10840        false
10841    }
10842
10843    fn wrap_selections_in_tag(
10844        &mut self,
10845        _: &WrapSelectionsInTag,
10846        window: &mut Window,
10847        cx: &mut Context<Self>,
10848    ) {
10849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10850
10851        let snapshot = self.buffer.read(cx).snapshot(cx);
10852
10853        let mut edits = Vec::new();
10854        let mut boundaries = Vec::new();
10855
10856        for selection in self
10857            .selections
10858            .all_adjusted(&self.display_snapshot(cx))
10859            .iter()
10860        {
10861            let Some(wrap_config) = snapshot
10862                .language_at(selection.start)
10863                .and_then(|lang| lang.config().wrap_characters.clone())
10864            else {
10865                continue;
10866            };
10867
10868            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10869            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10870
10871            let start_before = snapshot.anchor_before(selection.start);
10872            let end_after = snapshot.anchor_after(selection.end);
10873
10874            edits.push((start_before..start_before, open_tag));
10875            edits.push((end_after..end_after, close_tag));
10876
10877            boundaries.push((
10878                start_before,
10879                end_after,
10880                wrap_config.start_prefix.len(),
10881                wrap_config.end_suffix.len(),
10882            ));
10883        }
10884
10885        if edits.is_empty() {
10886            return;
10887        }
10888
10889        self.transact(window, cx, |this, window, cx| {
10890            let buffer = this.buffer.update(cx, |buffer, cx| {
10891                buffer.edit(edits, None, cx);
10892                buffer.snapshot(cx)
10893            });
10894
10895            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10896            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10897                boundaries.into_iter()
10898            {
10899                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10900                let close_offset = end_after
10901                    .to_offset(&buffer)
10902                    .saturating_sub_usize(end_suffix_len);
10903                new_selections.push(open_offset..open_offset);
10904                new_selections.push(close_offset..close_offset);
10905            }
10906
10907            this.change_selections(Default::default(), window, cx, |s| {
10908                s.select_ranges(new_selections);
10909            });
10910
10911            this.request_autoscroll(Autoscroll::fit(), cx);
10912        });
10913    }
10914
10915    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10916        let Some(project) = self.project.clone() else {
10917            return;
10918        };
10919        self.reload(project, window, cx)
10920            .detach_and_notify_err(window, cx);
10921    }
10922
10923    pub fn restore_file(
10924        &mut self,
10925        _: &::git::RestoreFile,
10926        window: &mut Window,
10927        cx: &mut Context<Self>,
10928    ) {
10929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10930        let mut buffer_ids = HashSet::default();
10931        let snapshot = self.buffer().read(cx).snapshot(cx);
10932        for selection in self
10933            .selections
10934            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10935        {
10936            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10937        }
10938
10939        let buffer = self.buffer().read(cx);
10940        let ranges = buffer_ids
10941            .into_iter()
10942            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10943            .collect::<Vec<_>>();
10944
10945        self.restore_hunks_in_ranges(ranges, window, cx);
10946    }
10947
10948    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10950        let selections = self
10951            .selections
10952            .all(&self.display_snapshot(cx))
10953            .into_iter()
10954            .map(|s| s.range())
10955            .collect();
10956        self.restore_hunks_in_ranges(selections, window, cx);
10957    }
10958
10959    pub fn restore_hunks_in_ranges(
10960        &mut self,
10961        ranges: Vec<Range<Point>>,
10962        window: &mut Window,
10963        cx: &mut Context<Editor>,
10964    ) {
10965        let mut revert_changes = HashMap::default();
10966        let chunk_by = self
10967            .snapshot(window, cx)
10968            .hunks_for_ranges(ranges)
10969            .into_iter()
10970            .chunk_by(|hunk| hunk.buffer_id);
10971        for (buffer_id, hunks) in &chunk_by {
10972            let hunks = hunks.collect::<Vec<_>>();
10973            for hunk in &hunks {
10974                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10975            }
10976            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10977        }
10978        drop(chunk_by);
10979        if !revert_changes.is_empty() {
10980            self.transact(window, cx, |editor, window, cx| {
10981                editor.restore(revert_changes, window, cx);
10982            });
10983        }
10984    }
10985
10986    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10987        if let Some(status) = self
10988            .addons
10989            .iter()
10990            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10991        {
10992            return Some(status);
10993        }
10994        self.project
10995            .as_ref()?
10996            .read(cx)
10997            .status_for_buffer_id(buffer_id, cx)
10998    }
10999
11000    pub fn open_active_item_in_terminal(
11001        &mut self,
11002        _: &OpenInTerminal,
11003        window: &mut Window,
11004        cx: &mut Context<Self>,
11005    ) {
11006        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11007            let project_path = buffer.read(cx).project_path(cx)?;
11008            let project = self.project()?.read(cx);
11009            let entry = project.entry_for_path(&project_path, cx)?;
11010            let parent = match &entry.canonical_path {
11011                Some(canonical_path) => canonical_path.to_path_buf(),
11012                None => project.absolute_path(&project_path, cx)?,
11013            }
11014            .parent()?
11015            .to_path_buf();
11016            Some(parent)
11017        }) {
11018            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11019        }
11020    }
11021
11022    fn set_breakpoint_context_menu(
11023        &mut self,
11024        display_row: DisplayRow,
11025        position: Option<Anchor>,
11026        clicked_point: gpui::Point<Pixels>,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        let source = self
11031            .buffer
11032            .read(cx)
11033            .snapshot(cx)
11034            .anchor_before(Point::new(display_row.0, 0u32));
11035
11036        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11037
11038        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11039            self,
11040            source,
11041            clicked_point,
11042            context_menu,
11043            window,
11044            cx,
11045        );
11046    }
11047
11048    fn add_edit_breakpoint_block(
11049        &mut self,
11050        anchor: Anchor,
11051        breakpoint: &Breakpoint,
11052        edit_action: BreakpointPromptEditAction,
11053        window: &mut Window,
11054        cx: &mut Context<Self>,
11055    ) {
11056        let weak_editor = cx.weak_entity();
11057        let bp_prompt = cx.new(|cx| {
11058            BreakpointPromptEditor::new(
11059                weak_editor,
11060                anchor,
11061                breakpoint.clone(),
11062                edit_action,
11063                window,
11064                cx,
11065            )
11066        });
11067
11068        let height = bp_prompt.update(cx, |this, cx| {
11069            this.prompt
11070                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11071        });
11072        let cloned_prompt = bp_prompt.clone();
11073        let blocks = vec![BlockProperties {
11074            style: BlockStyle::Sticky,
11075            placement: BlockPlacement::Above(anchor),
11076            height: Some(height),
11077            render: Arc::new(move |cx| {
11078                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11079                cloned_prompt.clone().into_any_element()
11080            }),
11081            priority: 0,
11082        }];
11083
11084        let focus_handle = bp_prompt.focus_handle(cx);
11085        window.focus(&focus_handle);
11086
11087        let block_ids = self.insert_blocks(blocks, None, cx);
11088        bp_prompt.update(cx, |prompt, _| {
11089            prompt.add_block_ids(block_ids);
11090        });
11091    }
11092
11093    pub(crate) fn breakpoint_at_row(
11094        &self,
11095        row: u32,
11096        window: &mut Window,
11097        cx: &mut Context<Self>,
11098    ) -> Option<(Anchor, Breakpoint)> {
11099        let snapshot = self.snapshot(window, cx);
11100        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11101
11102        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11103    }
11104
11105    pub(crate) fn breakpoint_at_anchor(
11106        &self,
11107        breakpoint_position: Anchor,
11108        snapshot: &EditorSnapshot,
11109        cx: &mut Context<Self>,
11110    ) -> Option<(Anchor, Breakpoint)> {
11111        let buffer = self
11112            .buffer
11113            .read(cx)
11114            .buffer_for_anchor(breakpoint_position, cx)?;
11115
11116        let enclosing_excerpt = breakpoint_position.excerpt_id;
11117        let buffer_snapshot = buffer.read(cx).snapshot();
11118
11119        let row = buffer_snapshot
11120            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11121            .row;
11122
11123        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11124        let anchor_end = snapshot
11125            .buffer_snapshot()
11126            .anchor_after(Point::new(row, line_len));
11127
11128        self.breakpoint_store
11129            .as_ref()?
11130            .read_with(cx, |breakpoint_store, cx| {
11131                breakpoint_store
11132                    .breakpoints(
11133                        &buffer,
11134                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11135                        &buffer_snapshot,
11136                        cx,
11137                    )
11138                    .next()
11139                    .and_then(|(bp, _)| {
11140                        let breakpoint_row = buffer_snapshot
11141                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11142                            .row;
11143
11144                        if breakpoint_row == row {
11145                            snapshot
11146                                .buffer_snapshot()
11147                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11148                                .map(|position| (position, bp.bp.clone()))
11149                        } else {
11150                            None
11151                        }
11152                    })
11153            })
11154    }
11155
11156    pub fn edit_log_breakpoint(
11157        &mut self,
11158        _: &EditLogBreakpoint,
11159        window: &mut Window,
11160        cx: &mut Context<Self>,
11161    ) {
11162        if self.breakpoint_store.is_none() {
11163            return;
11164        }
11165
11166        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11167            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11168                message: None,
11169                state: BreakpointState::Enabled,
11170                condition: None,
11171                hit_condition: None,
11172            });
11173
11174            self.add_edit_breakpoint_block(
11175                anchor,
11176                &breakpoint,
11177                BreakpointPromptEditAction::Log,
11178                window,
11179                cx,
11180            );
11181        }
11182    }
11183
11184    fn breakpoints_at_cursors(
11185        &self,
11186        window: &mut Window,
11187        cx: &mut Context<Self>,
11188    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11189        let snapshot = self.snapshot(window, cx);
11190        let cursors = self
11191            .selections
11192            .disjoint_anchors_arc()
11193            .iter()
11194            .map(|selection| {
11195                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11196
11197                let breakpoint_position = self
11198                    .breakpoint_at_row(cursor_position.row, window, cx)
11199                    .map(|bp| bp.0)
11200                    .unwrap_or_else(|| {
11201                        snapshot
11202                            .display_snapshot
11203                            .buffer_snapshot()
11204                            .anchor_after(Point::new(cursor_position.row, 0))
11205                    });
11206
11207                let breakpoint = self
11208                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11209                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11210
11211                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11212            })
11213            // 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.
11214            .collect::<HashMap<Anchor, _>>();
11215
11216        cursors.into_iter().collect()
11217    }
11218
11219    pub fn enable_breakpoint(
11220        &mut self,
11221        _: &crate::actions::EnableBreakpoint,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        if self.breakpoint_store.is_none() {
11226            return;
11227        }
11228
11229        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11230            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11231                continue;
11232            };
11233            self.edit_breakpoint_at_anchor(
11234                anchor,
11235                breakpoint,
11236                BreakpointEditAction::InvertState,
11237                cx,
11238            );
11239        }
11240    }
11241
11242    pub fn disable_breakpoint(
11243        &mut self,
11244        _: &crate::actions::DisableBreakpoint,
11245        window: &mut Window,
11246        cx: &mut Context<Self>,
11247    ) {
11248        if self.breakpoint_store.is_none() {
11249            return;
11250        }
11251
11252        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11253            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11254                continue;
11255            };
11256            self.edit_breakpoint_at_anchor(
11257                anchor,
11258                breakpoint,
11259                BreakpointEditAction::InvertState,
11260                cx,
11261            );
11262        }
11263    }
11264
11265    pub fn toggle_breakpoint(
11266        &mut self,
11267        _: &crate::actions::ToggleBreakpoint,
11268        window: &mut Window,
11269        cx: &mut Context<Self>,
11270    ) {
11271        if self.breakpoint_store.is_none() {
11272            return;
11273        }
11274
11275        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11276            if let Some(breakpoint) = breakpoint {
11277                self.edit_breakpoint_at_anchor(
11278                    anchor,
11279                    breakpoint,
11280                    BreakpointEditAction::Toggle,
11281                    cx,
11282                );
11283            } else {
11284                self.edit_breakpoint_at_anchor(
11285                    anchor,
11286                    Breakpoint::new_standard(),
11287                    BreakpointEditAction::Toggle,
11288                    cx,
11289                );
11290            }
11291        }
11292    }
11293
11294    pub fn edit_breakpoint_at_anchor(
11295        &mut self,
11296        breakpoint_position: Anchor,
11297        breakpoint: Breakpoint,
11298        edit_action: BreakpointEditAction,
11299        cx: &mut Context<Self>,
11300    ) {
11301        let Some(breakpoint_store) = &self.breakpoint_store else {
11302            return;
11303        };
11304
11305        let Some(buffer) = self
11306            .buffer
11307            .read(cx)
11308            .buffer_for_anchor(breakpoint_position, cx)
11309        else {
11310            return;
11311        };
11312
11313        breakpoint_store.update(cx, |breakpoint_store, cx| {
11314            breakpoint_store.toggle_breakpoint(
11315                buffer,
11316                BreakpointWithPosition {
11317                    position: breakpoint_position.text_anchor,
11318                    bp: breakpoint,
11319                },
11320                edit_action,
11321                cx,
11322            );
11323        });
11324
11325        cx.notify();
11326    }
11327
11328    #[cfg(any(test, feature = "test-support"))]
11329    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11330        self.breakpoint_store.clone()
11331    }
11332
11333    pub fn prepare_restore_change(
11334        &self,
11335        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11336        hunk: &MultiBufferDiffHunk,
11337        cx: &mut App,
11338    ) -> Option<()> {
11339        if hunk.is_created_file() {
11340            return None;
11341        }
11342        let buffer = self.buffer.read(cx);
11343        let diff = buffer.diff_for(hunk.buffer_id)?;
11344        let buffer = buffer.buffer(hunk.buffer_id)?;
11345        let buffer = buffer.read(cx);
11346        let original_text = diff
11347            .read(cx)
11348            .base_text()
11349            .as_rope()
11350            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11351        let buffer_snapshot = buffer.snapshot();
11352        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11353        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11354            probe
11355                .0
11356                .start
11357                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11358                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11359        }) {
11360            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11361            Some(())
11362        } else {
11363            None
11364        }
11365    }
11366
11367    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11368        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11369    }
11370
11371    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11372        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11373    }
11374
11375    fn manipulate_lines<M>(
11376        &mut self,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379        mut manipulate: M,
11380    ) where
11381        M: FnMut(&str) -> LineManipulationResult,
11382    {
11383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11384
11385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11386        let buffer = self.buffer.read(cx).snapshot(cx);
11387
11388        let mut edits = Vec::new();
11389
11390        let selections = self.selections.all::<Point>(&display_map);
11391        let mut selections = selections.iter().peekable();
11392        let mut contiguous_row_selections = Vec::new();
11393        let mut new_selections = Vec::new();
11394        let mut added_lines = 0;
11395        let mut removed_lines = 0;
11396
11397        while let Some(selection) = selections.next() {
11398            let (start_row, end_row) = consume_contiguous_rows(
11399                &mut contiguous_row_selections,
11400                selection,
11401                &display_map,
11402                &mut selections,
11403            );
11404
11405            let start_point = Point::new(start_row.0, 0);
11406            let end_point = Point::new(
11407                end_row.previous_row().0,
11408                buffer.line_len(end_row.previous_row()),
11409            );
11410            let text = buffer
11411                .text_for_range(start_point..end_point)
11412                .collect::<String>();
11413
11414            let LineManipulationResult {
11415                new_text,
11416                line_count_before,
11417                line_count_after,
11418            } = manipulate(&text);
11419
11420            edits.push((start_point..end_point, new_text));
11421
11422            // Selections must change based on added and removed line count
11423            let start_row =
11424                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11425            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11426            new_selections.push(Selection {
11427                id: selection.id,
11428                start: start_row,
11429                end: end_row,
11430                goal: SelectionGoal::None,
11431                reversed: selection.reversed,
11432            });
11433
11434            if line_count_after > line_count_before {
11435                added_lines += line_count_after - line_count_before;
11436            } else if line_count_before > line_count_after {
11437                removed_lines += line_count_before - line_count_after;
11438            }
11439        }
11440
11441        self.transact(window, cx, |this, window, cx| {
11442            let buffer = this.buffer.update(cx, |buffer, cx| {
11443                buffer.edit(edits, None, cx);
11444                buffer.snapshot(cx)
11445            });
11446
11447            // Recalculate offsets on newly edited buffer
11448            let new_selections = new_selections
11449                .iter()
11450                .map(|s| {
11451                    let start_point = Point::new(s.start.0, 0);
11452                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11453                    Selection {
11454                        id: s.id,
11455                        start: buffer.point_to_offset(start_point),
11456                        end: buffer.point_to_offset(end_point),
11457                        goal: s.goal,
11458                        reversed: s.reversed,
11459                    }
11460                })
11461                .collect();
11462
11463            this.change_selections(Default::default(), window, cx, |s| {
11464                s.select(new_selections);
11465            });
11466
11467            this.request_autoscroll(Autoscroll::fit(), cx);
11468        });
11469    }
11470
11471    fn manipulate_immutable_lines<Fn>(
11472        &mut self,
11473        window: &mut Window,
11474        cx: &mut Context<Self>,
11475        mut callback: Fn,
11476    ) where
11477        Fn: FnMut(&mut Vec<&str>),
11478    {
11479        self.manipulate_lines(window, cx, |text| {
11480            let mut lines: Vec<&str> = text.split('\n').collect();
11481            let line_count_before = lines.len();
11482
11483            callback(&mut lines);
11484
11485            LineManipulationResult {
11486                new_text: lines.join("\n"),
11487                line_count_before,
11488                line_count_after: lines.len(),
11489            }
11490        });
11491    }
11492
11493    fn manipulate_mutable_lines<Fn>(
11494        &mut self,
11495        window: &mut Window,
11496        cx: &mut Context<Self>,
11497        mut callback: Fn,
11498    ) where
11499        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11500    {
11501        self.manipulate_lines(window, cx, |text| {
11502            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11503            let line_count_before = lines.len();
11504
11505            callback(&mut lines);
11506
11507            LineManipulationResult {
11508                new_text: lines.join("\n"),
11509                line_count_before,
11510                line_count_after: lines.len(),
11511            }
11512        });
11513    }
11514
11515    pub fn convert_indentation_to_spaces(
11516        &mut self,
11517        _: &ConvertIndentationToSpaces,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        let settings = self.buffer.read(cx).language_settings(cx);
11522        let tab_size = settings.tab_size.get() as usize;
11523
11524        self.manipulate_mutable_lines(window, cx, |lines| {
11525            // Allocates a reasonably sized scratch buffer once for the whole loop
11526            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11527            // Avoids recomputing spaces that could be inserted many times
11528            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11529                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11530                .collect();
11531
11532            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11533                let mut chars = line.as_ref().chars();
11534                let mut col = 0;
11535                let mut changed = false;
11536
11537                for ch in chars.by_ref() {
11538                    match ch {
11539                        ' ' => {
11540                            reindented_line.push(' ');
11541                            col += 1;
11542                        }
11543                        '\t' => {
11544                            // \t are converted to spaces depending on the current column
11545                            let spaces_len = tab_size - (col % tab_size);
11546                            reindented_line.extend(&space_cache[spaces_len - 1]);
11547                            col += spaces_len;
11548                            changed = true;
11549                        }
11550                        _ => {
11551                            // If we dont append before break, the character is consumed
11552                            reindented_line.push(ch);
11553                            break;
11554                        }
11555                    }
11556                }
11557
11558                if !changed {
11559                    reindented_line.clear();
11560                    continue;
11561                }
11562                // Append the rest of the line and replace old reference with new one
11563                reindented_line.extend(chars);
11564                *line = Cow::Owned(reindented_line.clone());
11565                reindented_line.clear();
11566            }
11567        });
11568    }
11569
11570    pub fn convert_indentation_to_tabs(
11571        &mut self,
11572        _: &ConvertIndentationToTabs,
11573        window: &mut Window,
11574        cx: &mut Context<Self>,
11575    ) {
11576        let settings = self.buffer.read(cx).language_settings(cx);
11577        let tab_size = settings.tab_size.get() as usize;
11578
11579        self.manipulate_mutable_lines(window, cx, |lines| {
11580            // Allocates a reasonably sized buffer once for the whole loop
11581            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11582            // Avoids recomputing spaces that could be inserted many times
11583            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11584                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11585                .collect();
11586
11587            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11588                let mut chars = line.chars();
11589                let mut spaces_count = 0;
11590                let mut first_non_indent_char = None;
11591                let mut changed = false;
11592
11593                for ch in chars.by_ref() {
11594                    match ch {
11595                        ' ' => {
11596                            // Keep track of spaces. Append \t when we reach tab_size
11597                            spaces_count += 1;
11598                            changed = true;
11599                            if spaces_count == tab_size {
11600                                reindented_line.push('\t');
11601                                spaces_count = 0;
11602                            }
11603                        }
11604                        '\t' => {
11605                            reindented_line.push('\t');
11606                            spaces_count = 0;
11607                        }
11608                        _ => {
11609                            // Dont append it yet, we might have remaining spaces
11610                            first_non_indent_char = Some(ch);
11611                            break;
11612                        }
11613                    }
11614                }
11615
11616                if !changed {
11617                    reindented_line.clear();
11618                    continue;
11619                }
11620                // Remaining spaces that didn't make a full tab stop
11621                if spaces_count > 0 {
11622                    reindented_line.extend(&space_cache[spaces_count - 1]);
11623                }
11624                // If we consume an extra character that was not indentation, add it back
11625                if let Some(extra_char) = first_non_indent_char {
11626                    reindented_line.push(extra_char);
11627                }
11628                // Append the rest of the line and replace old reference with new one
11629                reindented_line.extend(chars);
11630                *line = Cow::Owned(reindented_line.clone());
11631                reindented_line.clear();
11632            }
11633        });
11634    }
11635
11636    pub fn convert_to_upper_case(
11637        &mut self,
11638        _: &ConvertToUpperCase,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.manipulate_text(window, cx, |text| text.to_uppercase())
11643    }
11644
11645    pub fn convert_to_lower_case(
11646        &mut self,
11647        _: &ConvertToLowerCase,
11648        window: &mut Window,
11649        cx: &mut Context<Self>,
11650    ) {
11651        self.manipulate_text(window, cx, |text| text.to_lowercase())
11652    }
11653
11654    pub fn convert_to_title_case(
11655        &mut self,
11656        _: &ConvertToTitleCase,
11657        window: &mut Window,
11658        cx: &mut Context<Self>,
11659    ) {
11660        self.manipulate_text(window, cx, |text| {
11661            text.split('\n')
11662                .map(|line| line.to_case(Case::Title))
11663                .join("\n")
11664        })
11665    }
11666
11667    pub fn convert_to_snake_case(
11668        &mut self,
11669        _: &ConvertToSnakeCase,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11674    }
11675
11676    pub fn convert_to_kebab_case(
11677        &mut self,
11678        _: &ConvertToKebabCase,
11679        window: &mut Window,
11680        cx: &mut Context<Self>,
11681    ) {
11682        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11683    }
11684
11685    pub fn convert_to_upper_camel_case(
11686        &mut self,
11687        _: &ConvertToUpperCamelCase,
11688        window: &mut Window,
11689        cx: &mut Context<Self>,
11690    ) {
11691        self.manipulate_text(window, cx, |text| {
11692            text.split('\n')
11693                .map(|line| line.to_case(Case::UpperCamel))
11694                .join("\n")
11695        })
11696    }
11697
11698    pub fn convert_to_lower_camel_case(
11699        &mut self,
11700        _: &ConvertToLowerCamelCase,
11701        window: &mut Window,
11702        cx: &mut Context<Self>,
11703    ) {
11704        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11705    }
11706
11707    pub fn convert_to_opposite_case(
11708        &mut self,
11709        _: &ConvertToOppositeCase,
11710        window: &mut Window,
11711        cx: &mut Context<Self>,
11712    ) {
11713        self.manipulate_text(window, cx, |text| {
11714            text.chars()
11715                .fold(String::with_capacity(text.len()), |mut t, c| {
11716                    if c.is_uppercase() {
11717                        t.extend(c.to_lowercase());
11718                    } else {
11719                        t.extend(c.to_uppercase());
11720                    }
11721                    t
11722                })
11723        })
11724    }
11725
11726    pub fn convert_to_sentence_case(
11727        &mut self,
11728        _: &ConvertToSentenceCase,
11729        window: &mut Window,
11730        cx: &mut Context<Self>,
11731    ) {
11732        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11733    }
11734
11735    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11736        self.manipulate_text(window, cx, |text| {
11737            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11738            if has_upper_case_characters {
11739                text.to_lowercase()
11740            } else {
11741                text.to_uppercase()
11742            }
11743        })
11744    }
11745
11746    pub fn convert_to_rot13(
11747        &mut self,
11748        _: &ConvertToRot13,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.manipulate_text(window, cx, |text| {
11753            text.chars()
11754                .map(|c| match c {
11755                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11756                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11757                    _ => c,
11758                })
11759                .collect()
11760        })
11761    }
11762
11763    pub fn convert_to_rot47(
11764        &mut self,
11765        _: &ConvertToRot47,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        self.manipulate_text(window, cx, |text| {
11770            text.chars()
11771                .map(|c| {
11772                    let code_point = c as u32;
11773                    if code_point >= 33 && code_point <= 126 {
11774                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11775                    }
11776                    c
11777                })
11778                .collect()
11779        })
11780    }
11781
11782    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11783    where
11784        Fn: FnMut(&str) -> String,
11785    {
11786        let buffer = self.buffer.read(cx).snapshot(cx);
11787
11788        let mut new_selections = Vec::new();
11789        let mut edits = Vec::new();
11790        let mut selection_adjustment = 0isize;
11791
11792        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11793            let selection_is_empty = selection.is_empty();
11794
11795            let (start, end) = if selection_is_empty {
11796                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11797                (word_range.start, word_range.end)
11798            } else {
11799                (
11800                    buffer.point_to_offset(selection.start),
11801                    buffer.point_to_offset(selection.end),
11802                )
11803            };
11804
11805            let text = buffer.text_for_range(start..end).collect::<String>();
11806            let old_length = text.len() as isize;
11807            let text = callback(&text);
11808
11809            new_selections.push(Selection {
11810                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11811                end: MultiBufferOffset(
11812                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11813                ),
11814                goal: SelectionGoal::None,
11815                id: selection.id,
11816                reversed: selection.reversed,
11817            });
11818
11819            selection_adjustment += old_length - text.len() as isize;
11820
11821            edits.push((start..end, text));
11822        }
11823
11824        self.transact(window, cx, |this, window, cx| {
11825            this.buffer.update(cx, |buffer, cx| {
11826                buffer.edit(edits, None, cx);
11827            });
11828
11829            this.change_selections(Default::default(), window, cx, |s| {
11830                s.select(new_selections);
11831            });
11832
11833            this.request_autoscroll(Autoscroll::fit(), cx);
11834        });
11835    }
11836
11837    pub fn move_selection_on_drop(
11838        &mut self,
11839        selection: &Selection<Anchor>,
11840        target: DisplayPoint,
11841        is_cut: bool,
11842        window: &mut Window,
11843        cx: &mut Context<Self>,
11844    ) {
11845        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11846        let buffer = display_map.buffer_snapshot();
11847        let mut edits = Vec::new();
11848        let insert_point = display_map
11849            .clip_point(target, Bias::Left)
11850            .to_point(&display_map);
11851        let text = buffer
11852            .text_for_range(selection.start..selection.end)
11853            .collect::<String>();
11854        if is_cut {
11855            edits.push(((selection.start..selection.end), String::new()));
11856        }
11857        let insert_anchor = buffer.anchor_before(insert_point);
11858        edits.push(((insert_anchor..insert_anchor), text));
11859        let last_edit_start = insert_anchor.bias_left(buffer);
11860        let last_edit_end = insert_anchor.bias_right(buffer);
11861        self.transact(window, cx, |this, window, cx| {
11862            this.buffer.update(cx, |buffer, cx| {
11863                buffer.edit(edits, None, cx);
11864            });
11865            this.change_selections(Default::default(), window, cx, |s| {
11866                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11867            });
11868        });
11869    }
11870
11871    pub fn clear_selection_drag_state(&mut self) {
11872        self.selection_drag_state = SelectionDragState::None;
11873    }
11874
11875    pub fn duplicate(
11876        &mut self,
11877        upwards: bool,
11878        whole_lines: bool,
11879        window: &mut Window,
11880        cx: &mut Context<Self>,
11881    ) {
11882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11883
11884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11885        let buffer = display_map.buffer_snapshot();
11886        let selections = self.selections.all::<Point>(&display_map);
11887
11888        let mut edits = Vec::new();
11889        let mut selections_iter = selections.iter().peekable();
11890        while let Some(selection) = selections_iter.next() {
11891            let mut rows = selection.spanned_rows(false, &display_map);
11892            // duplicate line-wise
11893            if whole_lines || selection.start == selection.end {
11894                // Avoid duplicating the same lines twice.
11895                while let Some(next_selection) = selections_iter.peek() {
11896                    let next_rows = next_selection.spanned_rows(false, &display_map);
11897                    if next_rows.start < rows.end {
11898                        rows.end = next_rows.end;
11899                        selections_iter.next().unwrap();
11900                    } else {
11901                        break;
11902                    }
11903                }
11904
11905                // Copy the text from the selected row region and splice it either at the start
11906                // or end of the region.
11907                let start = Point::new(rows.start.0, 0);
11908                let end = Point::new(
11909                    rows.end.previous_row().0,
11910                    buffer.line_len(rows.end.previous_row()),
11911                );
11912
11913                let mut text = buffer.text_for_range(start..end).collect::<String>();
11914
11915                let insert_location = if upwards {
11916                    // When duplicating upward, we need to insert before the current line.
11917                    // If we're on the last line and it doesn't end with a newline,
11918                    // we need to add a newline before the duplicated content.
11919                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11920                        && buffer.max_point().column > 0
11921                        && !text.ends_with('\n');
11922
11923                    if needs_leading_newline {
11924                        text.insert(0, '\n');
11925                        end
11926                    } else {
11927                        text.push('\n');
11928                        Point::new(rows.start.0, 0)
11929                    }
11930                } else {
11931                    text.push('\n');
11932                    start
11933                };
11934                edits.push((insert_location..insert_location, text));
11935            } else {
11936                // duplicate character-wise
11937                let start = selection.start;
11938                let end = selection.end;
11939                let text = buffer.text_for_range(start..end).collect::<String>();
11940                edits.push((selection.end..selection.end, text));
11941            }
11942        }
11943
11944        self.transact(window, cx, |this, window, cx| {
11945            this.buffer.update(cx, |buffer, cx| {
11946                buffer.edit(edits, None, cx);
11947            });
11948
11949            // When duplicating upward with whole lines, move the cursor to the duplicated line
11950            if upwards && whole_lines {
11951                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11952
11953                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11954                    let mut new_ranges = Vec::new();
11955                    let selections = s.all::<Point>(&display_map);
11956                    let mut selections_iter = selections.iter().peekable();
11957
11958                    while let Some(first_selection) = selections_iter.next() {
11959                        // Group contiguous selections together to find the total row span
11960                        let mut group_selections = vec![first_selection];
11961                        let mut rows = first_selection.spanned_rows(false, &display_map);
11962
11963                        while let Some(next_selection) = selections_iter.peek() {
11964                            let next_rows = next_selection.spanned_rows(false, &display_map);
11965                            if next_rows.start < rows.end {
11966                                rows.end = next_rows.end;
11967                                group_selections.push(selections_iter.next().unwrap());
11968                            } else {
11969                                break;
11970                            }
11971                        }
11972
11973                        let row_count = rows.end.0 - rows.start.0;
11974
11975                        // Move all selections in this group up by the total number of duplicated rows
11976                        for selection in group_selections {
11977                            let new_start = Point::new(
11978                                selection.start.row.saturating_sub(row_count),
11979                                selection.start.column,
11980                            );
11981
11982                            let new_end = Point::new(
11983                                selection.end.row.saturating_sub(row_count),
11984                                selection.end.column,
11985                            );
11986
11987                            new_ranges.push(new_start..new_end);
11988                        }
11989                    }
11990
11991                    s.select_ranges(new_ranges);
11992                });
11993            }
11994
11995            this.request_autoscroll(Autoscroll::fit(), cx);
11996        });
11997    }
11998
11999    pub fn duplicate_line_up(
12000        &mut self,
12001        _: &DuplicateLineUp,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.duplicate(true, true, window, cx);
12006    }
12007
12008    pub fn duplicate_line_down(
12009        &mut self,
12010        _: &DuplicateLineDown,
12011        window: &mut Window,
12012        cx: &mut Context<Self>,
12013    ) {
12014        self.duplicate(false, true, window, cx);
12015    }
12016
12017    pub fn duplicate_selection(
12018        &mut self,
12019        _: &DuplicateSelection,
12020        window: &mut Window,
12021        cx: &mut Context<Self>,
12022    ) {
12023        self.duplicate(false, false, window, cx);
12024    }
12025
12026    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12028        if self.mode.is_single_line() {
12029            cx.propagate();
12030            return;
12031        }
12032
12033        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12034        let buffer = self.buffer.read(cx).snapshot(cx);
12035
12036        let mut edits = Vec::new();
12037        let mut unfold_ranges = Vec::new();
12038        let mut refold_creases = Vec::new();
12039
12040        let selections = self.selections.all::<Point>(&display_map);
12041        let mut selections = selections.iter().peekable();
12042        let mut contiguous_row_selections = Vec::new();
12043        let mut new_selections = Vec::new();
12044
12045        while let Some(selection) = selections.next() {
12046            // Find all the selections that span a contiguous row range
12047            let (start_row, end_row) = consume_contiguous_rows(
12048                &mut contiguous_row_selections,
12049                selection,
12050                &display_map,
12051                &mut selections,
12052            );
12053
12054            // Move the text spanned by the row range to be before the line preceding the row range
12055            if start_row.0 > 0 {
12056                let range_to_move = Point::new(
12057                    start_row.previous_row().0,
12058                    buffer.line_len(start_row.previous_row()),
12059                )
12060                    ..Point::new(
12061                        end_row.previous_row().0,
12062                        buffer.line_len(end_row.previous_row()),
12063                    );
12064                let insertion_point = display_map
12065                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12066                    .0;
12067
12068                // Don't move lines across excerpts
12069                if buffer
12070                    .excerpt_containing(insertion_point..range_to_move.end)
12071                    .is_some()
12072                {
12073                    let text = buffer
12074                        .text_for_range(range_to_move.clone())
12075                        .flat_map(|s| s.chars())
12076                        .skip(1)
12077                        .chain(['\n'])
12078                        .collect::<String>();
12079
12080                    edits.push((
12081                        buffer.anchor_after(range_to_move.start)
12082                            ..buffer.anchor_before(range_to_move.end),
12083                        String::new(),
12084                    ));
12085                    let insertion_anchor = buffer.anchor_after(insertion_point);
12086                    edits.push((insertion_anchor..insertion_anchor, text));
12087
12088                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12089
12090                    // Move selections up
12091                    new_selections.extend(contiguous_row_selections.drain(..).map(
12092                        |mut selection| {
12093                            selection.start.row -= row_delta;
12094                            selection.end.row -= row_delta;
12095                            selection
12096                        },
12097                    ));
12098
12099                    // Move folds up
12100                    unfold_ranges.push(range_to_move.clone());
12101                    for fold in display_map.folds_in_range(
12102                        buffer.anchor_before(range_to_move.start)
12103                            ..buffer.anchor_after(range_to_move.end),
12104                    ) {
12105                        let mut start = fold.range.start.to_point(&buffer);
12106                        let mut end = fold.range.end.to_point(&buffer);
12107                        start.row -= row_delta;
12108                        end.row -= row_delta;
12109                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12110                    }
12111                }
12112            }
12113
12114            // If we didn't move line(s), preserve the existing selections
12115            new_selections.append(&mut contiguous_row_selections);
12116        }
12117
12118        self.transact(window, cx, |this, window, cx| {
12119            this.unfold_ranges(&unfold_ranges, true, true, cx);
12120            this.buffer.update(cx, |buffer, cx| {
12121                for (range, text) in edits {
12122                    buffer.edit([(range, text)], None, cx);
12123                }
12124            });
12125            this.fold_creases(refold_creases, true, window, cx);
12126            this.change_selections(Default::default(), window, cx, |s| {
12127                s.select(new_selections);
12128            })
12129        });
12130    }
12131
12132    pub fn move_line_down(
12133        &mut self,
12134        _: &MoveLineDown,
12135        window: &mut Window,
12136        cx: &mut Context<Self>,
12137    ) {
12138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12139        if self.mode.is_single_line() {
12140            cx.propagate();
12141            return;
12142        }
12143
12144        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12145        let buffer = self.buffer.read(cx).snapshot(cx);
12146
12147        let mut edits = Vec::new();
12148        let mut unfold_ranges = Vec::new();
12149        let mut refold_creases = Vec::new();
12150
12151        let selections = self.selections.all::<Point>(&display_map);
12152        let mut selections = selections.iter().peekable();
12153        let mut contiguous_row_selections = Vec::new();
12154        let mut new_selections = Vec::new();
12155
12156        while let Some(selection) = selections.next() {
12157            // Find all the selections that span a contiguous row range
12158            let (start_row, end_row) = consume_contiguous_rows(
12159                &mut contiguous_row_selections,
12160                selection,
12161                &display_map,
12162                &mut selections,
12163            );
12164
12165            // Move the text spanned by the row range to be after the last line of the row range
12166            if end_row.0 <= buffer.max_point().row {
12167                let range_to_move =
12168                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12169                let insertion_point = display_map
12170                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12171                    .0;
12172
12173                // Don't move lines across excerpt boundaries
12174                if buffer
12175                    .excerpt_containing(range_to_move.start..insertion_point)
12176                    .is_some()
12177                {
12178                    let mut text = String::from("\n");
12179                    text.extend(buffer.text_for_range(range_to_move.clone()));
12180                    text.pop(); // Drop trailing newline
12181                    edits.push((
12182                        buffer.anchor_after(range_to_move.start)
12183                            ..buffer.anchor_before(range_to_move.end),
12184                        String::new(),
12185                    ));
12186                    let insertion_anchor = buffer.anchor_after(insertion_point);
12187                    edits.push((insertion_anchor..insertion_anchor, text));
12188
12189                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12190
12191                    // Move selections down
12192                    new_selections.extend(contiguous_row_selections.drain(..).map(
12193                        |mut selection| {
12194                            selection.start.row += row_delta;
12195                            selection.end.row += row_delta;
12196                            selection
12197                        },
12198                    ));
12199
12200                    // Move folds down
12201                    unfold_ranges.push(range_to_move.clone());
12202                    for fold in display_map.folds_in_range(
12203                        buffer.anchor_before(range_to_move.start)
12204                            ..buffer.anchor_after(range_to_move.end),
12205                    ) {
12206                        let mut start = fold.range.start.to_point(&buffer);
12207                        let mut end = fold.range.end.to_point(&buffer);
12208                        start.row += row_delta;
12209                        end.row += row_delta;
12210                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12211                    }
12212                }
12213            }
12214
12215            // If we didn't move line(s), preserve the existing selections
12216            new_selections.append(&mut contiguous_row_selections);
12217        }
12218
12219        self.transact(window, cx, |this, window, cx| {
12220            this.unfold_ranges(&unfold_ranges, true, true, cx);
12221            this.buffer.update(cx, |buffer, cx| {
12222                for (range, text) in edits {
12223                    buffer.edit([(range, text)], None, cx);
12224                }
12225            });
12226            this.fold_creases(refold_creases, true, window, cx);
12227            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12228        });
12229    }
12230
12231    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12233        let text_layout_details = &self.text_layout_details(window);
12234        self.transact(window, cx, |this, window, cx| {
12235            let edits = this.change_selections(Default::default(), window, cx, |s| {
12236                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12237                s.move_with(|display_map, selection| {
12238                    if !selection.is_empty() {
12239                        return;
12240                    }
12241
12242                    let mut head = selection.head();
12243                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12244                    if head.column() == display_map.line_len(head.row()) {
12245                        transpose_offset = display_map
12246                            .buffer_snapshot()
12247                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12248                    }
12249
12250                    if transpose_offset == MultiBufferOffset(0) {
12251                        return;
12252                    }
12253
12254                    *head.column_mut() += 1;
12255                    head = display_map.clip_point(head, Bias::Right);
12256                    let goal = SelectionGoal::HorizontalPosition(
12257                        display_map
12258                            .x_for_display_point(head, text_layout_details)
12259                            .into(),
12260                    );
12261                    selection.collapse_to(head, goal);
12262
12263                    let transpose_start = display_map
12264                        .buffer_snapshot()
12265                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12266                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12267                        let transpose_end = display_map
12268                            .buffer_snapshot()
12269                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12270                        if let Some(ch) = display_map
12271                            .buffer_snapshot()
12272                            .chars_at(transpose_start)
12273                            .next()
12274                        {
12275                            edits.push((transpose_start..transpose_offset, String::new()));
12276                            edits.push((transpose_end..transpose_end, ch.to_string()));
12277                        }
12278                    }
12279                });
12280                edits
12281            });
12282            this.buffer
12283                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12284            let selections = this
12285                .selections
12286                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12287            this.change_selections(Default::default(), window, cx, |s| {
12288                s.select(selections);
12289            });
12290        });
12291    }
12292
12293    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12295        if self.mode.is_single_line() {
12296            cx.propagate();
12297            return;
12298        }
12299
12300        self.rewrap_impl(RewrapOptions::default(), cx)
12301    }
12302
12303    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12304        let buffer = self.buffer.read(cx).snapshot(cx);
12305        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12306
12307        #[derive(Clone, Debug, PartialEq)]
12308        enum CommentFormat {
12309            /// single line comment, with prefix for line
12310            Line(String),
12311            /// single line within a block comment, with prefix for line
12312            BlockLine(String),
12313            /// a single line of a block comment that includes the initial delimiter
12314            BlockCommentWithStart(BlockCommentConfig),
12315            /// a single line of a block comment that includes the ending delimiter
12316            BlockCommentWithEnd(BlockCommentConfig),
12317        }
12318
12319        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12320        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12321            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12322                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12323                .peekable();
12324
12325            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12326                row
12327            } else {
12328                return Vec::new();
12329            };
12330
12331            let language_settings = buffer.language_settings_at(selection.head(), cx);
12332            let language_scope = buffer.language_scope_at(selection.head());
12333
12334            let indent_and_prefix_for_row =
12335                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12336                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12337                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12338                        &language_scope
12339                    {
12340                        let indent_end = Point::new(row, indent.len);
12341                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12342                        let line_text_after_indent = buffer
12343                            .text_for_range(indent_end..line_end)
12344                            .collect::<String>();
12345
12346                        let is_within_comment_override = buffer
12347                            .language_scope_at(indent_end)
12348                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12349                        let comment_delimiters = if is_within_comment_override {
12350                            // we are within a comment syntax node, but we don't
12351                            // yet know what kind of comment: block, doc or line
12352                            match (
12353                                language_scope.documentation_comment(),
12354                                language_scope.block_comment(),
12355                            ) {
12356                                (Some(config), _) | (_, Some(config))
12357                                    if buffer.contains_str_at(indent_end, &config.start) =>
12358                                {
12359                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12360                                }
12361                                (Some(config), _) | (_, Some(config))
12362                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12363                                {
12364                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12365                                }
12366                                (Some(config), _) | (_, Some(config))
12367                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12368                                {
12369                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12370                                }
12371                                (_, _) => language_scope
12372                                    .line_comment_prefixes()
12373                                    .iter()
12374                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12375                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12376                            }
12377                        } else {
12378                            // we not in an overridden comment node, but we may
12379                            // be within a non-overridden line comment node
12380                            language_scope
12381                                .line_comment_prefixes()
12382                                .iter()
12383                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12384                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12385                        };
12386
12387                        let rewrap_prefix = language_scope
12388                            .rewrap_prefixes()
12389                            .iter()
12390                            .find_map(|prefix_regex| {
12391                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12392                                    if mat.start() == 0 {
12393                                        Some(mat.as_str().to_string())
12394                                    } else {
12395                                        None
12396                                    }
12397                                })
12398                            })
12399                            .flatten();
12400                        (comment_delimiters, rewrap_prefix)
12401                    } else {
12402                        (None, None)
12403                    };
12404                    (indent, comment_prefix, rewrap_prefix)
12405                };
12406
12407            let mut ranges = Vec::new();
12408            let from_empty_selection = selection.is_empty();
12409
12410            let mut current_range_start = first_row;
12411            let mut prev_row = first_row;
12412            let (
12413                mut current_range_indent,
12414                mut current_range_comment_delimiters,
12415                mut current_range_rewrap_prefix,
12416            ) = indent_and_prefix_for_row(first_row);
12417
12418            for row in non_blank_rows_iter.skip(1) {
12419                let has_paragraph_break = row > prev_row + 1;
12420
12421                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12422                    indent_and_prefix_for_row(row);
12423
12424                let has_indent_change = row_indent != current_range_indent;
12425                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12426
12427                let has_boundary_change = has_comment_change
12428                    || row_rewrap_prefix.is_some()
12429                    || (has_indent_change && current_range_comment_delimiters.is_some());
12430
12431                if has_paragraph_break || has_boundary_change {
12432                    ranges.push((
12433                        language_settings.clone(),
12434                        Point::new(current_range_start, 0)
12435                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12436                        current_range_indent,
12437                        current_range_comment_delimiters.clone(),
12438                        current_range_rewrap_prefix.clone(),
12439                        from_empty_selection,
12440                    ));
12441                    current_range_start = row;
12442                    current_range_indent = row_indent;
12443                    current_range_comment_delimiters = row_comment_delimiters;
12444                    current_range_rewrap_prefix = row_rewrap_prefix;
12445                }
12446                prev_row = row;
12447            }
12448
12449            ranges.push((
12450                language_settings.clone(),
12451                Point::new(current_range_start, 0)
12452                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12453                current_range_indent,
12454                current_range_comment_delimiters,
12455                current_range_rewrap_prefix,
12456                from_empty_selection,
12457            ));
12458
12459            ranges
12460        });
12461
12462        let mut edits = Vec::new();
12463        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12464
12465        for (
12466            language_settings,
12467            wrap_range,
12468            mut indent_size,
12469            comment_prefix,
12470            rewrap_prefix,
12471            from_empty_selection,
12472        ) in wrap_ranges
12473        {
12474            let mut start_row = wrap_range.start.row;
12475            let mut end_row = wrap_range.end.row;
12476
12477            // Skip selections that overlap with a range that has already been rewrapped.
12478            let selection_range = start_row..end_row;
12479            if rewrapped_row_ranges
12480                .iter()
12481                .any(|range| range.overlaps(&selection_range))
12482            {
12483                continue;
12484            }
12485
12486            let tab_size = language_settings.tab_size;
12487
12488            let (line_prefix, inside_comment) = match &comment_prefix {
12489                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12490                    (Some(prefix.as_str()), true)
12491                }
12492                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12493                    (Some(prefix.as_ref()), true)
12494                }
12495                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12496                    start: _,
12497                    end: _,
12498                    prefix,
12499                    tab_size,
12500                })) => {
12501                    indent_size.len += tab_size;
12502                    (Some(prefix.as_ref()), true)
12503                }
12504                None => (None, false),
12505            };
12506            let indent_prefix = indent_size.chars().collect::<String>();
12507            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12508
12509            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12510                RewrapBehavior::InComments => inside_comment,
12511                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12512                RewrapBehavior::Anywhere => true,
12513            };
12514
12515            let should_rewrap = options.override_language_settings
12516                || allow_rewrap_based_on_language
12517                || self.hard_wrap.is_some();
12518            if !should_rewrap {
12519                continue;
12520            }
12521
12522            if from_empty_selection {
12523                'expand_upwards: while start_row > 0 {
12524                    let prev_row = start_row - 1;
12525                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12526                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12527                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12528                    {
12529                        start_row = prev_row;
12530                    } else {
12531                        break 'expand_upwards;
12532                    }
12533                }
12534
12535                'expand_downwards: while end_row < buffer.max_point().row {
12536                    let next_row = end_row + 1;
12537                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12538                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12539                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12540                    {
12541                        end_row = next_row;
12542                    } else {
12543                        break 'expand_downwards;
12544                    }
12545                }
12546            }
12547
12548            let start = Point::new(start_row, 0);
12549            let start_offset = ToOffset::to_offset(&start, &buffer);
12550            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12551            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12552            let mut first_line_delimiter = None;
12553            let mut last_line_delimiter = None;
12554            let Some(lines_without_prefixes) = selection_text
12555                .lines()
12556                .enumerate()
12557                .map(|(ix, line)| {
12558                    let line_trimmed = line.trim_start();
12559                    if rewrap_prefix.is_some() && ix > 0 {
12560                        Ok(line_trimmed)
12561                    } else if let Some(
12562                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12563                            start,
12564                            prefix,
12565                            end,
12566                            tab_size,
12567                        })
12568                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12569                            start,
12570                            prefix,
12571                            end,
12572                            tab_size,
12573                        }),
12574                    ) = &comment_prefix
12575                    {
12576                        let line_trimmed = line_trimmed
12577                            .strip_prefix(start.as_ref())
12578                            .map(|s| {
12579                                let mut indent_size = indent_size;
12580                                indent_size.len -= tab_size;
12581                                let indent_prefix: String = indent_size.chars().collect();
12582                                first_line_delimiter = Some((indent_prefix, start));
12583                                s.trim_start()
12584                            })
12585                            .unwrap_or(line_trimmed);
12586                        let line_trimmed = line_trimmed
12587                            .strip_suffix(end.as_ref())
12588                            .map(|s| {
12589                                last_line_delimiter = Some(end);
12590                                s.trim_end()
12591                            })
12592                            .unwrap_or(line_trimmed);
12593                        let line_trimmed = line_trimmed
12594                            .strip_prefix(prefix.as_ref())
12595                            .unwrap_or(line_trimmed);
12596                        Ok(line_trimmed)
12597                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12598                        line_trimmed.strip_prefix(prefix).with_context(|| {
12599                            format!("line did not start with prefix {prefix:?}: {line:?}")
12600                        })
12601                    } else {
12602                        line_trimmed
12603                            .strip_prefix(&line_prefix.trim_start())
12604                            .with_context(|| {
12605                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12606                            })
12607                    }
12608                })
12609                .collect::<Result<Vec<_>, _>>()
12610                .log_err()
12611            else {
12612                continue;
12613            };
12614
12615            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12616                buffer
12617                    .language_settings_at(Point::new(start_row, 0), cx)
12618                    .preferred_line_length as usize
12619            });
12620
12621            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12622                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12623            } else {
12624                line_prefix.clone()
12625            };
12626
12627            let wrapped_text = {
12628                let mut wrapped_text = wrap_with_prefix(
12629                    line_prefix,
12630                    subsequent_lines_prefix,
12631                    lines_without_prefixes.join("\n"),
12632                    wrap_column,
12633                    tab_size,
12634                    options.preserve_existing_whitespace,
12635                );
12636
12637                if let Some((indent, delimiter)) = first_line_delimiter {
12638                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12639                }
12640                if let Some(last_line) = last_line_delimiter {
12641                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12642                }
12643
12644                wrapped_text
12645            };
12646
12647            // TODO: should always use char-based diff while still supporting cursor behavior that
12648            // matches vim.
12649            let mut diff_options = DiffOptions::default();
12650            if options.override_language_settings {
12651                diff_options.max_word_diff_len = 0;
12652                diff_options.max_word_diff_line_count = 0;
12653            } else {
12654                diff_options.max_word_diff_len = usize::MAX;
12655                diff_options.max_word_diff_line_count = usize::MAX;
12656            }
12657
12658            for (old_range, new_text) in
12659                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12660            {
12661                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12662                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12663                edits.push((edit_start..edit_end, new_text));
12664            }
12665
12666            rewrapped_row_ranges.push(start_row..=end_row);
12667        }
12668
12669        self.buffer
12670            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12671    }
12672
12673    pub fn cut_common(
12674        &mut self,
12675        cut_no_selection_line: bool,
12676        window: &mut Window,
12677        cx: &mut Context<Self>,
12678    ) -> ClipboardItem {
12679        let mut text = String::new();
12680        let buffer = self.buffer.read(cx).snapshot(cx);
12681        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12682        let mut clipboard_selections = Vec::with_capacity(selections.len());
12683        {
12684            let max_point = buffer.max_point();
12685            let mut is_first = true;
12686            let mut prev_selection_was_entire_line = false;
12687            for selection in &mut selections {
12688                let is_entire_line =
12689                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12690                if is_entire_line {
12691                    selection.start = Point::new(selection.start.row, 0);
12692                    if !selection.is_empty() && selection.end.column == 0 {
12693                        selection.end = cmp::min(max_point, selection.end);
12694                    } else {
12695                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12696                    }
12697                    selection.goal = SelectionGoal::None;
12698                }
12699                if is_first {
12700                    is_first = false;
12701                } else if !prev_selection_was_entire_line {
12702                    text += "\n";
12703                }
12704                prev_selection_was_entire_line = is_entire_line;
12705                let mut len = 0;
12706                for chunk in buffer.text_for_range(selection.start..selection.end) {
12707                    text.push_str(chunk);
12708                    len += chunk.len();
12709                }
12710                clipboard_selections.push(ClipboardSelection {
12711                    len,
12712                    is_entire_line,
12713                    first_line_indent: buffer
12714                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12715                        .len,
12716                });
12717            }
12718        }
12719
12720        self.transact(window, cx, |this, window, cx| {
12721            this.change_selections(Default::default(), window, cx, |s| {
12722                s.select(selections);
12723            });
12724            this.insert("", window, cx);
12725        });
12726        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12727    }
12728
12729    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12731        let item = self.cut_common(true, window, cx);
12732        cx.write_to_clipboard(item);
12733    }
12734
12735    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12737        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12738            s.move_with(|snapshot, sel| {
12739                if sel.is_empty() {
12740                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12741                }
12742                if sel.is_empty() {
12743                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12744                }
12745            });
12746        });
12747        let item = self.cut_common(false, window, cx);
12748        cx.set_global(KillRing(item))
12749    }
12750
12751    pub fn kill_ring_yank(
12752        &mut self,
12753        _: &KillRingYank,
12754        window: &mut Window,
12755        cx: &mut Context<Self>,
12756    ) {
12757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12758        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12759            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12760                (kill_ring.text().to_string(), kill_ring.metadata_json())
12761            } else {
12762                return;
12763            }
12764        } else {
12765            return;
12766        };
12767        self.do_paste(&text, metadata, false, window, cx);
12768    }
12769
12770    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12771        self.do_copy(true, cx);
12772    }
12773
12774    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12775        self.do_copy(false, cx);
12776    }
12777
12778    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12779        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12780        let buffer = self.buffer.read(cx).read(cx);
12781        let mut text = String::new();
12782
12783        let mut clipboard_selections = Vec::with_capacity(selections.len());
12784        {
12785            let max_point = buffer.max_point();
12786            let mut is_first = true;
12787            let mut prev_selection_was_entire_line = false;
12788            for selection in &selections {
12789                let mut start = selection.start;
12790                let mut end = selection.end;
12791                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12792                let mut add_trailing_newline = false;
12793                if is_entire_line {
12794                    start = Point::new(start.row, 0);
12795                    let next_line_start = Point::new(end.row + 1, 0);
12796                    if next_line_start <= max_point {
12797                        end = next_line_start;
12798                    } else {
12799                        // We're on the last line without a trailing newline.
12800                        // Copy to the end of the line and add a newline afterwards.
12801                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12802                        add_trailing_newline = true;
12803                    }
12804                }
12805
12806                let mut trimmed_selections = Vec::new();
12807                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12808                    let row = MultiBufferRow(start.row);
12809                    let first_indent = buffer.indent_size_for_line(row);
12810                    if first_indent.len == 0 || start.column > first_indent.len {
12811                        trimmed_selections.push(start..end);
12812                    } else {
12813                        trimmed_selections.push(
12814                            Point::new(row.0, first_indent.len)
12815                                ..Point::new(row.0, buffer.line_len(row)),
12816                        );
12817                        for row in start.row + 1..=end.row {
12818                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12819                            if row == end.row {
12820                                line_len = end.column;
12821                            }
12822                            if line_len == 0 {
12823                                trimmed_selections
12824                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12825                                continue;
12826                            }
12827                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12828                            if row_indent_size.len >= first_indent.len {
12829                                trimmed_selections.push(
12830                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12831                                );
12832                            } else {
12833                                trimmed_selections.clear();
12834                                trimmed_selections.push(start..end);
12835                                break;
12836                            }
12837                        }
12838                    }
12839                } else {
12840                    trimmed_selections.push(start..end);
12841                }
12842
12843                for trimmed_range in trimmed_selections {
12844                    if is_first {
12845                        is_first = false;
12846                    } else if !prev_selection_was_entire_line {
12847                        text += "\n";
12848                    }
12849                    prev_selection_was_entire_line = is_entire_line;
12850                    let mut len = 0;
12851                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12852                        text.push_str(chunk);
12853                        len += chunk.len();
12854                    }
12855                    if add_trailing_newline {
12856                        text.push('\n');
12857                        len += 1;
12858                    }
12859                    clipboard_selections.push(ClipboardSelection {
12860                        len,
12861                        is_entire_line,
12862                        first_line_indent: buffer
12863                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12864                            .len,
12865                    });
12866                }
12867            }
12868        }
12869
12870        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12871            text,
12872            clipboard_selections,
12873        ));
12874    }
12875
12876    pub fn do_paste(
12877        &mut self,
12878        text: &String,
12879        clipboard_selections: Option<Vec<ClipboardSelection>>,
12880        handle_entire_lines: bool,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        if self.read_only(cx) {
12885            return;
12886        }
12887
12888        let clipboard_text = Cow::Borrowed(text.as_str());
12889
12890        self.transact(window, cx, |this, window, cx| {
12891            let had_active_edit_prediction = this.has_active_edit_prediction();
12892            let display_map = this.display_snapshot(cx);
12893            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12894            let cursor_offset = this
12895                .selections
12896                .last::<MultiBufferOffset>(&display_map)
12897                .head();
12898
12899            if let Some(mut clipboard_selections) = clipboard_selections {
12900                let all_selections_were_entire_line =
12901                    clipboard_selections.iter().all(|s| s.is_entire_line);
12902                let first_selection_indent_column =
12903                    clipboard_selections.first().map(|s| s.first_line_indent);
12904                if clipboard_selections.len() != old_selections.len() {
12905                    clipboard_selections.drain(..);
12906                }
12907                let mut auto_indent_on_paste = true;
12908
12909                this.buffer.update(cx, |buffer, cx| {
12910                    let snapshot = buffer.read(cx);
12911                    auto_indent_on_paste = snapshot
12912                        .language_settings_at(cursor_offset, cx)
12913                        .auto_indent_on_paste;
12914
12915                    let mut start_offset = 0;
12916                    let mut edits = Vec::new();
12917                    let mut original_indent_columns = Vec::new();
12918                    for (ix, selection) in old_selections.iter().enumerate() {
12919                        let to_insert;
12920                        let entire_line;
12921                        let original_indent_column;
12922                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12923                            let end_offset = start_offset + clipboard_selection.len;
12924                            to_insert = &clipboard_text[start_offset..end_offset];
12925                            entire_line = clipboard_selection.is_entire_line;
12926                            start_offset = if entire_line {
12927                                end_offset
12928                            } else {
12929                                end_offset + 1
12930                            };
12931                            original_indent_column = Some(clipboard_selection.first_line_indent);
12932                        } else {
12933                            to_insert = &*clipboard_text;
12934                            entire_line = all_selections_were_entire_line;
12935                            original_indent_column = first_selection_indent_column
12936                        }
12937
12938                        let (range, to_insert) =
12939                            if selection.is_empty() && handle_entire_lines && entire_line {
12940                                // If the corresponding selection was empty when this slice of the
12941                                // clipboard text was written, then the entire line containing the
12942                                // selection was copied. If this selection is also currently empty,
12943                                // then paste the line before the current line of the buffer.
12944                                let column = selection.start.to_point(&snapshot).column as usize;
12945                                let line_start = selection.start - column;
12946                                (line_start..line_start, Cow::Borrowed(to_insert))
12947                            } else {
12948                                let language = snapshot.language_at(selection.head());
12949                                let range = selection.range();
12950                                if let Some(language) = language
12951                                    && language.name() == "Markdown".into()
12952                                {
12953                                    edit_for_markdown_paste(
12954                                        &snapshot,
12955                                        range,
12956                                        to_insert,
12957                                        url::Url::parse(to_insert).ok(),
12958                                    )
12959                                } else {
12960                                    (range, Cow::Borrowed(to_insert))
12961                                }
12962                            };
12963
12964                        edits.push((range, to_insert));
12965                        original_indent_columns.push(original_indent_column);
12966                    }
12967                    drop(snapshot);
12968
12969                    buffer.edit(
12970                        edits,
12971                        if auto_indent_on_paste {
12972                            Some(AutoindentMode::Block {
12973                                original_indent_columns,
12974                            })
12975                        } else {
12976                            None
12977                        },
12978                        cx,
12979                    );
12980                });
12981
12982                let selections = this
12983                    .selections
12984                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12985                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12986            } else {
12987                let url = url::Url::parse(&clipboard_text).ok();
12988
12989                let auto_indent_mode = if !clipboard_text.is_empty() {
12990                    Some(AutoindentMode::Block {
12991                        original_indent_columns: Vec::new(),
12992                    })
12993                } else {
12994                    None
12995                };
12996
12997                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12998                    let snapshot = buffer.snapshot(cx);
12999
13000                    let anchors = old_selections
13001                        .iter()
13002                        .map(|s| {
13003                            let anchor = snapshot.anchor_after(s.head());
13004                            s.map(|_| anchor)
13005                        })
13006                        .collect::<Vec<_>>();
13007
13008                    let mut edits = Vec::new();
13009
13010                    for selection in old_selections.iter() {
13011                        let language = snapshot.language_at(selection.head());
13012                        let range = selection.range();
13013
13014                        let (edit_range, edit_text) = if let Some(language) = language
13015                            && language.name() == "Markdown".into()
13016                        {
13017                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13018                        } else {
13019                            (range, clipboard_text.clone())
13020                        };
13021
13022                        edits.push((edit_range, edit_text));
13023                    }
13024
13025                    drop(snapshot);
13026                    buffer.edit(edits, auto_indent_mode, cx);
13027
13028                    anchors
13029                });
13030
13031                this.change_selections(Default::default(), window, cx, |s| {
13032                    s.select_anchors(selection_anchors);
13033                });
13034            }
13035
13036            //   🤔                 |    ..     | show_in_menu |
13037            // | ..                  |   true        true
13038            // | had_edit_prediction |   false       true
13039
13040            let trigger_in_words =
13041                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13042
13043            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13044        });
13045    }
13046
13047    pub fn diff_clipboard_with_selection(
13048        &mut self,
13049        _: &DiffClipboardWithSelection,
13050        window: &mut Window,
13051        cx: &mut Context<Self>,
13052    ) {
13053        let selections = self
13054            .selections
13055            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13056
13057        if selections.is_empty() {
13058            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13059            return;
13060        };
13061
13062        let clipboard_text = match cx.read_from_clipboard() {
13063            Some(item) => match item.entries().first() {
13064                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13065                _ => None,
13066            },
13067            None => None,
13068        };
13069
13070        let Some(clipboard_text) = clipboard_text else {
13071            log::warn!("Clipboard doesn't contain text.");
13072            return;
13073        };
13074
13075        window.dispatch_action(
13076            Box::new(DiffClipboardWithSelectionData {
13077                clipboard_text,
13078                editor: cx.entity(),
13079            }),
13080            cx,
13081        );
13082    }
13083
13084    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13086        if let Some(item) = cx.read_from_clipboard() {
13087            let entries = item.entries();
13088
13089            match entries.first() {
13090                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13091                // of all the pasted entries.
13092                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13093                    .do_paste(
13094                        clipboard_string.text(),
13095                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13096                        true,
13097                        window,
13098                        cx,
13099                    ),
13100                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13101            }
13102        }
13103    }
13104
13105    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13106        if self.read_only(cx) {
13107            return;
13108        }
13109
13110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13111
13112        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13113            if let Some((selections, _)) =
13114                self.selection_history.transaction(transaction_id).cloned()
13115            {
13116                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13117                    s.select_anchors(selections.to_vec());
13118                });
13119            } else {
13120                log::error!(
13121                    "No entry in selection_history found for undo. \
13122                     This may correspond to a bug where undo does not update the selection. \
13123                     If this is occurring, please add details to \
13124                     https://github.com/zed-industries/zed/issues/22692"
13125                );
13126            }
13127            self.request_autoscroll(Autoscroll::fit(), cx);
13128            self.unmark_text(window, cx);
13129            self.refresh_edit_prediction(true, false, window, cx);
13130            cx.emit(EditorEvent::Edited { transaction_id });
13131            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13132        }
13133    }
13134
13135    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13136        if self.read_only(cx) {
13137            return;
13138        }
13139
13140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13141
13142        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13143            if let Some((_, Some(selections))) =
13144                self.selection_history.transaction(transaction_id).cloned()
13145            {
13146                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13147                    s.select_anchors(selections.to_vec());
13148                });
13149            } else {
13150                log::error!(
13151                    "No entry in selection_history found for redo. \
13152                     This may correspond to a bug where undo does not update the selection. \
13153                     If this is occurring, please add details to \
13154                     https://github.com/zed-industries/zed/issues/22692"
13155                );
13156            }
13157            self.request_autoscroll(Autoscroll::fit(), cx);
13158            self.unmark_text(window, cx);
13159            self.refresh_edit_prediction(true, false, window, cx);
13160            cx.emit(EditorEvent::Edited { transaction_id });
13161        }
13162    }
13163
13164    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13165        self.buffer
13166            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13167    }
13168
13169    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13170        self.buffer
13171            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13172    }
13173
13174    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_with(|map, selection| {
13178                let cursor = if selection.is_empty() {
13179                    movement::left(map, selection.start)
13180                } else {
13181                    selection.start
13182                };
13183                selection.collapse_to(cursor, SelectionGoal::None);
13184            });
13185        })
13186    }
13187
13188    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13190        self.change_selections(Default::default(), window, cx, |s| {
13191            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13192        })
13193    }
13194
13195    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13197        self.change_selections(Default::default(), window, cx, |s| {
13198            s.move_with(|map, selection| {
13199                let cursor = if selection.is_empty() {
13200                    movement::right(map, selection.end)
13201                } else {
13202                    selection.end
13203                };
13204                selection.collapse_to(cursor, SelectionGoal::None)
13205            });
13206        })
13207    }
13208
13209    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13211        self.change_selections(Default::default(), window, cx, |s| {
13212            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13213        });
13214    }
13215
13216    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13217        if self.take_rename(true, window, cx).is_some() {
13218            return;
13219        }
13220
13221        if self.mode.is_single_line() {
13222            cx.propagate();
13223            return;
13224        }
13225
13226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13227
13228        let text_layout_details = &self.text_layout_details(window);
13229        let selection_count = self.selections.count();
13230        let first_selection = self.selections.first_anchor();
13231
13232        self.change_selections(Default::default(), window, cx, |s| {
13233            s.move_with(|map, selection| {
13234                if !selection.is_empty() {
13235                    selection.goal = SelectionGoal::None;
13236                }
13237                let (cursor, goal) = movement::up(
13238                    map,
13239                    selection.start,
13240                    selection.goal,
13241                    false,
13242                    text_layout_details,
13243                );
13244                selection.collapse_to(cursor, goal);
13245            });
13246        });
13247
13248        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13249        {
13250            cx.propagate();
13251        }
13252    }
13253
13254    pub fn move_up_by_lines(
13255        &mut self,
13256        action: &MoveUpByLines,
13257        window: &mut Window,
13258        cx: &mut Context<Self>,
13259    ) {
13260        if self.take_rename(true, window, cx).is_some() {
13261            return;
13262        }
13263
13264        if self.mode.is_single_line() {
13265            cx.propagate();
13266            return;
13267        }
13268
13269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13270
13271        let text_layout_details = &self.text_layout_details(window);
13272
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.move_with(|map, selection| {
13275                if !selection.is_empty() {
13276                    selection.goal = SelectionGoal::None;
13277                }
13278                let (cursor, goal) = movement::up_by_rows(
13279                    map,
13280                    selection.start,
13281                    action.lines,
13282                    selection.goal,
13283                    false,
13284                    text_layout_details,
13285                );
13286                selection.collapse_to(cursor, goal);
13287            });
13288        })
13289    }
13290
13291    pub fn move_down_by_lines(
13292        &mut self,
13293        action: &MoveDownByLines,
13294        window: &mut Window,
13295        cx: &mut Context<Self>,
13296    ) {
13297        if self.take_rename(true, window, cx).is_some() {
13298            return;
13299        }
13300
13301        if self.mode.is_single_line() {
13302            cx.propagate();
13303            return;
13304        }
13305
13306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13307
13308        let text_layout_details = &self.text_layout_details(window);
13309
13310        self.change_selections(Default::default(), window, cx, |s| {
13311            s.move_with(|map, selection| {
13312                if !selection.is_empty() {
13313                    selection.goal = SelectionGoal::None;
13314                }
13315                let (cursor, goal) = movement::down_by_rows(
13316                    map,
13317                    selection.start,
13318                    action.lines,
13319                    selection.goal,
13320                    false,
13321                    text_layout_details,
13322                );
13323                selection.collapse_to(cursor, goal);
13324            });
13325        })
13326    }
13327
13328    pub fn select_down_by_lines(
13329        &mut self,
13330        action: &SelectDownByLines,
13331        window: &mut Window,
13332        cx: &mut Context<Self>,
13333    ) {
13334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13335        let text_layout_details = &self.text_layout_details(window);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_heads_with(|map, head, goal| {
13338                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13339            })
13340        })
13341    }
13342
13343    pub fn select_up_by_lines(
13344        &mut self,
13345        action: &SelectUpByLines,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350        let text_layout_details = &self.text_layout_details(window);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_heads_with(|map, head, goal| {
13353                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13354            })
13355        })
13356    }
13357
13358    pub fn select_page_up(
13359        &mut self,
13360        _: &SelectPageUp,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        let Some(row_count) = self.visible_row_count() else {
13365            return;
13366        };
13367
13368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13369
13370        let text_layout_details = &self.text_layout_details(window);
13371
13372        self.change_selections(Default::default(), window, cx, |s| {
13373            s.move_heads_with(|map, head, goal| {
13374                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13375            })
13376        })
13377    }
13378
13379    pub fn move_page_up(
13380        &mut self,
13381        action: &MovePageUp,
13382        window: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) {
13385        if self.take_rename(true, window, cx).is_some() {
13386            return;
13387        }
13388
13389        if self
13390            .context_menu
13391            .borrow_mut()
13392            .as_mut()
13393            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13394            .unwrap_or(false)
13395        {
13396            return;
13397        }
13398
13399        if matches!(self.mode, EditorMode::SingleLine) {
13400            cx.propagate();
13401            return;
13402        }
13403
13404        let Some(row_count) = self.visible_row_count() else {
13405            return;
13406        };
13407
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409
13410        let effects = if action.center_cursor {
13411            SelectionEffects::scroll(Autoscroll::center())
13412        } else {
13413            SelectionEffects::default()
13414        };
13415
13416        let text_layout_details = &self.text_layout_details(window);
13417
13418        self.change_selections(effects, window, cx, |s| {
13419            s.move_with(|map, selection| {
13420                if !selection.is_empty() {
13421                    selection.goal = SelectionGoal::None;
13422                }
13423                let (cursor, goal) = movement::up_by_rows(
13424                    map,
13425                    selection.end,
13426                    row_count,
13427                    selection.goal,
13428                    false,
13429                    text_layout_details,
13430                );
13431                selection.collapse_to(cursor, goal);
13432            });
13433        });
13434    }
13435
13436    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        let text_layout_details = &self.text_layout_details(window);
13439        self.change_selections(Default::default(), window, cx, |s| {
13440            s.move_heads_with(|map, head, goal| {
13441                movement::up(map, head, goal, false, text_layout_details)
13442            })
13443        })
13444    }
13445
13446    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13447        self.take_rename(true, window, cx);
13448
13449        if self.mode.is_single_line() {
13450            cx.propagate();
13451            return;
13452        }
13453
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455
13456        let text_layout_details = &self.text_layout_details(window);
13457        let selection_count = self.selections.count();
13458        let first_selection = self.selections.first_anchor();
13459
13460        self.change_selections(Default::default(), window, cx, |s| {
13461            s.move_with(|map, selection| {
13462                if !selection.is_empty() {
13463                    selection.goal = SelectionGoal::None;
13464                }
13465                let (cursor, goal) = movement::down(
13466                    map,
13467                    selection.end,
13468                    selection.goal,
13469                    false,
13470                    text_layout_details,
13471                );
13472                selection.collapse_to(cursor, goal);
13473            });
13474        });
13475
13476        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13477        {
13478            cx.propagate();
13479        }
13480    }
13481
13482    pub fn select_page_down(
13483        &mut self,
13484        _: &SelectPageDown,
13485        window: &mut Window,
13486        cx: &mut Context<Self>,
13487    ) {
13488        let Some(row_count) = self.visible_row_count() else {
13489            return;
13490        };
13491
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493
13494        let text_layout_details = &self.text_layout_details(window);
13495
13496        self.change_selections(Default::default(), window, cx, |s| {
13497            s.move_heads_with(|map, head, goal| {
13498                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13499            })
13500        })
13501    }
13502
13503    pub fn move_page_down(
13504        &mut self,
13505        action: &MovePageDown,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        if self.take_rename(true, window, cx).is_some() {
13510            return;
13511        }
13512
13513        if self
13514            .context_menu
13515            .borrow_mut()
13516            .as_mut()
13517            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13518            .unwrap_or(false)
13519        {
13520            return;
13521        }
13522
13523        if matches!(self.mode, EditorMode::SingleLine) {
13524            cx.propagate();
13525            return;
13526        }
13527
13528        let Some(row_count) = self.visible_row_count() else {
13529            return;
13530        };
13531
13532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13533
13534        let effects = if action.center_cursor {
13535            SelectionEffects::scroll(Autoscroll::center())
13536        } else {
13537            SelectionEffects::default()
13538        };
13539
13540        let text_layout_details = &self.text_layout_details(window);
13541        self.change_selections(effects, window, cx, |s| {
13542            s.move_with(|map, selection| {
13543                if !selection.is_empty() {
13544                    selection.goal = SelectionGoal::None;
13545                }
13546                let (cursor, goal) = movement::down_by_rows(
13547                    map,
13548                    selection.end,
13549                    row_count,
13550                    selection.goal,
13551                    false,
13552                    text_layout_details,
13553                );
13554                selection.collapse_to(cursor, goal);
13555            });
13556        });
13557    }
13558
13559    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13561        let text_layout_details = &self.text_layout_details(window);
13562        self.change_selections(Default::default(), window, cx, |s| {
13563            s.move_heads_with(|map, head, goal| {
13564                movement::down(map, head, goal, false, text_layout_details)
13565            })
13566        });
13567    }
13568
13569    pub fn context_menu_first(
13570        &mut self,
13571        _: &ContextMenuFirst,
13572        window: &mut Window,
13573        cx: &mut Context<Self>,
13574    ) {
13575        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13576            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13577        }
13578    }
13579
13580    pub fn context_menu_prev(
13581        &mut self,
13582        _: &ContextMenuPrevious,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13587            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13588        }
13589    }
13590
13591    pub fn context_menu_next(
13592        &mut self,
13593        _: &ContextMenuNext,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13598            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13599        }
13600    }
13601
13602    pub fn context_menu_last(
13603        &mut self,
13604        _: &ContextMenuLast,
13605        window: &mut Window,
13606        cx: &mut Context<Self>,
13607    ) {
13608        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13609            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13610        }
13611    }
13612
13613    pub fn signature_help_prev(
13614        &mut self,
13615        _: &SignatureHelpPrevious,
13616        _: &mut Window,
13617        cx: &mut Context<Self>,
13618    ) {
13619        if let Some(popover) = self.signature_help_state.popover_mut() {
13620            if popover.current_signature == 0 {
13621                popover.current_signature = popover.signatures.len() - 1;
13622            } else {
13623                popover.current_signature -= 1;
13624            }
13625            cx.notify();
13626        }
13627    }
13628
13629    pub fn signature_help_next(
13630        &mut self,
13631        _: &SignatureHelpNext,
13632        _: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        if let Some(popover) = self.signature_help_state.popover_mut() {
13636            if popover.current_signature + 1 == popover.signatures.len() {
13637                popover.current_signature = 0;
13638            } else {
13639                popover.current_signature += 1;
13640            }
13641            cx.notify();
13642        }
13643    }
13644
13645    pub fn move_to_previous_word_start(
13646        &mut self,
13647        _: &MoveToPreviousWordStart,
13648        window: &mut Window,
13649        cx: &mut Context<Self>,
13650    ) {
13651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13652        self.change_selections(Default::default(), window, cx, |s| {
13653            s.move_cursors_with(|map, head, _| {
13654                (
13655                    movement::previous_word_start(map, head),
13656                    SelectionGoal::None,
13657                )
13658            });
13659        })
13660    }
13661
13662    pub fn move_to_previous_subword_start(
13663        &mut self,
13664        _: &MoveToPreviousSubwordStart,
13665        window: &mut Window,
13666        cx: &mut Context<Self>,
13667    ) {
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_cursors_with(|map, head, _| {
13671                (
13672                    movement::previous_subword_start(map, head),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn select_to_previous_word_start(
13680        &mut self,
13681        _: &SelectToPreviousWordStart,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_heads_with(|map, head, _| {
13688                (
13689                    movement::previous_word_start(map, head),
13690                    SelectionGoal::None,
13691                )
13692            });
13693        })
13694    }
13695
13696    pub fn select_to_previous_subword_start(
13697        &mut self,
13698        _: &SelectToPreviousSubwordStart,
13699        window: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13703        self.change_selections(Default::default(), window, cx, |s| {
13704            s.move_heads_with(|map, head, _| {
13705                (
13706                    movement::previous_subword_start(map, head),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn delete_to_previous_word_start(
13714        &mut self,
13715        action: &DeleteToPreviousWordStart,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13720        self.transact(window, cx, |this, window, cx| {
13721            this.select_autoclose_pair(window, cx);
13722            this.change_selections(Default::default(), window, cx, |s| {
13723                s.move_with(|map, selection| {
13724                    if selection.is_empty() {
13725                        let mut cursor = if action.ignore_newlines {
13726                            movement::previous_word_start(map, selection.head())
13727                        } else {
13728                            movement::previous_word_start_or_newline(map, selection.head())
13729                        };
13730                        cursor = movement::adjust_greedy_deletion(
13731                            map,
13732                            selection.head(),
13733                            cursor,
13734                            action.ignore_brackets,
13735                        );
13736                        selection.set_head(cursor, SelectionGoal::None);
13737                    }
13738                });
13739            });
13740            this.insert("", window, cx);
13741        });
13742    }
13743
13744    pub fn delete_to_previous_subword_start(
13745        &mut self,
13746        _: &DeleteToPreviousSubwordStart,
13747        window: &mut Window,
13748        cx: &mut Context<Self>,
13749    ) {
13750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13751        self.transact(window, cx, |this, window, cx| {
13752            this.select_autoclose_pair(window, cx);
13753            this.change_selections(Default::default(), window, cx, |s| {
13754                s.move_with(|map, selection| {
13755                    if selection.is_empty() {
13756                        let mut cursor = movement::previous_subword_start(map, selection.head());
13757                        cursor =
13758                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13759                        selection.set_head(cursor, SelectionGoal::None);
13760                    }
13761                });
13762            });
13763            this.insert("", window, cx);
13764        });
13765    }
13766
13767    pub fn move_to_next_word_end(
13768        &mut self,
13769        _: &MoveToNextWordEnd,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_cursors_with(|map, head, _| {
13776                (movement::next_word_end(map, head), SelectionGoal::None)
13777            });
13778        })
13779    }
13780
13781    pub fn move_to_next_subword_end(
13782        &mut self,
13783        _: &MoveToNextSubwordEnd,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13788        self.change_selections(Default::default(), window, cx, |s| {
13789            s.move_cursors_with(|map, head, _| {
13790                (movement::next_subword_end(map, head), SelectionGoal::None)
13791            });
13792        })
13793    }
13794
13795    pub fn select_to_next_word_end(
13796        &mut self,
13797        _: &SelectToNextWordEnd,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.move_heads_with(|map, head, _| {
13804                (movement::next_word_end(map, head), SelectionGoal::None)
13805            });
13806        })
13807    }
13808
13809    pub fn select_to_next_subword_end(
13810        &mut self,
13811        _: &SelectToNextSubwordEnd,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (movement::next_subword_end(map, head), SelectionGoal::None)
13819            });
13820        })
13821    }
13822
13823    pub fn delete_to_next_word_end(
13824        &mut self,
13825        action: &DeleteToNextWordEnd,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13830        self.transact(window, cx, |this, window, cx| {
13831            this.change_selections(Default::default(), window, cx, |s| {
13832                s.move_with(|map, selection| {
13833                    if selection.is_empty() {
13834                        let mut cursor = if action.ignore_newlines {
13835                            movement::next_word_end(map, selection.head())
13836                        } else {
13837                            movement::next_word_end_or_newline(map, selection.head())
13838                        };
13839                        cursor = movement::adjust_greedy_deletion(
13840                            map,
13841                            selection.head(),
13842                            cursor,
13843                            action.ignore_brackets,
13844                        );
13845                        selection.set_head(cursor, SelectionGoal::None);
13846                    }
13847                });
13848            });
13849            this.insert("", window, cx);
13850        });
13851    }
13852
13853    pub fn delete_to_next_subword_end(
13854        &mut self,
13855        _: &DeleteToNextSubwordEnd,
13856        window: &mut Window,
13857        cx: &mut Context<Self>,
13858    ) {
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13860        self.transact(window, cx, |this, window, cx| {
13861            this.change_selections(Default::default(), window, cx, |s| {
13862                s.move_with(|map, selection| {
13863                    if selection.is_empty() {
13864                        let mut cursor = movement::next_subword_end(map, selection.head());
13865                        cursor =
13866                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13867                        selection.set_head(cursor, SelectionGoal::None);
13868                    }
13869                });
13870            });
13871            this.insert("", window, cx);
13872        });
13873    }
13874
13875    pub fn move_to_beginning_of_line(
13876        &mut self,
13877        action: &MoveToBeginningOfLine,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) {
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13882        self.change_selections(Default::default(), window, cx, |s| {
13883            s.move_cursors_with(|map, head, _| {
13884                (
13885                    movement::indented_line_beginning(
13886                        map,
13887                        head,
13888                        action.stop_at_soft_wraps,
13889                        action.stop_at_indent,
13890                    ),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn select_to_beginning_of_line(
13898        &mut self,
13899        action: &SelectToBeginningOfLine,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13904        self.change_selections(Default::default(), window, cx, |s| {
13905            s.move_heads_with(|map, head, _| {
13906                (
13907                    movement::indented_line_beginning(
13908                        map,
13909                        head,
13910                        action.stop_at_soft_wraps,
13911                        action.stop_at_indent,
13912                    ),
13913                    SelectionGoal::None,
13914                )
13915            });
13916        });
13917    }
13918
13919    pub fn delete_to_beginning_of_line(
13920        &mut self,
13921        action: &DeleteToBeginningOfLine,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13926        self.transact(window, cx, |this, window, cx| {
13927            this.change_selections(Default::default(), window, cx, |s| {
13928                s.move_with(|_, selection| {
13929                    selection.reversed = true;
13930                });
13931            });
13932
13933            this.select_to_beginning_of_line(
13934                &SelectToBeginningOfLine {
13935                    stop_at_soft_wraps: false,
13936                    stop_at_indent: action.stop_at_indent,
13937                },
13938                window,
13939                cx,
13940            );
13941            this.backspace(&Backspace, window, cx);
13942        });
13943    }
13944
13945    pub fn move_to_end_of_line(
13946        &mut self,
13947        action: &MoveToEndOfLine,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952        self.change_selections(Default::default(), window, cx, |s| {
13953            s.move_cursors_with(|map, head, _| {
13954                (
13955                    movement::line_end(map, head, action.stop_at_soft_wraps),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn select_to_end_of_line(
13963        &mut self,
13964        action: &SelectToEndOfLine,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        self.change_selections(Default::default(), window, cx, |s| {
13970            s.move_heads_with(|map, head, _| {
13971                (
13972                    movement::line_end(map, head, action.stop_at_soft_wraps),
13973                    SelectionGoal::None,
13974                )
13975            });
13976        })
13977    }
13978
13979    pub fn delete_to_end_of_line(
13980        &mut self,
13981        _: &DeleteToEndOfLine,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13986        self.transact(window, cx, |this, window, cx| {
13987            this.select_to_end_of_line(
13988                &SelectToEndOfLine {
13989                    stop_at_soft_wraps: false,
13990                },
13991                window,
13992                cx,
13993            );
13994            this.delete(&Delete, window, cx);
13995        });
13996    }
13997
13998    pub fn cut_to_end_of_line(
13999        &mut self,
14000        action: &CutToEndOfLine,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14005        self.transact(window, cx, |this, window, cx| {
14006            this.select_to_end_of_line(
14007                &SelectToEndOfLine {
14008                    stop_at_soft_wraps: false,
14009                },
14010                window,
14011                cx,
14012            );
14013            if !action.stop_at_newlines {
14014                this.change_selections(Default::default(), window, cx, |s| {
14015                    s.move_with(|_, sel| {
14016                        if sel.is_empty() {
14017                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14018                        }
14019                    });
14020                });
14021            }
14022            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14023            let item = this.cut_common(false, window, cx);
14024            cx.write_to_clipboard(item);
14025        });
14026    }
14027
14028    pub fn move_to_start_of_paragraph(
14029        &mut self,
14030        _: &MoveToStartOfParagraph,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if matches!(self.mode, EditorMode::SingleLine) {
14035            cx.propagate();
14036            return;
14037        }
14038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14039        self.change_selections(Default::default(), window, cx, |s| {
14040            s.move_with(|map, selection| {
14041                selection.collapse_to(
14042                    movement::start_of_paragraph(map, selection.head(), 1),
14043                    SelectionGoal::None,
14044                )
14045            });
14046        })
14047    }
14048
14049    pub fn move_to_end_of_paragraph(
14050        &mut self,
14051        _: &MoveToEndOfParagraph,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        if matches!(self.mode, EditorMode::SingleLine) {
14056            cx.propagate();
14057            return;
14058        }
14059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14060        self.change_selections(Default::default(), window, cx, |s| {
14061            s.move_with(|map, selection| {
14062                selection.collapse_to(
14063                    movement::end_of_paragraph(map, selection.head(), 1),
14064                    SelectionGoal::None,
14065                )
14066            });
14067        })
14068    }
14069
14070    pub fn select_to_start_of_paragraph(
14071        &mut self,
14072        _: &SelectToStartOfParagraph,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        if matches!(self.mode, EditorMode::SingleLine) {
14077            cx.propagate();
14078            return;
14079        }
14080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14081        self.change_selections(Default::default(), window, cx, |s| {
14082            s.move_heads_with(|map, head, _| {
14083                (
14084                    movement::start_of_paragraph(map, head, 1),
14085                    SelectionGoal::None,
14086                )
14087            });
14088        })
14089    }
14090
14091    pub fn select_to_end_of_paragraph(
14092        &mut self,
14093        _: &SelectToEndOfParagraph,
14094        window: &mut Window,
14095        cx: &mut Context<Self>,
14096    ) {
14097        if matches!(self.mode, EditorMode::SingleLine) {
14098            cx.propagate();
14099            return;
14100        }
14101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14102        self.change_selections(Default::default(), window, cx, |s| {
14103            s.move_heads_with(|map, head, _| {
14104                (
14105                    movement::end_of_paragraph(map, head, 1),
14106                    SelectionGoal::None,
14107                )
14108            });
14109        })
14110    }
14111
14112    pub fn move_to_start_of_excerpt(
14113        &mut self,
14114        _: &MoveToStartOfExcerpt,
14115        window: &mut Window,
14116        cx: &mut Context<Self>,
14117    ) {
14118        if matches!(self.mode, EditorMode::SingleLine) {
14119            cx.propagate();
14120            return;
14121        }
14122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14123        self.change_selections(Default::default(), window, cx, |s| {
14124            s.move_with(|map, selection| {
14125                selection.collapse_to(
14126                    movement::start_of_excerpt(
14127                        map,
14128                        selection.head(),
14129                        workspace::searchable::Direction::Prev,
14130                    ),
14131                    SelectionGoal::None,
14132                )
14133            });
14134        })
14135    }
14136
14137    pub fn move_to_start_of_next_excerpt(
14138        &mut self,
14139        _: &MoveToStartOfNextExcerpt,
14140        window: &mut Window,
14141        cx: &mut Context<Self>,
14142    ) {
14143        if matches!(self.mode, EditorMode::SingleLine) {
14144            cx.propagate();
14145            return;
14146        }
14147
14148        self.change_selections(Default::default(), window, cx, |s| {
14149            s.move_with(|map, selection| {
14150                selection.collapse_to(
14151                    movement::start_of_excerpt(
14152                        map,
14153                        selection.head(),
14154                        workspace::searchable::Direction::Next,
14155                    ),
14156                    SelectionGoal::None,
14157                )
14158            });
14159        })
14160    }
14161
14162    pub fn move_to_end_of_excerpt(
14163        &mut self,
14164        _: &MoveToEndOfExcerpt,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        if matches!(self.mode, EditorMode::SingleLine) {
14169            cx.propagate();
14170            return;
14171        }
14172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.move_with(|map, selection| {
14175                selection.collapse_to(
14176                    movement::end_of_excerpt(
14177                        map,
14178                        selection.head(),
14179                        workspace::searchable::Direction::Next,
14180                    ),
14181                    SelectionGoal::None,
14182                )
14183            });
14184        })
14185    }
14186
14187    pub fn move_to_end_of_previous_excerpt(
14188        &mut self,
14189        _: &MoveToEndOfPreviousExcerpt,
14190        window: &mut Window,
14191        cx: &mut Context<Self>,
14192    ) {
14193        if matches!(self.mode, EditorMode::SingleLine) {
14194            cx.propagate();
14195            return;
14196        }
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198        self.change_selections(Default::default(), window, cx, |s| {
14199            s.move_with(|map, selection| {
14200                selection.collapse_to(
14201                    movement::end_of_excerpt(
14202                        map,
14203                        selection.head(),
14204                        workspace::searchable::Direction::Prev,
14205                    ),
14206                    SelectionGoal::None,
14207                )
14208            });
14209        })
14210    }
14211
14212    pub fn select_to_start_of_excerpt(
14213        &mut self,
14214        _: &SelectToStartOfExcerpt,
14215        window: &mut Window,
14216        cx: &mut Context<Self>,
14217    ) {
14218        if matches!(self.mode, EditorMode::SingleLine) {
14219            cx.propagate();
14220            return;
14221        }
14222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14223        self.change_selections(Default::default(), window, cx, |s| {
14224            s.move_heads_with(|map, head, _| {
14225                (
14226                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14227                    SelectionGoal::None,
14228                )
14229            });
14230        })
14231    }
14232
14233    pub fn select_to_start_of_next_excerpt(
14234        &mut self,
14235        _: &SelectToStartOfNextExcerpt,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        if matches!(self.mode, EditorMode::SingleLine) {
14240            cx.propagate();
14241            return;
14242        }
14243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14244        self.change_selections(Default::default(), window, cx, |s| {
14245            s.move_heads_with(|map, head, _| {
14246                (
14247                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14248                    SelectionGoal::None,
14249                )
14250            });
14251        })
14252    }
14253
14254    pub fn select_to_end_of_excerpt(
14255        &mut self,
14256        _: &SelectToEndOfExcerpt,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        if matches!(self.mode, EditorMode::SingleLine) {
14261            cx.propagate();
14262            return;
14263        }
14264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14265        self.change_selections(Default::default(), window, cx, |s| {
14266            s.move_heads_with(|map, head, _| {
14267                (
14268                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14269                    SelectionGoal::None,
14270                )
14271            });
14272        })
14273    }
14274
14275    pub fn select_to_end_of_previous_excerpt(
14276        &mut self,
14277        _: &SelectToEndOfPreviousExcerpt,
14278        window: &mut Window,
14279        cx: &mut Context<Self>,
14280    ) {
14281        if matches!(self.mode, EditorMode::SingleLine) {
14282            cx.propagate();
14283            return;
14284        }
14285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14286        self.change_selections(Default::default(), window, cx, |s| {
14287            s.move_heads_with(|map, head, _| {
14288                (
14289                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14290                    SelectionGoal::None,
14291                )
14292            });
14293        })
14294    }
14295
14296    pub fn move_to_beginning(
14297        &mut self,
14298        _: &MoveToBeginning,
14299        window: &mut Window,
14300        cx: &mut Context<Self>,
14301    ) {
14302        if matches!(self.mode, EditorMode::SingleLine) {
14303            cx.propagate();
14304            return;
14305        }
14306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14307        self.change_selections(Default::default(), window, cx, |s| {
14308            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14309        });
14310    }
14311
14312    pub fn select_to_beginning(
14313        &mut self,
14314        _: &SelectToBeginning,
14315        window: &mut Window,
14316        cx: &mut Context<Self>,
14317    ) {
14318        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14319        selection.set_head(Point::zero(), SelectionGoal::None);
14320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14321        self.change_selections(Default::default(), window, cx, |s| {
14322            s.select(vec![selection]);
14323        });
14324    }
14325
14326    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14327        if matches!(self.mode, EditorMode::SingleLine) {
14328            cx.propagate();
14329            return;
14330        }
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332        let cursor = self.buffer.read(cx).read(cx).len();
14333        self.change_selections(Default::default(), window, cx, |s| {
14334            s.select_ranges(vec![cursor..cursor])
14335        });
14336    }
14337
14338    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14339        self.nav_history = nav_history;
14340    }
14341
14342    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14343        self.nav_history.as_ref()
14344    }
14345
14346    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14347        self.push_to_nav_history(
14348            self.selections.newest_anchor().head(),
14349            None,
14350            false,
14351            true,
14352            cx,
14353        );
14354    }
14355
14356    fn push_to_nav_history(
14357        &mut self,
14358        cursor_anchor: Anchor,
14359        new_position: Option<Point>,
14360        is_deactivate: bool,
14361        always: bool,
14362        cx: &mut Context<Self>,
14363    ) {
14364        if let Some(nav_history) = self.nav_history.as_mut() {
14365            let buffer = self.buffer.read(cx).read(cx);
14366            let cursor_position = cursor_anchor.to_point(&buffer);
14367            let scroll_state = self.scroll_manager.anchor();
14368            let scroll_top_row = scroll_state.top_row(&buffer);
14369            drop(buffer);
14370
14371            if let Some(new_position) = new_position {
14372                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14373                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14374                    return;
14375                }
14376            }
14377
14378            nav_history.push(
14379                Some(NavigationData {
14380                    cursor_anchor,
14381                    cursor_position,
14382                    scroll_anchor: scroll_state,
14383                    scroll_top_row,
14384                }),
14385                cx,
14386            );
14387            cx.emit(EditorEvent::PushedToNavHistory {
14388                anchor: cursor_anchor,
14389                is_deactivate,
14390            })
14391        }
14392    }
14393
14394    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14396        let buffer = self.buffer.read(cx).snapshot(cx);
14397        let mut selection = self
14398            .selections
14399            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14400        selection.set_head(buffer.len(), SelectionGoal::None);
14401        self.change_selections(Default::default(), window, cx, |s| {
14402            s.select(vec![selection]);
14403        });
14404    }
14405
14406    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14409            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14410        });
14411    }
14412
14413    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14415        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14416        let mut selections = self.selections.all::<Point>(&display_map);
14417        let max_point = display_map.buffer_snapshot().max_point();
14418        for selection in &mut selections {
14419            let rows = selection.spanned_rows(true, &display_map);
14420            selection.start = Point::new(rows.start.0, 0);
14421            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14422            selection.reversed = false;
14423        }
14424        self.change_selections(Default::default(), window, cx, |s| {
14425            s.select(selections);
14426        });
14427    }
14428
14429    pub fn split_selection_into_lines(
14430        &mut self,
14431        action: &SplitSelectionIntoLines,
14432        window: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        let selections = self
14436            .selections
14437            .all::<Point>(&self.display_snapshot(cx))
14438            .into_iter()
14439            .map(|selection| selection.start..selection.end)
14440            .collect::<Vec<_>>();
14441        self.unfold_ranges(&selections, true, true, cx);
14442
14443        let mut new_selection_ranges = Vec::new();
14444        {
14445            let buffer = self.buffer.read(cx).read(cx);
14446            for selection in selections {
14447                for row in selection.start.row..selection.end.row {
14448                    let line_start = Point::new(row, 0);
14449                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14450
14451                    if action.keep_selections {
14452                        // Keep the selection range for each line
14453                        let selection_start = if row == selection.start.row {
14454                            selection.start
14455                        } else {
14456                            line_start
14457                        };
14458                        new_selection_ranges.push(selection_start..line_end);
14459                    } else {
14460                        // Collapse to cursor at end of line
14461                        new_selection_ranges.push(line_end..line_end);
14462                    }
14463                }
14464
14465                let is_multiline_selection = selection.start.row != selection.end.row;
14466                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14467                // so this action feels more ergonomic when paired with other selection operations
14468                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14469                if !should_skip_last {
14470                    if action.keep_selections {
14471                        if is_multiline_selection {
14472                            let line_start = Point::new(selection.end.row, 0);
14473                            new_selection_ranges.push(line_start..selection.end);
14474                        } else {
14475                            new_selection_ranges.push(selection.start..selection.end);
14476                        }
14477                    } else {
14478                        new_selection_ranges.push(selection.end..selection.end);
14479                    }
14480                }
14481            }
14482        }
14483        self.change_selections(Default::default(), window, cx, |s| {
14484            s.select_ranges(new_selection_ranges);
14485        });
14486    }
14487
14488    pub fn add_selection_above(
14489        &mut self,
14490        action: &AddSelectionAbove,
14491        window: &mut Window,
14492        cx: &mut Context<Self>,
14493    ) {
14494        self.add_selection(true, action.skip_soft_wrap, window, cx);
14495    }
14496
14497    pub fn add_selection_below(
14498        &mut self,
14499        action: &AddSelectionBelow,
14500        window: &mut Window,
14501        cx: &mut Context<Self>,
14502    ) {
14503        self.add_selection(false, action.skip_soft_wrap, window, cx);
14504    }
14505
14506    fn add_selection(
14507        &mut self,
14508        above: bool,
14509        skip_soft_wrap: bool,
14510        window: &mut Window,
14511        cx: &mut Context<Self>,
14512    ) {
14513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14514
14515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14516        let all_selections = self.selections.all::<Point>(&display_map);
14517        let text_layout_details = self.text_layout_details(window);
14518
14519        let (mut columnar_selections, new_selections_to_columnarize) = {
14520            if let Some(state) = self.add_selections_state.as_ref() {
14521                let columnar_selection_ids: HashSet<_> = state
14522                    .groups
14523                    .iter()
14524                    .flat_map(|group| group.stack.iter())
14525                    .copied()
14526                    .collect();
14527
14528                all_selections
14529                    .into_iter()
14530                    .partition(|s| columnar_selection_ids.contains(&s.id))
14531            } else {
14532                (Vec::new(), all_selections)
14533            }
14534        };
14535
14536        let mut state = self
14537            .add_selections_state
14538            .take()
14539            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14540
14541        for selection in new_selections_to_columnarize {
14542            let range = selection.display_range(&display_map).sorted();
14543            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14544            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14545            let positions = start_x.min(end_x)..start_x.max(end_x);
14546            let mut stack = Vec::new();
14547            for row in range.start.row().0..=range.end.row().0 {
14548                if let Some(selection) = self.selections.build_columnar_selection(
14549                    &display_map,
14550                    DisplayRow(row),
14551                    &positions,
14552                    selection.reversed,
14553                    &text_layout_details,
14554                ) {
14555                    stack.push(selection.id);
14556                    columnar_selections.push(selection);
14557                }
14558            }
14559            if !stack.is_empty() {
14560                if above {
14561                    stack.reverse();
14562                }
14563                state.groups.push(AddSelectionsGroup { above, stack });
14564            }
14565        }
14566
14567        let mut final_selections = Vec::new();
14568        let end_row = if above {
14569            DisplayRow(0)
14570        } else {
14571            display_map.max_point().row()
14572        };
14573
14574        let mut last_added_item_per_group = HashMap::default();
14575        for group in state.groups.iter_mut() {
14576            if let Some(last_id) = group.stack.last() {
14577                last_added_item_per_group.insert(*last_id, group);
14578            }
14579        }
14580
14581        for selection in columnar_selections {
14582            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14583                if above == group.above {
14584                    let range = selection.display_range(&display_map).sorted();
14585                    debug_assert_eq!(range.start.row(), range.end.row());
14586                    let mut row = range.start.row();
14587                    let positions =
14588                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14589                            Pixels::from(start)..Pixels::from(end)
14590                        } else {
14591                            let start_x =
14592                                display_map.x_for_display_point(range.start, &text_layout_details);
14593                            let end_x =
14594                                display_map.x_for_display_point(range.end, &text_layout_details);
14595                            start_x.min(end_x)..start_x.max(end_x)
14596                        };
14597
14598                    let mut maybe_new_selection = None;
14599                    let direction = if above { -1 } else { 1 };
14600
14601                    while row != end_row {
14602                        if skip_soft_wrap {
14603                            row = display_map
14604                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14605                                .row();
14606                        } else if above {
14607                            row.0 -= 1;
14608                        } else {
14609                            row.0 += 1;
14610                        }
14611
14612                        if let Some(new_selection) = self.selections.build_columnar_selection(
14613                            &display_map,
14614                            row,
14615                            &positions,
14616                            selection.reversed,
14617                            &text_layout_details,
14618                        ) {
14619                            maybe_new_selection = Some(new_selection);
14620                            break;
14621                        }
14622                    }
14623
14624                    if let Some(new_selection) = maybe_new_selection {
14625                        group.stack.push(new_selection.id);
14626                        if above {
14627                            final_selections.push(new_selection);
14628                            final_selections.push(selection);
14629                        } else {
14630                            final_selections.push(selection);
14631                            final_selections.push(new_selection);
14632                        }
14633                    } else {
14634                        final_selections.push(selection);
14635                    }
14636                } else {
14637                    group.stack.pop();
14638                }
14639            } else {
14640                final_selections.push(selection);
14641            }
14642        }
14643
14644        self.change_selections(Default::default(), window, cx, |s| {
14645            s.select(final_selections);
14646        });
14647
14648        let final_selection_ids: HashSet<_> = self
14649            .selections
14650            .all::<Point>(&display_map)
14651            .iter()
14652            .map(|s| s.id)
14653            .collect();
14654        state.groups.retain_mut(|group| {
14655            // selections might get merged above so we remove invalid items from stacks
14656            group.stack.retain(|id| final_selection_ids.contains(id));
14657
14658            // single selection in stack can be treated as initial state
14659            group.stack.len() > 1
14660        });
14661
14662        if !state.groups.is_empty() {
14663            self.add_selections_state = Some(state);
14664        }
14665    }
14666
14667    fn select_match_ranges(
14668        &mut self,
14669        range: Range<MultiBufferOffset>,
14670        reversed: bool,
14671        replace_newest: bool,
14672        auto_scroll: Option<Autoscroll>,
14673        window: &mut Window,
14674        cx: &mut Context<Editor>,
14675    ) {
14676        self.unfold_ranges(
14677            std::slice::from_ref(&range),
14678            false,
14679            auto_scroll.is_some(),
14680            cx,
14681        );
14682        let effects = if let Some(scroll) = auto_scroll {
14683            SelectionEffects::scroll(scroll)
14684        } else {
14685            SelectionEffects::no_scroll()
14686        };
14687        self.change_selections(effects, window, cx, |s| {
14688            if replace_newest {
14689                s.delete(s.newest_anchor().id);
14690            }
14691            if reversed {
14692                s.insert_range(range.end..range.start);
14693            } else {
14694                s.insert_range(range);
14695            }
14696        });
14697    }
14698
14699    pub fn select_next_match_internal(
14700        &mut self,
14701        display_map: &DisplaySnapshot,
14702        replace_newest: bool,
14703        autoscroll: Option<Autoscroll>,
14704        window: &mut Window,
14705        cx: &mut Context<Self>,
14706    ) -> Result<()> {
14707        let buffer = display_map.buffer_snapshot();
14708        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14709        if let Some(mut select_next_state) = self.select_next_state.take() {
14710            let query = &select_next_state.query;
14711            if !select_next_state.done {
14712                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14713                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14714                let mut next_selected_range = None;
14715
14716                let bytes_after_last_selection =
14717                    buffer.bytes_in_range(last_selection.end..buffer.len());
14718                let bytes_before_first_selection =
14719                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14720                let query_matches = query
14721                    .stream_find_iter(bytes_after_last_selection)
14722                    .map(|result| (last_selection.end, result))
14723                    .chain(
14724                        query
14725                            .stream_find_iter(bytes_before_first_selection)
14726                            .map(|result| (MultiBufferOffset(0), result)),
14727                    );
14728
14729                for (start_offset, query_match) in query_matches {
14730                    let query_match = query_match.unwrap(); // can only fail due to I/O
14731                    let offset_range =
14732                        start_offset + query_match.start()..start_offset + query_match.end();
14733
14734                    if !select_next_state.wordwise
14735                        || (!buffer.is_inside_word(offset_range.start, None)
14736                            && !buffer.is_inside_word(offset_range.end, None))
14737                    {
14738                        let idx = selections
14739                            .partition_point(|selection| selection.end <= offset_range.start);
14740                        let overlaps = selections
14741                            .get(idx)
14742                            .map_or(false, |selection| selection.start < offset_range.end);
14743
14744                        if !overlaps {
14745                            next_selected_range = Some(offset_range);
14746                            break;
14747                        }
14748                    }
14749                }
14750
14751                if let Some(next_selected_range) = next_selected_range {
14752                    self.select_match_ranges(
14753                        next_selected_range,
14754                        last_selection.reversed,
14755                        replace_newest,
14756                        autoscroll,
14757                        window,
14758                        cx,
14759                    );
14760                } else {
14761                    select_next_state.done = true;
14762                }
14763            }
14764
14765            self.select_next_state = Some(select_next_state);
14766        } else {
14767            let mut only_carets = true;
14768            let mut same_text_selected = true;
14769            let mut selected_text = None;
14770
14771            let mut selections_iter = selections.iter().peekable();
14772            while let Some(selection) = selections_iter.next() {
14773                if selection.start != selection.end {
14774                    only_carets = false;
14775                }
14776
14777                if same_text_selected {
14778                    if selected_text.is_none() {
14779                        selected_text =
14780                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14781                    }
14782
14783                    if let Some(next_selection) = selections_iter.peek() {
14784                        if next_selection.len() == selection.len() {
14785                            let next_selected_text = buffer
14786                                .text_for_range(next_selection.range())
14787                                .collect::<String>();
14788                            if Some(next_selected_text) != selected_text {
14789                                same_text_selected = false;
14790                                selected_text = None;
14791                            }
14792                        } else {
14793                            same_text_selected = false;
14794                            selected_text = None;
14795                        }
14796                    }
14797                }
14798            }
14799
14800            if only_carets {
14801                for selection in &mut selections {
14802                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14803                    selection.start = word_range.start;
14804                    selection.end = word_range.end;
14805                    selection.goal = SelectionGoal::None;
14806                    selection.reversed = false;
14807                    self.select_match_ranges(
14808                        selection.start..selection.end,
14809                        selection.reversed,
14810                        replace_newest,
14811                        autoscroll,
14812                        window,
14813                        cx,
14814                    );
14815                }
14816
14817                if selections.len() == 1 {
14818                    let selection = selections
14819                        .last()
14820                        .expect("ensured that there's only one selection");
14821                    let query = buffer
14822                        .text_for_range(selection.start..selection.end)
14823                        .collect::<String>();
14824                    let is_empty = query.is_empty();
14825                    let select_state = SelectNextState {
14826                        query: self.build_query(&[query], cx)?,
14827                        wordwise: true,
14828                        done: is_empty,
14829                    };
14830                    self.select_next_state = Some(select_state);
14831                } else {
14832                    self.select_next_state = None;
14833                }
14834            } else if let Some(selected_text) = selected_text {
14835                self.select_next_state = Some(SelectNextState {
14836                    query: self.build_query(&[selected_text], cx)?,
14837                    wordwise: false,
14838                    done: false,
14839                });
14840                self.select_next_match_internal(
14841                    display_map,
14842                    replace_newest,
14843                    autoscroll,
14844                    window,
14845                    cx,
14846                )?;
14847            }
14848        }
14849        Ok(())
14850    }
14851
14852    pub fn select_all_matches(
14853        &mut self,
14854        _action: &SelectAllMatches,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) -> Result<()> {
14858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14859
14860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14861
14862        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14863        let Some(select_next_state) = self.select_next_state.as_mut() else {
14864            return Ok(());
14865        };
14866        if select_next_state.done {
14867            return Ok(());
14868        }
14869
14870        let mut new_selections = Vec::new();
14871
14872        let reversed = self
14873            .selections
14874            .oldest::<MultiBufferOffset>(&display_map)
14875            .reversed;
14876        let buffer = display_map.buffer_snapshot();
14877        let query_matches = select_next_state
14878            .query
14879            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14880
14881        for query_match in query_matches.into_iter() {
14882            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14883            let offset_range = if reversed {
14884                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14885            } else {
14886                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14887            };
14888
14889            if !select_next_state.wordwise
14890                || (!buffer.is_inside_word(offset_range.start, None)
14891                    && !buffer.is_inside_word(offset_range.end, None))
14892            {
14893                new_selections.push(offset_range.start..offset_range.end);
14894            }
14895        }
14896
14897        select_next_state.done = true;
14898
14899        if new_selections.is_empty() {
14900            log::error!("bug: new_selections is empty in select_all_matches");
14901            return Ok(());
14902        }
14903
14904        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14906            selections.select_ranges(new_selections)
14907        });
14908
14909        Ok(())
14910    }
14911
14912    pub fn select_next(
14913        &mut self,
14914        action: &SelectNext,
14915        window: &mut Window,
14916        cx: &mut Context<Self>,
14917    ) -> Result<()> {
14918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14919        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14920        self.select_next_match_internal(
14921            &display_map,
14922            action.replace_newest,
14923            Some(Autoscroll::newest()),
14924            window,
14925            cx,
14926        )?;
14927        Ok(())
14928    }
14929
14930    pub fn select_previous(
14931        &mut self,
14932        action: &SelectPrevious,
14933        window: &mut Window,
14934        cx: &mut Context<Self>,
14935    ) -> Result<()> {
14936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14937        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14938        let buffer = display_map.buffer_snapshot();
14939        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14940        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14941            let query = &select_prev_state.query;
14942            if !select_prev_state.done {
14943                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14944                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14945                let mut next_selected_range = None;
14946                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14947                let bytes_before_last_selection =
14948                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14949                let bytes_after_first_selection =
14950                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14951                let query_matches = query
14952                    .stream_find_iter(bytes_before_last_selection)
14953                    .map(|result| (last_selection.start, result))
14954                    .chain(
14955                        query
14956                            .stream_find_iter(bytes_after_first_selection)
14957                            .map(|result| (buffer.len(), result)),
14958                    );
14959                for (end_offset, query_match) in query_matches {
14960                    let query_match = query_match.unwrap(); // can only fail due to I/O
14961                    let offset_range =
14962                        end_offset - query_match.end()..end_offset - query_match.start();
14963
14964                    if !select_prev_state.wordwise
14965                        || (!buffer.is_inside_word(offset_range.start, None)
14966                            && !buffer.is_inside_word(offset_range.end, None))
14967                    {
14968                        next_selected_range = Some(offset_range);
14969                        break;
14970                    }
14971                }
14972
14973                if let Some(next_selected_range) = next_selected_range {
14974                    self.select_match_ranges(
14975                        next_selected_range,
14976                        last_selection.reversed,
14977                        action.replace_newest,
14978                        Some(Autoscroll::newest()),
14979                        window,
14980                        cx,
14981                    );
14982                } else {
14983                    select_prev_state.done = true;
14984                }
14985            }
14986
14987            self.select_prev_state = Some(select_prev_state);
14988        } else {
14989            let mut only_carets = true;
14990            let mut same_text_selected = true;
14991            let mut selected_text = None;
14992
14993            let mut selections_iter = selections.iter().peekable();
14994            while let Some(selection) = selections_iter.next() {
14995                if selection.start != selection.end {
14996                    only_carets = false;
14997                }
14998
14999                if same_text_selected {
15000                    if selected_text.is_none() {
15001                        selected_text =
15002                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15003                    }
15004
15005                    if let Some(next_selection) = selections_iter.peek() {
15006                        if next_selection.len() == selection.len() {
15007                            let next_selected_text = buffer
15008                                .text_for_range(next_selection.range())
15009                                .collect::<String>();
15010                            if Some(next_selected_text) != selected_text {
15011                                same_text_selected = false;
15012                                selected_text = None;
15013                            }
15014                        } else {
15015                            same_text_selected = false;
15016                            selected_text = None;
15017                        }
15018                    }
15019                }
15020            }
15021
15022            if only_carets {
15023                for selection in &mut selections {
15024                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15025                    selection.start = word_range.start;
15026                    selection.end = word_range.end;
15027                    selection.goal = SelectionGoal::None;
15028                    selection.reversed = false;
15029                    self.select_match_ranges(
15030                        selection.start..selection.end,
15031                        selection.reversed,
15032                        action.replace_newest,
15033                        Some(Autoscroll::newest()),
15034                        window,
15035                        cx,
15036                    );
15037                }
15038                if selections.len() == 1 {
15039                    let selection = selections
15040                        .last()
15041                        .expect("ensured that there's only one selection");
15042                    let query = buffer
15043                        .text_for_range(selection.start..selection.end)
15044                        .collect::<String>();
15045                    let is_empty = query.is_empty();
15046                    let select_state = SelectNextState {
15047                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15048                        wordwise: true,
15049                        done: is_empty,
15050                    };
15051                    self.select_prev_state = Some(select_state);
15052                } else {
15053                    self.select_prev_state = None;
15054                }
15055            } else if let Some(selected_text) = selected_text {
15056                self.select_prev_state = Some(SelectNextState {
15057                    query: self
15058                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15059                    wordwise: false,
15060                    done: false,
15061                });
15062                self.select_previous(action, window, cx)?;
15063            }
15064        }
15065        Ok(())
15066    }
15067
15068    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15069    /// setting the case sensitivity based on the global
15070    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15071    /// editor's settings.
15072    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15073    where
15074        I: IntoIterator<Item = P>,
15075        P: AsRef<[u8]>,
15076    {
15077        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15078            || EditorSettings::get_global(cx).search.case_sensitive,
15079            |value| value,
15080        );
15081
15082        let mut builder = AhoCorasickBuilder::new();
15083        builder.ascii_case_insensitive(!case_sensitive);
15084        builder.build(patterns)
15085    }
15086
15087    pub fn find_next_match(
15088        &mut self,
15089        _: &FindNextMatch,
15090        window: &mut Window,
15091        cx: &mut Context<Self>,
15092    ) -> Result<()> {
15093        let selections = self.selections.disjoint_anchors_arc();
15094        match selections.first() {
15095            Some(first) if selections.len() >= 2 => {
15096                self.change_selections(Default::default(), window, cx, |s| {
15097                    s.select_ranges([first.range()]);
15098                });
15099            }
15100            _ => self.select_next(
15101                &SelectNext {
15102                    replace_newest: true,
15103                },
15104                window,
15105                cx,
15106            )?,
15107        }
15108        Ok(())
15109    }
15110
15111    pub fn find_previous_match(
15112        &mut self,
15113        _: &FindPreviousMatch,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) -> Result<()> {
15117        let selections = self.selections.disjoint_anchors_arc();
15118        match selections.last() {
15119            Some(last) if selections.len() >= 2 => {
15120                self.change_selections(Default::default(), window, cx, |s| {
15121                    s.select_ranges([last.range()]);
15122                });
15123            }
15124            _ => self.select_previous(
15125                &SelectPrevious {
15126                    replace_newest: true,
15127                },
15128                window,
15129                cx,
15130            )?,
15131        }
15132        Ok(())
15133    }
15134
15135    pub fn toggle_comments(
15136        &mut self,
15137        action: &ToggleComments,
15138        window: &mut Window,
15139        cx: &mut Context<Self>,
15140    ) {
15141        if self.read_only(cx) {
15142            return;
15143        }
15144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15145        let text_layout_details = &self.text_layout_details(window);
15146        self.transact(window, cx, |this, window, cx| {
15147            let mut selections = this
15148                .selections
15149                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15150            let mut edits = Vec::new();
15151            let mut selection_edit_ranges = Vec::new();
15152            let mut last_toggled_row = None;
15153            let snapshot = this.buffer.read(cx).read(cx);
15154            let empty_str: Arc<str> = Arc::default();
15155            let mut suffixes_inserted = Vec::new();
15156            let ignore_indent = action.ignore_indent;
15157
15158            fn comment_prefix_range(
15159                snapshot: &MultiBufferSnapshot,
15160                row: MultiBufferRow,
15161                comment_prefix: &str,
15162                comment_prefix_whitespace: &str,
15163                ignore_indent: bool,
15164            ) -> Range<Point> {
15165                let indent_size = if ignore_indent {
15166                    0
15167                } else {
15168                    snapshot.indent_size_for_line(row).len
15169                };
15170
15171                let start = Point::new(row.0, indent_size);
15172
15173                let mut line_bytes = snapshot
15174                    .bytes_in_range(start..snapshot.max_point())
15175                    .flatten()
15176                    .copied();
15177
15178                // If this line currently begins with the line comment prefix, then record
15179                // the range containing the prefix.
15180                if line_bytes
15181                    .by_ref()
15182                    .take(comment_prefix.len())
15183                    .eq(comment_prefix.bytes())
15184                {
15185                    // Include any whitespace that matches the comment prefix.
15186                    let matching_whitespace_len = line_bytes
15187                        .zip(comment_prefix_whitespace.bytes())
15188                        .take_while(|(a, b)| a == b)
15189                        .count() as u32;
15190                    let end = Point::new(
15191                        start.row,
15192                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15193                    );
15194                    start..end
15195                } else {
15196                    start..start
15197                }
15198            }
15199
15200            fn comment_suffix_range(
15201                snapshot: &MultiBufferSnapshot,
15202                row: MultiBufferRow,
15203                comment_suffix: &str,
15204                comment_suffix_has_leading_space: bool,
15205            ) -> Range<Point> {
15206                let end = Point::new(row.0, snapshot.line_len(row));
15207                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15208
15209                let mut line_end_bytes = snapshot
15210                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15211                    .flatten()
15212                    .copied();
15213
15214                let leading_space_len = if suffix_start_column > 0
15215                    && line_end_bytes.next() == Some(b' ')
15216                    && comment_suffix_has_leading_space
15217                {
15218                    1
15219                } else {
15220                    0
15221                };
15222
15223                // If this line currently begins with the line comment prefix, then record
15224                // the range containing the prefix.
15225                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15226                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15227                    start..end
15228                } else {
15229                    end..end
15230                }
15231            }
15232
15233            // TODO: Handle selections that cross excerpts
15234            for selection in &mut selections {
15235                let start_column = snapshot
15236                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15237                    .len;
15238                let language = if let Some(language) =
15239                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15240                {
15241                    language
15242                } else {
15243                    continue;
15244                };
15245
15246                selection_edit_ranges.clear();
15247
15248                // If multiple selections contain a given row, avoid processing that
15249                // row more than once.
15250                let mut start_row = MultiBufferRow(selection.start.row);
15251                if last_toggled_row == Some(start_row) {
15252                    start_row = start_row.next_row();
15253                }
15254                let end_row =
15255                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15256                        MultiBufferRow(selection.end.row - 1)
15257                    } else {
15258                        MultiBufferRow(selection.end.row)
15259                    };
15260                last_toggled_row = Some(end_row);
15261
15262                if start_row > end_row {
15263                    continue;
15264                }
15265
15266                // If the language has line comments, toggle those.
15267                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15268
15269                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15270                if ignore_indent {
15271                    full_comment_prefixes = full_comment_prefixes
15272                        .into_iter()
15273                        .map(|s| Arc::from(s.trim_end()))
15274                        .collect();
15275                }
15276
15277                if !full_comment_prefixes.is_empty() {
15278                    let first_prefix = full_comment_prefixes
15279                        .first()
15280                        .expect("prefixes is non-empty");
15281                    let prefix_trimmed_lengths = full_comment_prefixes
15282                        .iter()
15283                        .map(|p| p.trim_end_matches(' ').len())
15284                        .collect::<SmallVec<[usize; 4]>>();
15285
15286                    let mut all_selection_lines_are_comments = true;
15287
15288                    for row in start_row.0..=end_row.0 {
15289                        let row = MultiBufferRow(row);
15290                        if start_row < end_row && snapshot.is_line_blank(row) {
15291                            continue;
15292                        }
15293
15294                        let prefix_range = full_comment_prefixes
15295                            .iter()
15296                            .zip(prefix_trimmed_lengths.iter().copied())
15297                            .map(|(prefix, trimmed_prefix_len)| {
15298                                comment_prefix_range(
15299                                    snapshot.deref(),
15300                                    row,
15301                                    &prefix[..trimmed_prefix_len],
15302                                    &prefix[trimmed_prefix_len..],
15303                                    ignore_indent,
15304                                )
15305                            })
15306                            .max_by_key(|range| range.end.column - range.start.column)
15307                            .expect("prefixes is non-empty");
15308
15309                        if prefix_range.is_empty() {
15310                            all_selection_lines_are_comments = false;
15311                        }
15312
15313                        selection_edit_ranges.push(prefix_range);
15314                    }
15315
15316                    if all_selection_lines_are_comments {
15317                        edits.extend(
15318                            selection_edit_ranges
15319                                .iter()
15320                                .cloned()
15321                                .map(|range| (range, empty_str.clone())),
15322                        );
15323                    } else {
15324                        let min_column = selection_edit_ranges
15325                            .iter()
15326                            .map(|range| range.start.column)
15327                            .min()
15328                            .unwrap_or(0);
15329                        edits.extend(selection_edit_ranges.iter().map(|range| {
15330                            let position = Point::new(range.start.row, min_column);
15331                            (position..position, first_prefix.clone())
15332                        }));
15333                    }
15334                } else if let Some(BlockCommentConfig {
15335                    start: full_comment_prefix,
15336                    end: comment_suffix,
15337                    ..
15338                }) = language.block_comment()
15339                {
15340                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15341                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15342                    let prefix_range = comment_prefix_range(
15343                        snapshot.deref(),
15344                        start_row,
15345                        comment_prefix,
15346                        comment_prefix_whitespace,
15347                        ignore_indent,
15348                    );
15349                    let suffix_range = comment_suffix_range(
15350                        snapshot.deref(),
15351                        end_row,
15352                        comment_suffix.trim_start_matches(' '),
15353                        comment_suffix.starts_with(' '),
15354                    );
15355
15356                    if prefix_range.is_empty() || suffix_range.is_empty() {
15357                        edits.push((
15358                            prefix_range.start..prefix_range.start,
15359                            full_comment_prefix.clone(),
15360                        ));
15361                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15362                        suffixes_inserted.push((end_row, comment_suffix.len()));
15363                    } else {
15364                        edits.push((prefix_range, empty_str.clone()));
15365                        edits.push((suffix_range, empty_str.clone()));
15366                    }
15367                } else {
15368                    continue;
15369                }
15370            }
15371
15372            drop(snapshot);
15373            this.buffer.update(cx, |buffer, cx| {
15374                buffer.edit(edits, None, cx);
15375            });
15376
15377            // Adjust selections so that they end before any comment suffixes that
15378            // were inserted.
15379            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15380            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15381            let snapshot = this.buffer.read(cx).read(cx);
15382            for selection in &mut selections {
15383                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15384                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15385                        Ordering::Less => {
15386                            suffixes_inserted.next();
15387                            continue;
15388                        }
15389                        Ordering::Greater => break,
15390                        Ordering::Equal => {
15391                            if selection.end.column == snapshot.line_len(row) {
15392                                if selection.is_empty() {
15393                                    selection.start.column -= suffix_len as u32;
15394                                }
15395                                selection.end.column -= suffix_len as u32;
15396                            }
15397                            break;
15398                        }
15399                    }
15400                }
15401            }
15402
15403            drop(snapshot);
15404            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15405
15406            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15407            let selections_on_single_row = selections.windows(2).all(|selections| {
15408                selections[0].start.row == selections[1].start.row
15409                    && selections[0].end.row == selections[1].end.row
15410                    && selections[0].start.row == selections[0].end.row
15411            });
15412            let selections_selecting = selections
15413                .iter()
15414                .any(|selection| selection.start != selection.end);
15415            let advance_downwards = action.advance_downwards
15416                && selections_on_single_row
15417                && !selections_selecting
15418                && !matches!(this.mode, EditorMode::SingleLine);
15419
15420            if advance_downwards {
15421                let snapshot = this.buffer.read(cx).snapshot(cx);
15422
15423                this.change_selections(Default::default(), window, cx, |s| {
15424                    s.move_cursors_with(|display_snapshot, display_point, _| {
15425                        let mut point = display_point.to_point(display_snapshot);
15426                        point.row += 1;
15427                        point = snapshot.clip_point(point, Bias::Left);
15428                        let display_point = point.to_display_point(display_snapshot);
15429                        let goal = SelectionGoal::HorizontalPosition(
15430                            display_snapshot
15431                                .x_for_display_point(display_point, text_layout_details)
15432                                .into(),
15433                        );
15434                        (display_point, goal)
15435                    })
15436                });
15437            }
15438        });
15439    }
15440
15441    pub fn select_enclosing_symbol(
15442        &mut self,
15443        _: &SelectEnclosingSymbol,
15444        window: &mut Window,
15445        cx: &mut Context<Self>,
15446    ) {
15447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15448
15449        let buffer = self.buffer.read(cx).snapshot(cx);
15450        let old_selections = self
15451            .selections
15452            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15453            .into_boxed_slice();
15454
15455        fn update_selection(
15456            selection: &Selection<MultiBufferOffset>,
15457            buffer_snap: &MultiBufferSnapshot,
15458        ) -> Option<Selection<MultiBufferOffset>> {
15459            let cursor = selection.head();
15460            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15461            for symbol in symbols.iter().rev() {
15462                let start = symbol.range.start.to_offset(buffer_snap);
15463                let end = symbol.range.end.to_offset(buffer_snap);
15464                let new_range = start..end;
15465                if start < selection.start || end > selection.end {
15466                    return Some(Selection {
15467                        id: selection.id,
15468                        start: new_range.start,
15469                        end: new_range.end,
15470                        goal: SelectionGoal::None,
15471                        reversed: selection.reversed,
15472                    });
15473                }
15474            }
15475            None
15476        }
15477
15478        let mut selected_larger_symbol = false;
15479        let new_selections = old_selections
15480            .iter()
15481            .map(|selection| match update_selection(selection, &buffer) {
15482                Some(new_selection) => {
15483                    if new_selection.range() != selection.range() {
15484                        selected_larger_symbol = true;
15485                    }
15486                    new_selection
15487                }
15488                None => selection.clone(),
15489            })
15490            .collect::<Vec<_>>();
15491
15492        if selected_larger_symbol {
15493            self.change_selections(Default::default(), window, cx, |s| {
15494                s.select(new_selections);
15495            });
15496        }
15497    }
15498
15499    pub fn select_larger_syntax_node(
15500        &mut self,
15501        _: &SelectLargerSyntaxNode,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) {
15505        let Some(visible_row_count) = self.visible_row_count() else {
15506            return;
15507        };
15508        let old_selections: Box<[_]> = self
15509            .selections
15510            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15511            .into();
15512        if old_selections.is_empty() {
15513            return;
15514        }
15515
15516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15517
15518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15519        let buffer = self.buffer.read(cx).snapshot(cx);
15520
15521        let mut selected_larger_node = false;
15522        let mut new_selections = old_selections
15523            .iter()
15524            .map(|selection| {
15525                let old_range = selection.start..selection.end;
15526
15527                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15528                    // manually select word at selection
15529                    if ["string_content", "inline"].contains(&node.kind()) {
15530                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15531                        // ignore if word is already selected
15532                        if !word_range.is_empty() && old_range != word_range {
15533                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15534                            // only select word if start and end point belongs to same word
15535                            if word_range == last_word_range {
15536                                selected_larger_node = true;
15537                                return Selection {
15538                                    id: selection.id,
15539                                    start: word_range.start,
15540                                    end: word_range.end,
15541                                    goal: SelectionGoal::None,
15542                                    reversed: selection.reversed,
15543                                };
15544                            }
15545                        }
15546                    }
15547                }
15548
15549                let mut new_range = old_range.clone();
15550                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15551                    new_range = range;
15552                    if !node.is_named() {
15553                        continue;
15554                    }
15555                    if !display_map.intersects_fold(new_range.start)
15556                        && !display_map.intersects_fold(new_range.end)
15557                    {
15558                        break;
15559                    }
15560                }
15561
15562                selected_larger_node |= new_range != old_range;
15563                Selection {
15564                    id: selection.id,
15565                    start: new_range.start,
15566                    end: new_range.end,
15567                    goal: SelectionGoal::None,
15568                    reversed: selection.reversed,
15569                }
15570            })
15571            .collect::<Vec<_>>();
15572
15573        if !selected_larger_node {
15574            return; // don't put this call in the history
15575        }
15576
15577        // scroll based on transformation done to the last selection created by the user
15578        let (last_old, last_new) = old_selections
15579            .last()
15580            .zip(new_selections.last().cloned())
15581            .expect("old_selections isn't empty");
15582
15583        // revert selection
15584        let is_selection_reversed = {
15585            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15586            new_selections.last_mut().expect("checked above").reversed =
15587                should_newest_selection_be_reversed;
15588            should_newest_selection_be_reversed
15589        };
15590
15591        if selected_larger_node {
15592            self.select_syntax_node_history.disable_clearing = true;
15593            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15594                s.select(new_selections.clone());
15595            });
15596            self.select_syntax_node_history.disable_clearing = false;
15597        }
15598
15599        let start_row = last_new.start.to_display_point(&display_map).row().0;
15600        let end_row = last_new.end.to_display_point(&display_map).row().0;
15601        let selection_height = end_row - start_row + 1;
15602        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15603
15604        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15605        let scroll_behavior = if fits_on_the_screen {
15606            self.request_autoscroll(Autoscroll::fit(), cx);
15607            SelectSyntaxNodeScrollBehavior::FitSelection
15608        } else if is_selection_reversed {
15609            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15610            SelectSyntaxNodeScrollBehavior::CursorTop
15611        } else {
15612            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15613            SelectSyntaxNodeScrollBehavior::CursorBottom
15614        };
15615
15616        self.select_syntax_node_history.push((
15617            old_selections,
15618            scroll_behavior,
15619            is_selection_reversed,
15620        ));
15621    }
15622
15623    pub fn select_smaller_syntax_node(
15624        &mut self,
15625        _: &SelectSmallerSyntaxNode,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) {
15629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15630
15631        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15632            self.select_syntax_node_history.pop()
15633        {
15634            if let Some(selection) = selections.last_mut() {
15635                selection.reversed = is_selection_reversed;
15636            }
15637
15638            self.select_syntax_node_history.disable_clearing = true;
15639            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15640                s.select(selections.to_vec());
15641            });
15642            self.select_syntax_node_history.disable_clearing = false;
15643
15644            match scroll_behavior {
15645                SelectSyntaxNodeScrollBehavior::CursorTop => {
15646                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15647                }
15648                SelectSyntaxNodeScrollBehavior::FitSelection => {
15649                    self.request_autoscroll(Autoscroll::fit(), cx);
15650                }
15651                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15652                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15653                }
15654            }
15655        }
15656    }
15657
15658    pub fn unwrap_syntax_node(
15659        &mut self,
15660        _: &UnwrapSyntaxNode,
15661        window: &mut Window,
15662        cx: &mut Context<Self>,
15663    ) {
15664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15665
15666        let buffer = self.buffer.read(cx).snapshot(cx);
15667        let selections = self
15668            .selections
15669            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15670            .into_iter()
15671            // subtracting the offset requires sorting
15672            .sorted_by_key(|i| i.start);
15673
15674        let full_edits = selections
15675            .into_iter()
15676            .filter_map(|selection| {
15677                let child = if selection.is_empty()
15678                    && let Some((_, ancestor_range)) =
15679                        buffer.syntax_ancestor(selection.start..selection.end)
15680                {
15681                    ancestor_range
15682                } else {
15683                    selection.range()
15684                };
15685
15686                let mut parent = child.clone();
15687                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15688                    parent = ancestor_range;
15689                    if parent.start < child.start || parent.end > child.end {
15690                        break;
15691                    }
15692                }
15693
15694                if parent == child {
15695                    return None;
15696                }
15697                let text = buffer.text_for_range(child).collect::<String>();
15698                Some((selection.id, parent, text))
15699            })
15700            .collect::<Vec<_>>();
15701        if full_edits.is_empty() {
15702            return;
15703        }
15704
15705        self.transact(window, cx, |this, window, cx| {
15706            this.buffer.update(cx, |buffer, cx| {
15707                buffer.edit(
15708                    full_edits
15709                        .iter()
15710                        .map(|(_, p, t)| (p.clone(), t.clone()))
15711                        .collect::<Vec<_>>(),
15712                    None,
15713                    cx,
15714                );
15715            });
15716            this.change_selections(Default::default(), window, cx, |s| {
15717                let mut offset = 0;
15718                let mut selections = vec![];
15719                for (id, parent, text) in full_edits {
15720                    let start = parent.start - offset;
15721                    offset += (parent.end - parent.start) - text.len();
15722                    selections.push(Selection {
15723                        id,
15724                        start,
15725                        end: start + text.len(),
15726                        reversed: false,
15727                        goal: Default::default(),
15728                    });
15729                }
15730                s.select(selections);
15731            });
15732        });
15733    }
15734
15735    pub fn select_next_syntax_node(
15736        &mut self,
15737        _: &SelectNextSyntaxNode,
15738        window: &mut Window,
15739        cx: &mut Context<Self>,
15740    ) {
15741        let old_selections: Box<[_]> = self
15742            .selections
15743            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15744            .into();
15745        if old_selections.is_empty() {
15746            return;
15747        }
15748
15749        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15750
15751        let buffer = self.buffer.read(cx).snapshot(cx);
15752        let mut selected_sibling = false;
15753
15754        let new_selections = old_selections
15755            .iter()
15756            .map(|selection| {
15757                let old_range = selection.start..selection.end;
15758
15759                let old_range =
15760                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15761                let excerpt = buffer.excerpt_containing(old_range.clone());
15762
15763                if let Some(mut excerpt) = excerpt
15764                    && let Some(node) = excerpt
15765                        .buffer()
15766                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15767                {
15768                    let new_range = excerpt.map_range_from_buffer(
15769                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15770                    );
15771                    selected_sibling = true;
15772                    Selection {
15773                        id: selection.id,
15774                        start: new_range.start,
15775                        end: new_range.end,
15776                        goal: SelectionGoal::None,
15777                        reversed: selection.reversed,
15778                    }
15779                } else {
15780                    selection.clone()
15781                }
15782            })
15783            .collect::<Vec<_>>();
15784
15785        if selected_sibling {
15786            self.change_selections(
15787                SelectionEffects::scroll(Autoscroll::fit()),
15788                window,
15789                cx,
15790                |s| {
15791                    s.select(new_selections);
15792                },
15793            );
15794        }
15795    }
15796
15797    pub fn select_prev_syntax_node(
15798        &mut self,
15799        _: &SelectPreviousSyntaxNode,
15800        window: &mut Window,
15801        cx: &mut Context<Self>,
15802    ) {
15803        let old_selections: Box<[_]> = self
15804            .selections
15805            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15806            .into();
15807        if old_selections.is_empty() {
15808            return;
15809        }
15810
15811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15812
15813        let buffer = self.buffer.read(cx).snapshot(cx);
15814        let mut selected_sibling = false;
15815
15816        let new_selections = old_selections
15817            .iter()
15818            .map(|selection| {
15819                let old_range = selection.start..selection.end;
15820                let old_range =
15821                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15822                let excerpt = buffer.excerpt_containing(old_range.clone());
15823
15824                if let Some(mut excerpt) = excerpt
15825                    && let Some(node) = excerpt
15826                        .buffer()
15827                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15828                {
15829                    let new_range = excerpt.map_range_from_buffer(
15830                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15831                    );
15832                    selected_sibling = true;
15833                    Selection {
15834                        id: selection.id,
15835                        start: new_range.start,
15836                        end: new_range.end,
15837                        goal: SelectionGoal::None,
15838                        reversed: selection.reversed,
15839                    }
15840                } else {
15841                    selection.clone()
15842                }
15843            })
15844            .collect::<Vec<_>>();
15845
15846        if selected_sibling {
15847            self.change_selections(
15848                SelectionEffects::scroll(Autoscroll::fit()),
15849                window,
15850                cx,
15851                |s| {
15852                    s.select(new_selections);
15853                },
15854            );
15855        }
15856    }
15857
15858    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15859        if !EditorSettings::get_global(cx).gutter.runnables {
15860            self.clear_tasks();
15861            return Task::ready(());
15862        }
15863        let project = self.project().map(Entity::downgrade);
15864        let task_sources = self.lsp_task_sources(cx);
15865        let multi_buffer = self.buffer.downgrade();
15866        cx.spawn_in(window, async move |editor, cx| {
15867            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15868            let Some(project) = project.and_then(|p| p.upgrade()) else {
15869                return;
15870            };
15871            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15872                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15873            }) else {
15874                return;
15875            };
15876
15877            let hide_runnables = project
15878                .update(cx, |project, _| project.is_via_collab())
15879                .unwrap_or(true);
15880            if hide_runnables {
15881                return;
15882            }
15883            let new_rows =
15884                cx.background_spawn({
15885                    let snapshot = display_snapshot.clone();
15886                    async move {
15887                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15888                    }
15889                })
15890                    .await;
15891            let Ok(lsp_tasks) =
15892                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15893            else {
15894                return;
15895            };
15896            let lsp_tasks = lsp_tasks.await;
15897
15898            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15899                lsp_tasks
15900                    .into_iter()
15901                    .flat_map(|(kind, tasks)| {
15902                        tasks.into_iter().filter_map(move |(location, task)| {
15903                            Some((kind.clone(), location?, task))
15904                        })
15905                    })
15906                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15907                        let buffer = location.target.buffer;
15908                        let buffer_snapshot = buffer.read(cx).snapshot();
15909                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15910                            |(excerpt_id, snapshot, _)| {
15911                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15912                                    display_snapshot
15913                                        .buffer_snapshot()
15914                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15915                                } else {
15916                                    None
15917                                }
15918                            },
15919                        );
15920                        if let Some(offset) = offset {
15921                            let task_buffer_range =
15922                                location.target.range.to_point(&buffer_snapshot);
15923                            let context_buffer_range =
15924                                task_buffer_range.to_offset(&buffer_snapshot);
15925                            let context_range = BufferOffset(context_buffer_range.start)
15926                                ..BufferOffset(context_buffer_range.end);
15927
15928                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15929                                .or_insert_with(|| RunnableTasks {
15930                                    templates: Vec::new(),
15931                                    offset,
15932                                    column: task_buffer_range.start.column,
15933                                    extra_variables: HashMap::default(),
15934                                    context_range,
15935                                })
15936                                .templates
15937                                .push((kind, task.original_task().clone()));
15938                        }
15939
15940                        acc
15941                    })
15942            }) else {
15943                return;
15944            };
15945
15946            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15947                buffer.language_settings(cx).tasks.prefer_lsp
15948            }) else {
15949                return;
15950            };
15951
15952            let rows = Self::runnable_rows(
15953                project,
15954                display_snapshot,
15955                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15956                new_rows,
15957                cx.clone(),
15958            )
15959            .await;
15960            editor
15961                .update(cx, |editor, _| {
15962                    editor.clear_tasks();
15963                    for (key, mut value) in rows {
15964                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15965                            value.templates.extend(lsp_tasks.templates);
15966                        }
15967
15968                        editor.insert_tasks(key, value);
15969                    }
15970                    for (key, value) in lsp_tasks_by_rows {
15971                        editor.insert_tasks(key, value);
15972                    }
15973                })
15974                .ok();
15975        })
15976    }
15977    fn fetch_runnable_ranges(
15978        snapshot: &DisplaySnapshot,
15979        range: Range<Anchor>,
15980    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15981        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15982    }
15983
15984    fn runnable_rows(
15985        project: Entity<Project>,
15986        snapshot: DisplaySnapshot,
15987        prefer_lsp: bool,
15988        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15989        cx: AsyncWindowContext,
15990    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15991        cx.spawn(async move |cx| {
15992            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15993            for (run_range, mut runnable) in runnable_ranges {
15994                let Some(tasks) = cx
15995                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15996                    .ok()
15997                else {
15998                    continue;
15999                };
16000                let mut tasks = tasks.await;
16001
16002                if prefer_lsp {
16003                    tasks.retain(|(task_kind, _)| {
16004                        !matches!(task_kind, TaskSourceKind::Language { .. })
16005                    });
16006                }
16007                if tasks.is_empty() {
16008                    continue;
16009                }
16010
16011                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16012                let Some(row) = snapshot
16013                    .buffer_snapshot()
16014                    .buffer_line_for_row(MultiBufferRow(point.row))
16015                    .map(|(_, range)| range.start.row)
16016                else {
16017                    continue;
16018                };
16019
16020                let context_range =
16021                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16022                runnable_rows.push((
16023                    (runnable.buffer_id, row),
16024                    RunnableTasks {
16025                        templates: tasks,
16026                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16027                        context_range,
16028                        column: point.column,
16029                        extra_variables: runnable.extra_captures,
16030                    },
16031                ));
16032            }
16033            runnable_rows
16034        })
16035    }
16036
16037    fn templates_with_tags(
16038        project: &Entity<Project>,
16039        runnable: &mut Runnable,
16040        cx: &mut App,
16041    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16042        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16043            let (worktree_id, file) = project
16044                .buffer_for_id(runnable.buffer, cx)
16045                .and_then(|buffer| buffer.read(cx).file())
16046                .map(|file| (file.worktree_id(cx), file.clone()))
16047                .unzip();
16048
16049            (
16050                project.task_store().read(cx).task_inventory().cloned(),
16051                worktree_id,
16052                file,
16053            )
16054        });
16055
16056        let tags = mem::take(&mut runnable.tags);
16057        let language = runnable.language.clone();
16058        cx.spawn(async move |cx| {
16059            let mut templates_with_tags = Vec::new();
16060            if let Some(inventory) = inventory {
16061                for RunnableTag(tag) in tags {
16062                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16063                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16064                    }) else {
16065                        return templates_with_tags;
16066                    };
16067                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16068                        move |(_, template)| {
16069                            template.tags.iter().any(|source_tag| source_tag == &tag)
16070                        },
16071                    ));
16072                }
16073            }
16074            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16075
16076            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16077                // Strongest source wins; if we have worktree tag binding, prefer that to
16078                // global and language bindings;
16079                // if we have a global binding, prefer that to language binding.
16080                let first_mismatch = templates_with_tags
16081                    .iter()
16082                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16083                if let Some(index) = first_mismatch {
16084                    templates_with_tags.truncate(index);
16085                }
16086            }
16087
16088            templates_with_tags
16089        })
16090    }
16091
16092    pub fn move_to_enclosing_bracket(
16093        &mut self,
16094        _: &MoveToEnclosingBracket,
16095        window: &mut Window,
16096        cx: &mut Context<Self>,
16097    ) {
16098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16099        self.change_selections(Default::default(), window, cx, |s| {
16100            s.move_offsets_with(|snapshot, selection| {
16101                let Some(enclosing_bracket_ranges) =
16102                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16103                else {
16104                    return;
16105                };
16106
16107                let mut best_length = usize::MAX;
16108                let mut best_inside = false;
16109                let mut best_in_bracket_range = false;
16110                let mut best_destination = None;
16111                for (open, close) in enclosing_bracket_ranges {
16112                    let close = close.to_inclusive();
16113                    let length = *close.end() - open.start;
16114                    let inside = selection.start >= open.end && selection.end <= *close.start();
16115                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16116                        || close.contains(&selection.head());
16117
16118                    // If best is next to a bracket and current isn't, skip
16119                    if !in_bracket_range && best_in_bracket_range {
16120                        continue;
16121                    }
16122
16123                    // Prefer smaller lengths unless best is inside and current isn't
16124                    if length > best_length && (best_inside || !inside) {
16125                        continue;
16126                    }
16127
16128                    best_length = length;
16129                    best_inside = inside;
16130                    best_in_bracket_range = in_bracket_range;
16131                    best_destination = Some(
16132                        if close.contains(&selection.start) && close.contains(&selection.end) {
16133                            if inside { open.end } else { open.start }
16134                        } else if inside {
16135                            *close.start()
16136                        } else {
16137                            *close.end()
16138                        },
16139                    );
16140                }
16141
16142                if let Some(destination) = best_destination {
16143                    selection.collapse_to(destination, SelectionGoal::None);
16144                }
16145            })
16146        });
16147    }
16148
16149    pub fn undo_selection(
16150        &mut self,
16151        _: &UndoSelection,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16156        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16157            self.selection_history.mode = SelectionHistoryMode::Undoing;
16158            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16159                this.end_selection(window, cx);
16160                this.change_selections(
16161                    SelectionEffects::scroll(Autoscroll::newest()),
16162                    window,
16163                    cx,
16164                    |s| s.select_anchors(entry.selections.to_vec()),
16165                );
16166            });
16167            self.selection_history.mode = SelectionHistoryMode::Normal;
16168
16169            self.select_next_state = entry.select_next_state;
16170            self.select_prev_state = entry.select_prev_state;
16171            self.add_selections_state = entry.add_selections_state;
16172        }
16173    }
16174
16175    pub fn redo_selection(
16176        &mut self,
16177        _: &RedoSelection,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) {
16181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16182        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16183            self.selection_history.mode = SelectionHistoryMode::Redoing;
16184            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16185                this.end_selection(window, cx);
16186                this.change_selections(
16187                    SelectionEffects::scroll(Autoscroll::newest()),
16188                    window,
16189                    cx,
16190                    |s| s.select_anchors(entry.selections.to_vec()),
16191                );
16192            });
16193            self.selection_history.mode = SelectionHistoryMode::Normal;
16194
16195            self.select_next_state = entry.select_next_state;
16196            self.select_prev_state = entry.select_prev_state;
16197            self.add_selections_state = entry.add_selections_state;
16198        }
16199    }
16200
16201    pub fn expand_excerpts(
16202        &mut self,
16203        action: &ExpandExcerpts,
16204        _: &mut Window,
16205        cx: &mut Context<Self>,
16206    ) {
16207        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16208    }
16209
16210    pub fn expand_excerpts_down(
16211        &mut self,
16212        action: &ExpandExcerptsDown,
16213        _: &mut Window,
16214        cx: &mut Context<Self>,
16215    ) {
16216        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16217    }
16218
16219    pub fn expand_excerpts_up(
16220        &mut self,
16221        action: &ExpandExcerptsUp,
16222        _: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) {
16225        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16226    }
16227
16228    pub fn expand_excerpts_for_direction(
16229        &mut self,
16230        lines: u32,
16231        direction: ExpandExcerptDirection,
16232
16233        cx: &mut Context<Self>,
16234    ) {
16235        let selections = self.selections.disjoint_anchors_arc();
16236
16237        let lines = if lines == 0 {
16238            EditorSettings::get_global(cx).expand_excerpt_lines
16239        } else {
16240            lines
16241        };
16242
16243        self.buffer.update(cx, |buffer, cx| {
16244            let snapshot = buffer.snapshot(cx);
16245            let mut excerpt_ids = selections
16246                .iter()
16247                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16248                .collect::<Vec<_>>();
16249            excerpt_ids.sort();
16250            excerpt_ids.dedup();
16251            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16252        })
16253    }
16254
16255    pub fn expand_excerpt(
16256        &mut self,
16257        excerpt: ExcerptId,
16258        direction: ExpandExcerptDirection,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) {
16262        let current_scroll_position = self.scroll_position(cx);
16263        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16264        let mut scroll = None;
16265
16266        if direction == ExpandExcerptDirection::Down {
16267            let multi_buffer = self.buffer.read(cx);
16268            let snapshot = multi_buffer.snapshot(cx);
16269            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16270                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16271                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16272            {
16273                let buffer_snapshot = buffer.read(cx).snapshot();
16274                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16275                let last_row = buffer_snapshot.max_point().row;
16276                let lines_below = last_row.saturating_sub(excerpt_end_row);
16277                if lines_below >= lines_to_expand {
16278                    scroll = Some(
16279                        current_scroll_position
16280                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16281                    );
16282                }
16283            }
16284        }
16285        if direction == ExpandExcerptDirection::Up
16286            && self
16287                .buffer
16288                .read(cx)
16289                .snapshot(cx)
16290                .excerpt_before(excerpt)
16291                .is_none()
16292        {
16293            scroll = Some(current_scroll_position);
16294        }
16295
16296        self.buffer.update(cx, |buffer, cx| {
16297            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16298        });
16299
16300        if let Some(new_scroll_position) = scroll {
16301            self.set_scroll_position(new_scroll_position, window, cx);
16302        }
16303    }
16304
16305    pub fn go_to_singleton_buffer_point(
16306        &mut self,
16307        point: Point,
16308        window: &mut Window,
16309        cx: &mut Context<Self>,
16310    ) {
16311        self.go_to_singleton_buffer_range(point..point, window, cx);
16312    }
16313
16314    pub fn go_to_singleton_buffer_range(
16315        &mut self,
16316        range: Range<Point>,
16317        window: &mut Window,
16318        cx: &mut Context<Self>,
16319    ) {
16320        let multibuffer = self.buffer().read(cx);
16321        let Some(buffer) = multibuffer.as_singleton() else {
16322            return;
16323        };
16324        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16325            return;
16326        };
16327        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16328            return;
16329        };
16330        self.change_selections(
16331            SelectionEffects::default().nav_history(true),
16332            window,
16333            cx,
16334            |s| s.select_anchor_ranges([start..end]),
16335        );
16336    }
16337
16338    pub fn go_to_diagnostic(
16339        &mut self,
16340        action: &GoToDiagnostic,
16341        window: &mut Window,
16342        cx: &mut Context<Self>,
16343    ) {
16344        if !self.diagnostics_enabled() {
16345            return;
16346        }
16347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16348        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16349    }
16350
16351    pub fn go_to_prev_diagnostic(
16352        &mut self,
16353        action: &GoToPreviousDiagnostic,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) {
16357        if !self.diagnostics_enabled() {
16358            return;
16359        }
16360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16361        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16362    }
16363
16364    pub fn go_to_diagnostic_impl(
16365        &mut self,
16366        direction: Direction,
16367        severity: GoToDiagnosticSeverityFilter,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) {
16371        let buffer = self.buffer.read(cx).snapshot(cx);
16372        let selection = self
16373            .selections
16374            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16375
16376        let mut active_group_id = None;
16377        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16378            && active_group.active_range.start.to_offset(&buffer) == selection.start
16379        {
16380            active_group_id = Some(active_group.group_id);
16381        }
16382
16383        fn filtered<'a>(
16384            severity: GoToDiagnosticSeverityFilter,
16385            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16386        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16387            diagnostics
16388                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16389                .filter(|entry| entry.range.start != entry.range.end)
16390                .filter(|entry| !entry.diagnostic.is_unnecessary)
16391        }
16392
16393        let before = filtered(
16394            severity,
16395            buffer
16396                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16397                .filter(|entry| entry.range.start <= selection.start),
16398        );
16399        let after = filtered(
16400            severity,
16401            buffer
16402                .diagnostics_in_range(selection.start..buffer.len())
16403                .filter(|entry| entry.range.start >= selection.start),
16404        );
16405
16406        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16407        if direction == Direction::Prev {
16408            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16409            {
16410                for diagnostic in prev_diagnostics.into_iter().rev() {
16411                    if diagnostic.range.start != selection.start
16412                        || active_group_id
16413                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16414                    {
16415                        found = Some(diagnostic);
16416                        break 'outer;
16417                    }
16418                }
16419            }
16420        } else {
16421            for diagnostic in after.chain(before) {
16422                if diagnostic.range.start != selection.start
16423                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16424                {
16425                    found = Some(diagnostic);
16426                    break;
16427                }
16428            }
16429        }
16430        let Some(next_diagnostic) = found else {
16431            return;
16432        };
16433
16434        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16435        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16436            return;
16437        };
16438        let snapshot = self.snapshot(window, cx);
16439        if snapshot.intersects_fold(next_diagnostic.range.start) {
16440            self.unfold_ranges(
16441                std::slice::from_ref(&next_diagnostic.range),
16442                true,
16443                false,
16444                cx,
16445            );
16446        }
16447        self.change_selections(Default::default(), window, cx, |s| {
16448            s.select_ranges(vec![
16449                next_diagnostic.range.start..next_diagnostic.range.start,
16450            ])
16451        });
16452        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16453        self.refresh_edit_prediction(false, true, window, cx);
16454    }
16455
16456    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16458        let snapshot = self.snapshot(window, cx);
16459        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16460        self.go_to_hunk_before_or_after_position(
16461            &snapshot,
16462            selection.head(),
16463            Direction::Next,
16464            window,
16465            cx,
16466        );
16467    }
16468
16469    pub fn go_to_hunk_before_or_after_position(
16470        &mut self,
16471        snapshot: &EditorSnapshot,
16472        position: Point,
16473        direction: Direction,
16474        window: &mut Window,
16475        cx: &mut Context<Editor>,
16476    ) {
16477        let row = if direction == Direction::Next {
16478            self.hunk_after_position(snapshot, position)
16479                .map(|hunk| hunk.row_range.start)
16480        } else {
16481            self.hunk_before_position(snapshot, position)
16482        };
16483
16484        if let Some(row) = row {
16485            let destination = Point::new(row.0, 0);
16486            let autoscroll = Autoscroll::center();
16487
16488            self.unfold_ranges(&[destination..destination], false, false, cx);
16489            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16490                s.select_ranges([destination..destination]);
16491            });
16492        }
16493    }
16494
16495    fn hunk_after_position(
16496        &mut self,
16497        snapshot: &EditorSnapshot,
16498        position: Point,
16499    ) -> Option<MultiBufferDiffHunk> {
16500        snapshot
16501            .buffer_snapshot()
16502            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16503            .find(|hunk| hunk.row_range.start.0 > position.row)
16504            .or_else(|| {
16505                snapshot
16506                    .buffer_snapshot()
16507                    .diff_hunks_in_range(Point::zero()..position)
16508                    .find(|hunk| hunk.row_range.end.0 < position.row)
16509            })
16510    }
16511
16512    fn go_to_prev_hunk(
16513        &mut self,
16514        _: &GoToPreviousHunk,
16515        window: &mut Window,
16516        cx: &mut Context<Self>,
16517    ) {
16518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16519        let snapshot = self.snapshot(window, cx);
16520        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16521        self.go_to_hunk_before_or_after_position(
16522            &snapshot,
16523            selection.head(),
16524            Direction::Prev,
16525            window,
16526            cx,
16527        );
16528    }
16529
16530    fn hunk_before_position(
16531        &mut self,
16532        snapshot: &EditorSnapshot,
16533        position: Point,
16534    ) -> Option<MultiBufferRow> {
16535        snapshot
16536            .buffer_snapshot()
16537            .diff_hunk_before(position)
16538            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16539    }
16540
16541    fn go_to_next_change(
16542        &mut self,
16543        _: &GoToNextChange,
16544        window: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) {
16547        if let Some(selections) = self
16548            .change_list
16549            .next_change(1, Direction::Next)
16550            .map(|s| s.to_vec())
16551        {
16552            self.change_selections(Default::default(), window, cx, |s| {
16553                let map = s.display_snapshot();
16554                s.select_display_ranges(selections.iter().map(|a| {
16555                    let point = a.to_display_point(&map);
16556                    point..point
16557                }))
16558            })
16559        }
16560    }
16561
16562    fn go_to_previous_change(
16563        &mut self,
16564        _: &GoToPreviousChange,
16565        window: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) {
16568        if let Some(selections) = self
16569            .change_list
16570            .next_change(1, Direction::Prev)
16571            .map(|s| s.to_vec())
16572        {
16573            self.change_selections(Default::default(), window, cx, |s| {
16574                let map = s.display_snapshot();
16575                s.select_display_ranges(selections.iter().map(|a| {
16576                    let point = a.to_display_point(&map);
16577                    point..point
16578                }))
16579            })
16580        }
16581    }
16582
16583    pub fn go_to_next_document_highlight(
16584        &mut self,
16585        _: &GoToNextDocumentHighlight,
16586        window: &mut Window,
16587        cx: &mut Context<Self>,
16588    ) {
16589        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16590    }
16591
16592    pub fn go_to_prev_document_highlight(
16593        &mut self,
16594        _: &GoToPreviousDocumentHighlight,
16595        window: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) {
16598        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16599    }
16600
16601    pub fn go_to_document_highlight_before_or_after_position(
16602        &mut self,
16603        direction: Direction,
16604        window: &mut Window,
16605        cx: &mut Context<Editor>,
16606    ) {
16607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16608        let snapshot = self.snapshot(window, cx);
16609        let buffer = &snapshot.buffer_snapshot();
16610        let position = self
16611            .selections
16612            .newest::<Point>(&snapshot.display_snapshot)
16613            .head();
16614        let anchor_position = buffer.anchor_after(position);
16615
16616        // Get all document highlights (both read and write)
16617        let mut all_highlights = Vec::new();
16618
16619        if let Some((_, read_highlights)) = self
16620            .background_highlights
16621            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16622        {
16623            all_highlights.extend(read_highlights.iter());
16624        }
16625
16626        if let Some((_, write_highlights)) = self
16627            .background_highlights
16628            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16629        {
16630            all_highlights.extend(write_highlights.iter());
16631        }
16632
16633        if all_highlights.is_empty() {
16634            return;
16635        }
16636
16637        // Sort highlights by position
16638        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16639
16640        let target_highlight = match direction {
16641            Direction::Next => {
16642                // Find the first highlight after the current position
16643                all_highlights
16644                    .iter()
16645                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16646            }
16647            Direction::Prev => {
16648                // Find the last highlight before the current position
16649                all_highlights
16650                    .iter()
16651                    .rev()
16652                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16653            }
16654        };
16655
16656        if let Some(highlight) = target_highlight {
16657            let destination = highlight.start.to_point(buffer);
16658            let autoscroll = Autoscroll::center();
16659
16660            self.unfold_ranges(&[destination..destination], false, false, cx);
16661            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16662                s.select_ranges([destination..destination]);
16663            });
16664        }
16665    }
16666
16667    fn go_to_line<T: 'static>(
16668        &mut self,
16669        position: Anchor,
16670        highlight_color: Option<Hsla>,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) {
16674        let snapshot = self.snapshot(window, cx).display_snapshot;
16675        let position = position.to_point(&snapshot.buffer_snapshot());
16676        let start = snapshot
16677            .buffer_snapshot()
16678            .clip_point(Point::new(position.row, 0), Bias::Left);
16679        let end = start + Point::new(1, 0);
16680        let start = snapshot.buffer_snapshot().anchor_before(start);
16681        let end = snapshot.buffer_snapshot().anchor_before(end);
16682
16683        self.highlight_rows::<T>(
16684            start..end,
16685            highlight_color
16686                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16687            Default::default(),
16688            cx,
16689        );
16690
16691        if self.buffer.read(cx).is_singleton() {
16692            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16693        }
16694    }
16695
16696    pub fn go_to_definition(
16697        &mut self,
16698        _: &GoToDefinition,
16699        window: &mut Window,
16700        cx: &mut Context<Self>,
16701    ) -> Task<Result<Navigated>> {
16702        let definition =
16703            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16704        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16705        cx.spawn_in(window, async move |editor, cx| {
16706            if definition.await? == Navigated::Yes {
16707                return Ok(Navigated::Yes);
16708            }
16709            match fallback_strategy {
16710                GoToDefinitionFallback::None => Ok(Navigated::No),
16711                GoToDefinitionFallback::FindAllReferences => {
16712                    match editor.update_in(cx, |editor, window, cx| {
16713                        editor.find_all_references(&FindAllReferences, window, cx)
16714                    })? {
16715                        Some(references) => references.await,
16716                        None => Ok(Navigated::No),
16717                    }
16718                }
16719            }
16720        })
16721    }
16722
16723    pub fn go_to_declaration(
16724        &mut self,
16725        _: &GoToDeclaration,
16726        window: &mut Window,
16727        cx: &mut Context<Self>,
16728    ) -> Task<Result<Navigated>> {
16729        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16730    }
16731
16732    pub fn go_to_declaration_split(
16733        &mut self,
16734        _: &GoToDeclaration,
16735        window: &mut Window,
16736        cx: &mut Context<Self>,
16737    ) -> Task<Result<Navigated>> {
16738        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16739    }
16740
16741    pub fn go_to_implementation(
16742        &mut self,
16743        _: &GoToImplementation,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) -> Task<Result<Navigated>> {
16747        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16748    }
16749
16750    pub fn go_to_implementation_split(
16751        &mut self,
16752        _: &GoToImplementationSplit,
16753        window: &mut Window,
16754        cx: &mut Context<Self>,
16755    ) -> Task<Result<Navigated>> {
16756        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16757    }
16758
16759    pub fn go_to_type_definition(
16760        &mut self,
16761        _: &GoToTypeDefinition,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) -> Task<Result<Navigated>> {
16765        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16766    }
16767
16768    pub fn go_to_definition_split(
16769        &mut self,
16770        _: &GoToDefinitionSplit,
16771        window: &mut Window,
16772        cx: &mut Context<Self>,
16773    ) -> Task<Result<Navigated>> {
16774        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16775    }
16776
16777    pub fn go_to_type_definition_split(
16778        &mut self,
16779        _: &GoToTypeDefinitionSplit,
16780        window: &mut Window,
16781        cx: &mut Context<Self>,
16782    ) -> Task<Result<Navigated>> {
16783        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16784    }
16785
16786    fn go_to_definition_of_kind(
16787        &mut self,
16788        kind: GotoDefinitionKind,
16789        split: bool,
16790        window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) -> Task<Result<Navigated>> {
16793        let Some(provider) = self.semantics_provider.clone() else {
16794            return Task::ready(Ok(Navigated::No));
16795        };
16796        let head = self
16797            .selections
16798            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16799            .head();
16800        let buffer = self.buffer.read(cx);
16801        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16802            return Task::ready(Ok(Navigated::No));
16803        };
16804        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16805            return Task::ready(Ok(Navigated::No));
16806        };
16807
16808        cx.spawn_in(window, async move |editor, cx| {
16809            let Some(definitions) = definitions.await? else {
16810                return Ok(Navigated::No);
16811            };
16812            let navigated = editor
16813                .update_in(cx, |editor, window, cx| {
16814                    editor.navigate_to_hover_links(
16815                        Some(kind),
16816                        definitions
16817                            .into_iter()
16818                            .filter(|location| {
16819                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16820                            })
16821                            .map(HoverLink::Text)
16822                            .collect::<Vec<_>>(),
16823                        split,
16824                        window,
16825                        cx,
16826                    )
16827                })?
16828                .await?;
16829            anyhow::Ok(navigated)
16830        })
16831    }
16832
16833    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16834        let selection = self.selections.newest_anchor();
16835        let head = selection.head();
16836        let tail = selection.tail();
16837
16838        let Some((buffer, start_position)) =
16839            self.buffer.read(cx).text_anchor_for_position(head, cx)
16840        else {
16841            return;
16842        };
16843
16844        let end_position = if head != tail {
16845            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16846                return;
16847            };
16848            Some(pos)
16849        } else {
16850            None
16851        };
16852
16853        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16854            let url = if let Some(end_pos) = end_position {
16855                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16856            } else {
16857                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16858            };
16859
16860            if let Some(url) = url {
16861                cx.update(|window, cx| {
16862                    if parse_zed_link(&url, cx).is_some() {
16863                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16864                    } else {
16865                        cx.open_url(&url);
16866                    }
16867                })?;
16868            }
16869
16870            anyhow::Ok(())
16871        });
16872
16873        url_finder.detach();
16874    }
16875
16876    pub fn open_selected_filename(
16877        &mut self,
16878        _: &OpenSelectedFilename,
16879        window: &mut Window,
16880        cx: &mut Context<Self>,
16881    ) {
16882        let Some(workspace) = self.workspace() else {
16883            return;
16884        };
16885
16886        let position = self.selections.newest_anchor().head();
16887
16888        let Some((buffer, buffer_position)) =
16889            self.buffer.read(cx).text_anchor_for_position(position, cx)
16890        else {
16891            return;
16892        };
16893
16894        let project = self.project.clone();
16895
16896        cx.spawn_in(window, async move |_, cx| {
16897            let result = find_file(&buffer, project, buffer_position, cx).await;
16898
16899            if let Some((_, path)) = result {
16900                workspace
16901                    .update_in(cx, |workspace, window, cx| {
16902                        workspace.open_resolved_path(path, window, cx)
16903                    })?
16904                    .await?;
16905            }
16906            anyhow::Ok(())
16907        })
16908        .detach();
16909    }
16910
16911    pub(crate) fn navigate_to_hover_links(
16912        &mut self,
16913        kind: Option<GotoDefinitionKind>,
16914        definitions: Vec<HoverLink>,
16915        split: bool,
16916        window: &mut Window,
16917        cx: &mut Context<Editor>,
16918    ) -> Task<Result<Navigated>> {
16919        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16920        let mut first_url_or_file = None;
16921        let definitions: Vec<_> = definitions
16922            .into_iter()
16923            .filter_map(|def| match def {
16924                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16925                HoverLink::InlayHint(lsp_location, server_id) => {
16926                    let computation =
16927                        self.compute_target_location(lsp_location, server_id, window, cx);
16928                    Some(cx.background_spawn(computation))
16929                }
16930                HoverLink::Url(url) => {
16931                    first_url_or_file = Some(Either::Left(url));
16932                    None
16933                }
16934                HoverLink::File(path) => {
16935                    first_url_or_file = Some(Either::Right(path));
16936                    None
16937                }
16938            })
16939            .collect();
16940
16941        let workspace = self.workspace();
16942
16943        cx.spawn_in(window, async move |editor, cx| {
16944            let locations: Vec<Location> = future::join_all(definitions)
16945                .await
16946                .into_iter()
16947                .filter_map(|location| location.transpose())
16948                .collect::<Result<_>>()
16949                .context("location tasks")?;
16950            let mut locations = cx.update(|_, cx| {
16951                locations
16952                    .into_iter()
16953                    .map(|location| {
16954                        let buffer = location.buffer.read(cx);
16955                        (location.buffer, location.range.to_point(buffer))
16956                    })
16957                    .into_group_map()
16958            })?;
16959            let mut num_locations = 0;
16960            for ranges in locations.values_mut() {
16961                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16962                ranges.dedup();
16963                num_locations += ranges.len();
16964            }
16965
16966            if num_locations > 1 {
16967                let Some(workspace) = workspace else {
16968                    return Ok(Navigated::No);
16969                };
16970
16971                let tab_kind = match kind {
16972                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16973                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16974                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16975                    Some(GotoDefinitionKind::Type) => "Types",
16976                };
16977                let title = editor
16978                    .update_in(cx, |_, _, cx| {
16979                        let target = locations
16980                            .iter()
16981                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16982                            .map(|(buffer, location)| {
16983                                buffer
16984                                    .read(cx)
16985                                    .text_for_range(location.clone())
16986                                    .collect::<String>()
16987                            })
16988                            .filter(|text| !text.contains('\n'))
16989                            .unique()
16990                            .take(3)
16991                            .join(", ");
16992                        if target.is_empty() {
16993                            tab_kind.to_owned()
16994                        } else {
16995                            format!("{tab_kind} for {target}")
16996                        }
16997                    })
16998                    .context("buffer title")?;
16999
17000                let opened = workspace
17001                    .update_in(cx, |workspace, window, cx| {
17002                        Self::open_locations_in_multibuffer(
17003                            workspace,
17004                            locations,
17005                            title,
17006                            split,
17007                            MultibufferSelectionMode::First,
17008                            window,
17009                            cx,
17010                        )
17011                    })
17012                    .is_ok();
17013
17014                anyhow::Ok(Navigated::from_bool(opened))
17015            } else if num_locations == 0 {
17016                // If there is one url or file, open it directly
17017                match first_url_or_file {
17018                    Some(Either::Left(url)) => {
17019                        cx.update(|_, cx| cx.open_url(&url))?;
17020                        Ok(Navigated::Yes)
17021                    }
17022                    Some(Either::Right(path)) => {
17023                        let Some(workspace) = workspace else {
17024                            return Ok(Navigated::No);
17025                        };
17026
17027                        workspace
17028                            .update_in(cx, |workspace, window, cx| {
17029                                workspace.open_resolved_path(path, window, cx)
17030                            })?
17031                            .await?;
17032                        Ok(Navigated::Yes)
17033                    }
17034                    None => Ok(Navigated::No),
17035                }
17036            } else {
17037                let Some(workspace) = workspace else {
17038                    return Ok(Navigated::No);
17039                };
17040
17041                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17042                let target_range = target_ranges.first().unwrap().clone();
17043
17044                editor.update_in(cx, |editor, window, cx| {
17045                    let range = target_range.to_point(target_buffer.read(cx));
17046                    let range = editor.range_for_match(&range);
17047                    let range = collapse_multiline_range(range);
17048
17049                    if !split
17050                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17051                    {
17052                        editor.go_to_singleton_buffer_range(range, window, cx);
17053                    } else {
17054                        let pane = workspace.read(cx).active_pane().clone();
17055                        window.defer(cx, move |window, cx| {
17056                            let target_editor: Entity<Self> =
17057                                workspace.update(cx, |workspace, cx| {
17058                                    let pane = if split {
17059                                        workspace.adjacent_pane(window, cx)
17060                                    } else {
17061                                        workspace.active_pane().clone()
17062                                    };
17063
17064                                    workspace.open_project_item(
17065                                        pane,
17066                                        target_buffer.clone(),
17067                                        true,
17068                                        true,
17069                                        window,
17070                                        cx,
17071                                    )
17072                                });
17073                            target_editor.update(cx, |target_editor, cx| {
17074                                // When selecting a definition in a different buffer, disable the nav history
17075                                // to avoid creating a history entry at the previous cursor location.
17076                                pane.update(cx, |pane, _| pane.disable_history());
17077                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17078                                pane.update(cx, |pane, _| pane.enable_history());
17079                            });
17080                        });
17081                    }
17082                    Navigated::Yes
17083                })
17084            }
17085        })
17086    }
17087
17088    fn compute_target_location(
17089        &self,
17090        lsp_location: lsp::Location,
17091        server_id: LanguageServerId,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) -> Task<anyhow::Result<Option<Location>>> {
17095        let Some(project) = self.project.clone() else {
17096            return Task::ready(Ok(None));
17097        };
17098
17099        cx.spawn_in(window, async move |editor, cx| {
17100            let location_task = editor.update(cx, |_, cx| {
17101                project.update(cx, |project, cx| {
17102                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17103                })
17104            })?;
17105            let location = Some({
17106                let target_buffer_handle = location_task.await.context("open local buffer")?;
17107                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17108                    let target_start = target_buffer
17109                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17110                    let target_end = target_buffer
17111                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17112                    target_buffer.anchor_after(target_start)
17113                        ..target_buffer.anchor_before(target_end)
17114                })?;
17115                Location {
17116                    buffer: target_buffer_handle,
17117                    range,
17118                }
17119            });
17120            Ok(location)
17121        })
17122    }
17123
17124    fn go_to_next_reference(
17125        &mut self,
17126        _: &GoToNextReference,
17127        window: &mut Window,
17128        cx: &mut Context<Self>,
17129    ) {
17130        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17131        if let Some(task) = task {
17132            task.detach();
17133        };
17134    }
17135
17136    fn go_to_prev_reference(
17137        &mut self,
17138        _: &GoToPreviousReference,
17139        window: &mut Window,
17140        cx: &mut Context<Self>,
17141    ) {
17142        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17143        if let Some(task) = task {
17144            task.detach();
17145        };
17146    }
17147
17148    pub fn go_to_reference_before_or_after_position(
17149        &mut self,
17150        direction: Direction,
17151        count: usize,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) -> Option<Task<Result<()>>> {
17155        let selection = self.selections.newest_anchor();
17156        let head = selection.head();
17157
17158        let multi_buffer = self.buffer.read(cx);
17159
17160        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17161        let workspace = self.workspace()?;
17162        let project = workspace.read(cx).project().clone();
17163        let references =
17164            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17165        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17166            let Some(locations) = references.await? else {
17167                return Ok(());
17168            };
17169
17170            if locations.is_empty() {
17171                // totally normal - the cursor may be on something which is not
17172                // a symbol (e.g. a keyword)
17173                log::info!("no references found under cursor");
17174                return Ok(());
17175            }
17176
17177            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17178
17179            let (locations, current_location_index) =
17180                multi_buffer.update(cx, |multi_buffer, cx| {
17181                    let mut locations = locations
17182                        .into_iter()
17183                        .filter_map(|loc| {
17184                            let start = multi_buffer.buffer_anchor_to_anchor(
17185                                &loc.buffer,
17186                                loc.range.start,
17187                                cx,
17188                            )?;
17189                            let end = multi_buffer.buffer_anchor_to_anchor(
17190                                &loc.buffer,
17191                                loc.range.end,
17192                                cx,
17193                            )?;
17194                            Some(start..end)
17195                        })
17196                        .collect::<Vec<_>>();
17197
17198                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17199                    // There is an O(n) implementation, but given this list will be
17200                    // small (usually <100 items), the extra O(log(n)) factor isn't
17201                    // worth the (surprisingly large amount of) extra complexity.
17202                    locations
17203                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17204
17205                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17206
17207                    let current_location_index = locations.iter().position(|loc| {
17208                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17209                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17210                    });
17211
17212                    (locations, current_location_index)
17213                })?;
17214
17215            let Some(current_location_index) = current_location_index else {
17216                // This indicates something has gone wrong, because we already
17217                // handle the "no references" case above
17218                log::error!(
17219                    "failed to find current reference under cursor. Total references: {}",
17220                    locations.len()
17221                );
17222                return Ok(());
17223            };
17224
17225            let destination_location_index = match direction {
17226                Direction::Next => (current_location_index + count) % locations.len(),
17227                Direction::Prev => {
17228                    (current_location_index + locations.len() - count % locations.len())
17229                        % locations.len()
17230                }
17231            };
17232
17233            // TODO(cameron): is this needed?
17234            // the thinking is to avoid "jumping to the current location" (avoid
17235            // polluting "jumplist" in vim terms)
17236            if current_location_index == destination_location_index {
17237                return Ok(());
17238            }
17239
17240            let Range { start, end } = locations[destination_location_index];
17241
17242            editor.update_in(cx, |editor, window, cx| {
17243                let effects = SelectionEffects::default();
17244
17245                editor.unfold_ranges(&[start..end], false, false, cx);
17246                editor.change_selections(effects, window, cx, |s| {
17247                    s.select_ranges([start..start]);
17248                });
17249            })?;
17250
17251            Ok(())
17252        }))
17253    }
17254
17255    pub fn find_all_references(
17256        &mut self,
17257        _: &FindAllReferences,
17258        window: &mut Window,
17259        cx: &mut Context<Self>,
17260    ) -> Option<Task<Result<Navigated>>> {
17261        let selection = self
17262            .selections
17263            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17264        let multi_buffer = self.buffer.read(cx);
17265        let head = selection.head();
17266
17267        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17268        let head_anchor = multi_buffer_snapshot.anchor_at(
17269            head,
17270            if head < selection.tail() {
17271                Bias::Right
17272            } else {
17273                Bias::Left
17274            },
17275        );
17276
17277        match self
17278            .find_all_references_task_sources
17279            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17280        {
17281            Ok(_) => {
17282                log::info!(
17283                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17284                );
17285                return None;
17286            }
17287            Err(i) => {
17288                self.find_all_references_task_sources.insert(i, head_anchor);
17289            }
17290        }
17291
17292        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17293        let workspace = self.workspace()?;
17294        let project = workspace.read(cx).project().clone();
17295        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17296        Some(cx.spawn_in(window, async move |editor, cx| {
17297            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17298                if let Ok(i) = editor
17299                    .find_all_references_task_sources
17300                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17301                {
17302                    editor.find_all_references_task_sources.remove(i);
17303                }
17304            });
17305
17306            let Some(locations) = references.await? else {
17307                return anyhow::Ok(Navigated::No);
17308            };
17309            let mut locations = cx.update(|_, cx| {
17310                locations
17311                    .into_iter()
17312                    .map(|location| {
17313                        let buffer = location.buffer.read(cx);
17314                        (location.buffer, location.range.to_point(buffer))
17315                    })
17316                    .into_group_map()
17317            })?;
17318            if locations.is_empty() {
17319                return anyhow::Ok(Navigated::No);
17320            }
17321            for ranges in locations.values_mut() {
17322                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17323                ranges.dedup();
17324            }
17325
17326            workspace.update_in(cx, |workspace, window, cx| {
17327                let target = locations
17328                    .iter()
17329                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17330                    .map(|(buffer, location)| {
17331                        buffer
17332                            .read(cx)
17333                            .text_for_range(location.clone())
17334                            .collect::<String>()
17335                    })
17336                    .filter(|text| !text.contains('\n'))
17337                    .unique()
17338                    .take(3)
17339                    .join(", ");
17340                let title = if target.is_empty() {
17341                    "References".to_owned()
17342                } else {
17343                    format!("References to {target}")
17344                };
17345                Self::open_locations_in_multibuffer(
17346                    workspace,
17347                    locations,
17348                    title,
17349                    false,
17350                    MultibufferSelectionMode::First,
17351                    window,
17352                    cx,
17353                );
17354                Navigated::Yes
17355            })
17356        }))
17357    }
17358
17359    /// Opens a multibuffer with the given project locations in it
17360    pub fn open_locations_in_multibuffer(
17361        workspace: &mut Workspace,
17362        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17363        title: String,
17364        split: bool,
17365        multibuffer_selection_mode: MultibufferSelectionMode,
17366        window: &mut Window,
17367        cx: &mut Context<Workspace>,
17368    ) {
17369        if locations.is_empty() {
17370            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17371            return;
17372        }
17373
17374        let capability = workspace.project().read(cx).capability();
17375        let mut ranges = <Vec<Range<Anchor>>>::new();
17376
17377        // a key to find existing multibuffer editors with the same set of locations
17378        // to prevent us from opening more and more multibuffer tabs for searches and the like
17379        let mut key = (title.clone(), vec![]);
17380        let excerpt_buffer = cx.new(|cx| {
17381            let key = &mut key.1;
17382            let mut multibuffer = MultiBuffer::new(capability);
17383            for (buffer, mut ranges_for_buffer) in locations {
17384                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17385                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17386                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17387                    PathKey::for_buffer(&buffer, cx),
17388                    buffer.clone(),
17389                    ranges_for_buffer,
17390                    multibuffer_context_lines(cx),
17391                    cx,
17392                );
17393                ranges.extend(new_ranges)
17394            }
17395
17396            multibuffer.with_title(title)
17397        });
17398        let existing = workspace.active_pane().update(cx, |pane, cx| {
17399            pane.items()
17400                .filter_map(|item| item.downcast::<Editor>())
17401                .find(|editor| {
17402                    editor
17403                        .read(cx)
17404                        .lookup_key
17405                        .as_ref()
17406                        .and_then(|it| {
17407                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17408                        })
17409                        .is_some_and(|it| *it == key)
17410                })
17411        });
17412        let editor = existing.unwrap_or_else(|| {
17413            cx.new(|cx| {
17414                let mut editor = Editor::for_multibuffer(
17415                    excerpt_buffer,
17416                    Some(workspace.project().clone()),
17417                    window,
17418                    cx,
17419                );
17420                editor.lookup_key = Some(Box::new(key));
17421                editor
17422            })
17423        });
17424        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17425            MultibufferSelectionMode::First => {
17426                if let Some(first_range) = ranges.first() {
17427                    editor.change_selections(
17428                        SelectionEffects::no_scroll(),
17429                        window,
17430                        cx,
17431                        |selections| {
17432                            selections.clear_disjoint();
17433                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17434                        },
17435                    );
17436                }
17437                editor.highlight_background::<Self>(
17438                    &ranges,
17439                    |theme| theme.colors().editor_highlighted_line_background,
17440                    cx,
17441                );
17442            }
17443            MultibufferSelectionMode::All => {
17444                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17445                    selections.clear_disjoint();
17446                    selections.select_anchor_ranges(ranges);
17447                });
17448            }
17449        });
17450
17451        let item = Box::new(editor);
17452        let item_id = item.item_id();
17453
17454        if split {
17455            let pane = workspace.adjacent_pane(window, cx);
17456            workspace.add_item(pane, item, None, true, true, window, cx);
17457        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17458            let (preview_item_id, preview_item_idx) =
17459                workspace.active_pane().read_with(cx, |pane, _| {
17460                    (pane.preview_item_id(), pane.preview_item_idx())
17461                });
17462
17463            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17464
17465            if let Some(preview_item_id) = preview_item_id {
17466                workspace.active_pane().update(cx, |pane, cx| {
17467                    pane.remove_item(preview_item_id, false, false, window, cx);
17468                });
17469            }
17470        } else {
17471            workspace.add_item_to_active_pane(item, None, true, window, cx);
17472        }
17473        workspace.active_pane().update(cx, |pane, cx| {
17474            pane.set_preview_item_id(Some(item_id), cx);
17475        });
17476    }
17477
17478    pub fn rename(
17479        &mut self,
17480        _: &Rename,
17481        window: &mut Window,
17482        cx: &mut Context<Self>,
17483    ) -> Option<Task<Result<()>>> {
17484        use language::ToOffset as _;
17485
17486        let provider = self.semantics_provider.clone()?;
17487        let selection = self.selections.newest_anchor().clone();
17488        let (cursor_buffer, cursor_buffer_position) = self
17489            .buffer
17490            .read(cx)
17491            .text_anchor_for_position(selection.head(), cx)?;
17492        let (tail_buffer, cursor_buffer_position_end) = self
17493            .buffer
17494            .read(cx)
17495            .text_anchor_for_position(selection.tail(), cx)?;
17496        if tail_buffer != cursor_buffer {
17497            return None;
17498        }
17499
17500        let snapshot = cursor_buffer.read(cx).snapshot();
17501        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17502        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17503        let prepare_rename = provider
17504            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17505            .unwrap_or_else(|| Task::ready(Ok(None)));
17506        drop(snapshot);
17507
17508        Some(cx.spawn_in(window, async move |this, cx| {
17509            let rename_range = if let Some(range) = prepare_rename.await? {
17510                Some(range)
17511            } else {
17512                this.update(cx, |this, cx| {
17513                    let buffer = this.buffer.read(cx).snapshot(cx);
17514                    let mut buffer_highlights = this
17515                        .document_highlights_for_position(selection.head(), &buffer)
17516                        .filter(|highlight| {
17517                            highlight.start.excerpt_id == selection.head().excerpt_id
17518                                && highlight.end.excerpt_id == selection.head().excerpt_id
17519                        });
17520                    buffer_highlights
17521                        .next()
17522                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17523                })?
17524            };
17525            if let Some(rename_range) = rename_range {
17526                this.update_in(cx, |this, window, cx| {
17527                    let snapshot = cursor_buffer.read(cx).snapshot();
17528                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17529                    let cursor_offset_in_rename_range =
17530                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17531                    let cursor_offset_in_rename_range_end =
17532                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17533
17534                    this.take_rename(false, window, cx);
17535                    let buffer = this.buffer.read(cx).read(cx);
17536                    let cursor_offset = selection.head().to_offset(&buffer);
17537                    let rename_start =
17538                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17539                    let rename_end = rename_start + rename_buffer_range.len();
17540                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17541                    let mut old_highlight_id = None;
17542                    let old_name: Arc<str> = buffer
17543                        .chunks(rename_start..rename_end, true)
17544                        .map(|chunk| {
17545                            if old_highlight_id.is_none() {
17546                                old_highlight_id = chunk.syntax_highlight_id;
17547                            }
17548                            chunk.text
17549                        })
17550                        .collect::<String>()
17551                        .into();
17552
17553                    drop(buffer);
17554
17555                    // Position the selection in the rename editor so that it matches the current selection.
17556                    this.show_local_selections = false;
17557                    let rename_editor = cx.new(|cx| {
17558                        let mut editor = Editor::single_line(window, cx);
17559                        editor.buffer.update(cx, |buffer, cx| {
17560                            buffer.edit(
17561                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17562                                None,
17563                                cx,
17564                            )
17565                        });
17566                        let cursor_offset_in_rename_range =
17567                            MultiBufferOffset(cursor_offset_in_rename_range);
17568                        let cursor_offset_in_rename_range_end =
17569                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17570                        let rename_selection_range = match cursor_offset_in_rename_range
17571                            .cmp(&cursor_offset_in_rename_range_end)
17572                        {
17573                            Ordering::Equal => {
17574                                editor.select_all(&SelectAll, window, cx);
17575                                return editor;
17576                            }
17577                            Ordering::Less => {
17578                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17579                            }
17580                            Ordering::Greater => {
17581                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17582                            }
17583                        };
17584                        if rename_selection_range.end.0 > old_name.len() {
17585                            editor.select_all(&SelectAll, window, cx);
17586                        } else {
17587                            editor.change_selections(Default::default(), window, cx, |s| {
17588                                s.select_ranges([rename_selection_range]);
17589                            });
17590                        }
17591                        editor
17592                    });
17593                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17594                        if e == &EditorEvent::Focused {
17595                            cx.emit(EditorEvent::FocusedIn)
17596                        }
17597                    })
17598                    .detach();
17599
17600                    let write_highlights =
17601                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17602                    let read_highlights =
17603                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17604                    let ranges = write_highlights
17605                        .iter()
17606                        .flat_map(|(_, ranges)| ranges.iter())
17607                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17608                        .cloned()
17609                        .collect();
17610
17611                    this.highlight_text::<Rename>(
17612                        ranges,
17613                        HighlightStyle {
17614                            fade_out: Some(0.6),
17615                            ..Default::default()
17616                        },
17617                        cx,
17618                    );
17619                    let rename_focus_handle = rename_editor.focus_handle(cx);
17620                    window.focus(&rename_focus_handle);
17621                    let block_id = this.insert_blocks(
17622                        [BlockProperties {
17623                            style: BlockStyle::Flex,
17624                            placement: BlockPlacement::Below(range.start),
17625                            height: Some(1),
17626                            render: Arc::new({
17627                                let rename_editor = rename_editor.clone();
17628                                move |cx: &mut BlockContext| {
17629                                    let mut text_style = cx.editor_style.text.clone();
17630                                    if let Some(highlight_style) = old_highlight_id
17631                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17632                                    {
17633                                        text_style = text_style.highlight(highlight_style);
17634                                    }
17635                                    div()
17636                                        .block_mouse_except_scroll()
17637                                        .pl(cx.anchor_x)
17638                                        .child(EditorElement::new(
17639                                            &rename_editor,
17640                                            EditorStyle {
17641                                                background: cx.theme().system().transparent,
17642                                                local_player: cx.editor_style.local_player,
17643                                                text: text_style,
17644                                                scrollbar_width: cx.editor_style.scrollbar_width,
17645                                                syntax: cx.editor_style.syntax.clone(),
17646                                                status: cx.editor_style.status.clone(),
17647                                                inlay_hints_style: HighlightStyle {
17648                                                    font_weight: Some(FontWeight::BOLD),
17649                                                    ..make_inlay_hints_style(cx.app)
17650                                                },
17651                                                edit_prediction_styles: make_suggestion_styles(
17652                                                    cx.app,
17653                                                ),
17654                                                ..EditorStyle::default()
17655                                            },
17656                                        ))
17657                                        .into_any_element()
17658                                }
17659                            }),
17660                            priority: 0,
17661                        }],
17662                        Some(Autoscroll::fit()),
17663                        cx,
17664                    )[0];
17665                    this.pending_rename = Some(RenameState {
17666                        range,
17667                        old_name,
17668                        editor: rename_editor,
17669                        block_id,
17670                    });
17671                })?;
17672            }
17673
17674            Ok(())
17675        }))
17676    }
17677
17678    pub fn confirm_rename(
17679        &mut self,
17680        _: &ConfirmRename,
17681        window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) -> Option<Task<Result<()>>> {
17684        let rename = self.take_rename(false, window, cx)?;
17685        let workspace = self.workspace()?.downgrade();
17686        let (buffer, start) = self
17687            .buffer
17688            .read(cx)
17689            .text_anchor_for_position(rename.range.start, cx)?;
17690        let (end_buffer, _) = self
17691            .buffer
17692            .read(cx)
17693            .text_anchor_for_position(rename.range.end, cx)?;
17694        if buffer != end_buffer {
17695            return None;
17696        }
17697
17698        let old_name = rename.old_name;
17699        let new_name = rename.editor.read(cx).text(cx);
17700
17701        let rename = self.semantics_provider.as_ref()?.perform_rename(
17702            &buffer,
17703            start,
17704            new_name.clone(),
17705            cx,
17706        )?;
17707
17708        Some(cx.spawn_in(window, async move |editor, cx| {
17709            let project_transaction = rename.await?;
17710            Self::open_project_transaction(
17711                &editor,
17712                workspace,
17713                project_transaction,
17714                format!("Rename: {}{}", old_name, new_name),
17715                cx,
17716            )
17717            .await?;
17718
17719            editor.update(cx, |editor, cx| {
17720                editor.refresh_document_highlights(cx);
17721            })?;
17722            Ok(())
17723        }))
17724    }
17725
17726    fn take_rename(
17727        &mut self,
17728        moving_cursor: bool,
17729        window: &mut Window,
17730        cx: &mut Context<Self>,
17731    ) -> Option<RenameState> {
17732        let rename = self.pending_rename.take()?;
17733        if rename.editor.focus_handle(cx).is_focused(window) {
17734            window.focus(&self.focus_handle);
17735        }
17736
17737        self.remove_blocks(
17738            [rename.block_id].into_iter().collect(),
17739            Some(Autoscroll::fit()),
17740            cx,
17741        );
17742        self.clear_highlights::<Rename>(cx);
17743        self.show_local_selections = true;
17744
17745        if moving_cursor {
17746            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17747                editor
17748                    .selections
17749                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17750                    .head()
17751            });
17752
17753            // Update the selection to match the position of the selection inside
17754            // the rename editor.
17755            let snapshot = self.buffer.read(cx).read(cx);
17756            let rename_range = rename.range.to_offset(&snapshot);
17757            let cursor_in_editor = snapshot
17758                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17759                .min(rename_range.end);
17760            drop(snapshot);
17761
17762            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17763                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17764            });
17765        } else {
17766            self.refresh_document_highlights(cx);
17767        }
17768
17769        Some(rename)
17770    }
17771
17772    pub fn pending_rename(&self) -> Option<&RenameState> {
17773        self.pending_rename.as_ref()
17774    }
17775
17776    fn format(
17777        &mut self,
17778        _: &Format,
17779        window: &mut Window,
17780        cx: &mut Context<Self>,
17781    ) -> Option<Task<Result<()>>> {
17782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17783
17784        let project = match &self.project {
17785            Some(project) => project.clone(),
17786            None => return None,
17787        };
17788
17789        Some(self.perform_format(
17790            project,
17791            FormatTrigger::Manual,
17792            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17793            window,
17794            cx,
17795        ))
17796    }
17797
17798    fn format_selections(
17799        &mut self,
17800        _: &FormatSelections,
17801        window: &mut Window,
17802        cx: &mut Context<Self>,
17803    ) -> Option<Task<Result<()>>> {
17804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17805
17806        let project = match &self.project {
17807            Some(project) => project.clone(),
17808            None => return None,
17809        };
17810
17811        let ranges = self
17812            .selections
17813            .all_adjusted(&self.display_snapshot(cx))
17814            .into_iter()
17815            .map(|selection| selection.range())
17816            .collect_vec();
17817
17818        Some(self.perform_format(
17819            project,
17820            FormatTrigger::Manual,
17821            FormatTarget::Ranges(ranges),
17822            window,
17823            cx,
17824        ))
17825    }
17826
17827    fn perform_format(
17828        &mut self,
17829        project: Entity<Project>,
17830        trigger: FormatTrigger,
17831        target: FormatTarget,
17832        window: &mut Window,
17833        cx: &mut Context<Self>,
17834    ) -> Task<Result<()>> {
17835        let buffer = self.buffer.clone();
17836        let (buffers, target) = match target {
17837            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17838            FormatTarget::Ranges(selection_ranges) => {
17839                let multi_buffer = buffer.read(cx);
17840                let snapshot = multi_buffer.read(cx);
17841                let mut buffers = HashSet::default();
17842                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17843                    BTreeMap::new();
17844                for selection_range in selection_ranges {
17845                    for (buffer, buffer_range, _) in
17846                        snapshot.range_to_buffer_ranges(selection_range)
17847                    {
17848                        let buffer_id = buffer.remote_id();
17849                        let start = buffer.anchor_before(buffer_range.start);
17850                        let end = buffer.anchor_after(buffer_range.end);
17851                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17852                        buffer_id_to_ranges
17853                            .entry(buffer_id)
17854                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17855                            .or_insert_with(|| vec![start..end]);
17856                    }
17857                }
17858                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17859            }
17860        };
17861
17862        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17863        let selections_prev = transaction_id_prev
17864            .and_then(|transaction_id_prev| {
17865                // default to selections as they were after the last edit, if we have them,
17866                // instead of how they are now.
17867                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17868                // will take you back to where you made the last edit, instead of staying where you scrolled
17869                self.selection_history
17870                    .transaction(transaction_id_prev)
17871                    .map(|t| t.0.clone())
17872            })
17873            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17874
17875        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17876        let format = project.update(cx, |project, cx| {
17877            project.format(buffers, target, true, trigger, cx)
17878        });
17879
17880        cx.spawn_in(window, async move |editor, cx| {
17881            let transaction = futures::select_biased! {
17882                transaction = format.log_err().fuse() => transaction,
17883                () = timeout => {
17884                    log::warn!("timed out waiting for formatting");
17885                    None
17886                }
17887            };
17888
17889            buffer
17890                .update(cx, |buffer, cx| {
17891                    if let Some(transaction) = transaction
17892                        && !buffer.is_singleton()
17893                    {
17894                        buffer.push_transaction(&transaction.0, cx);
17895                    }
17896                    cx.notify();
17897                })
17898                .ok();
17899
17900            if let Some(transaction_id_now) =
17901                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17902            {
17903                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17904                if has_new_transaction {
17905                    _ = editor.update(cx, |editor, _| {
17906                        editor
17907                            .selection_history
17908                            .insert_transaction(transaction_id_now, selections_prev);
17909                    });
17910                }
17911            }
17912
17913            Ok(())
17914        })
17915    }
17916
17917    fn organize_imports(
17918        &mut self,
17919        _: &OrganizeImports,
17920        window: &mut Window,
17921        cx: &mut Context<Self>,
17922    ) -> Option<Task<Result<()>>> {
17923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17924        let project = match &self.project {
17925            Some(project) => project.clone(),
17926            None => return None,
17927        };
17928        Some(self.perform_code_action_kind(
17929            project,
17930            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17931            window,
17932            cx,
17933        ))
17934    }
17935
17936    fn perform_code_action_kind(
17937        &mut self,
17938        project: Entity<Project>,
17939        kind: CodeActionKind,
17940        window: &mut Window,
17941        cx: &mut Context<Self>,
17942    ) -> Task<Result<()>> {
17943        let buffer = self.buffer.clone();
17944        let buffers = buffer.read(cx).all_buffers();
17945        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17946        let apply_action = project.update(cx, |project, cx| {
17947            project.apply_code_action_kind(buffers, kind, true, cx)
17948        });
17949        cx.spawn_in(window, async move |_, cx| {
17950            let transaction = futures::select_biased! {
17951                () = timeout => {
17952                    log::warn!("timed out waiting for executing code action");
17953                    None
17954                }
17955                transaction = apply_action.log_err().fuse() => transaction,
17956            };
17957            buffer
17958                .update(cx, |buffer, cx| {
17959                    // check if we need this
17960                    if let Some(transaction) = transaction
17961                        && !buffer.is_singleton()
17962                    {
17963                        buffer.push_transaction(&transaction.0, cx);
17964                    }
17965                    cx.notify();
17966                })
17967                .ok();
17968            Ok(())
17969        })
17970    }
17971
17972    pub fn restart_language_server(
17973        &mut self,
17974        _: &RestartLanguageServer,
17975        _: &mut Window,
17976        cx: &mut Context<Self>,
17977    ) {
17978        if let Some(project) = self.project.clone() {
17979            self.buffer.update(cx, |multi_buffer, cx| {
17980                project.update(cx, |project, cx| {
17981                    project.restart_language_servers_for_buffers(
17982                        multi_buffer.all_buffers().into_iter().collect(),
17983                        HashSet::default(),
17984                        cx,
17985                    );
17986                });
17987            })
17988        }
17989    }
17990
17991    pub fn stop_language_server(
17992        &mut self,
17993        _: &StopLanguageServer,
17994        _: &mut Window,
17995        cx: &mut Context<Self>,
17996    ) {
17997        if let Some(project) = self.project.clone() {
17998            self.buffer.update(cx, |multi_buffer, cx| {
17999                project.update(cx, |project, cx| {
18000                    project.stop_language_servers_for_buffers(
18001                        multi_buffer.all_buffers().into_iter().collect(),
18002                        HashSet::default(),
18003                        cx,
18004                    );
18005                });
18006            });
18007            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18008        }
18009    }
18010
18011    fn cancel_language_server_work(
18012        workspace: &mut Workspace,
18013        _: &actions::CancelLanguageServerWork,
18014        _: &mut Window,
18015        cx: &mut Context<Workspace>,
18016    ) {
18017        let project = workspace.project();
18018        let buffers = workspace
18019            .active_item(cx)
18020            .and_then(|item| item.act_as::<Editor>(cx))
18021            .map_or(HashSet::default(), |editor| {
18022                editor.read(cx).buffer.read(cx).all_buffers()
18023            });
18024        project.update(cx, |project, cx| {
18025            project.cancel_language_server_work_for_buffers(buffers, cx);
18026        });
18027    }
18028
18029    fn show_character_palette(
18030        &mut self,
18031        _: &ShowCharacterPalette,
18032        window: &mut Window,
18033        _: &mut Context<Self>,
18034    ) {
18035        window.show_character_palette();
18036    }
18037
18038    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18039        if !self.diagnostics_enabled() {
18040            return;
18041        }
18042
18043        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18044            let buffer = self.buffer.read(cx).snapshot(cx);
18045            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18046            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18047            let is_valid = buffer
18048                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18049                .any(|entry| {
18050                    entry.diagnostic.is_primary
18051                        && !entry.range.is_empty()
18052                        && entry.range.start == primary_range_start
18053                        && entry.diagnostic.message == active_diagnostics.active_message
18054                });
18055
18056            if !is_valid {
18057                self.dismiss_diagnostics(cx);
18058            }
18059        }
18060    }
18061
18062    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18063        match &self.active_diagnostics {
18064            ActiveDiagnostic::Group(group) => Some(group),
18065            _ => None,
18066        }
18067    }
18068
18069    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18070        if !self.diagnostics_enabled() {
18071            return;
18072        }
18073        self.dismiss_diagnostics(cx);
18074        self.active_diagnostics = ActiveDiagnostic::All;
18075    }
18076
18077    fn activate_diagnostics(
18078        &mut self,
18079        buffer_id: BufferId,
18080        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18085            return;
18086        }
18087        self.dismiss_diagnostics(cx);
18088        let snapshot = self.snapshot(window, cx);
18089        let buffer = self.buffer.read(cx).snapshot(cx);
18090        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18091            return;
18092        };
18093
18094        let diagnostic_group = buffer
18095            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18096            .collect::<Vec<_>>();
18097
18098        let language_registry = self
18099            .project()
18100            .map(|project| project.read(cx).languages().clone());
18101
18102        let blocks = renderer.render_group(
18103            diagnostic_group,
18104            buffer_id,
18105            snapshot,
18106            cx.weak_entity(),
18107            language_registry,
18108            cx,
18109        );
18110
18111        let blocks = self.display_map.update(cx, |display_map, cx| {
18112            display_map.insert_blocks(blocks, cx).into_iter().collect()
18113        });
18114        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18115            active_range: buffer.anchor_before(diagnostic.range.start)
18116                ..buffer.anchor_after(diagnostic.range.end),
18117            active_message: diagnostic.diagnostic.message.clone(),
18118            group_id: diagnostic.diagnostic.group_id,
18119            blocks,
18120        });
18121        cx.notify();
18122    }
18123
18124    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18125        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18126            return;
18127        };
18128
18129        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18130        if let ActiveDiagnostic::Group(group) = prev {
18131            self.display_map.update(cx, |display_map, cx| {
18132                display_map.remove_blocks(group.blocks, cx);
18133            });
18134            cx.notify();
18135        }
18136    }
18137
18138    /// Disable inline diagnostics rendering for this editor.
18139    pub fn disable_inline_diagnostics(&mut self) {
18140        self.inline_diagnostics_enabled = false;
18141        self.inline_diagnostics_update = Task::ready(());
18142        self.inline_diagnostics.clear();
18143    }
18144
18145    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18146        self.diagnostics_enabled = false;
18147        self.dismiss_diagnostics(cx);
18148        self.inline_diagnostics_update = Task::ready(());
18149        self.inline_diagnostics.clear();
18150    }
18151
18152    pub fn disable_word_completions(&mut self) {
18153        self.word_completions_enabled = false;
18154    }
18155
18156    pub fn diagnostics_enabled(&self) -> bool {
18157        self.diagnostics_enabled && self.mode.is_full()
18158    }
18159
18160    pub fn inline_diagnostics_enabled(&self) -> bool {
18161        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18162    }
18163
18164    pub fn show_inline_diagnostics(&self) -> bool {
18165        self.show_inline_diagnostics
18166    }
18167
18168    pub fn toggle_inline_diagnostics(
18169        &mut self,
18170        _: &ToggleInlineDiagnostics,
18171        window: &mut Window,
18172        cx: &mut Context<Editor>,
18173    ) {
18174        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18175        self.refresh_inline_diagnostics(false, window, cx);
18176    }
18177
18178    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18179        self.diagnostics_max_severity = severity;
18180        self.display_map.update(cx, |display_map, _| {
18181            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18182        });
18183    }
18184
18185    pub fn toggle_diagnostics(
18186        &mut self,
18187        _: &ToggleDiagnostics,
18188        window: &mut Window,
18189        cx: &mut Context<Editor>,
18190    ) {
18191        if !self.diagnostics_enabled() {
18192            return;
18193        }
18194
18195        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18196            EditorSettings::get_global(cx)
18197                .diagnostics_max_severity
18198                .filter(|severity| severity != &DiagnosticSeverity::Off)
18199                .unwrap_or(DiagnosticSeverity::Hint)
18200        } else {
18201            DiagnosticSeverity::Off
18202        };
18203        self.set_max_diagnostics_severity(new_severity, cx);
18204        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18205            self.active_diagnostics = ActiveDiagnostic::None;
18206            self.inline_diagnostics_update = Task::ready(());
18207            self.inline_diagnostics.clear();
18208        } else {
18209            self.refresh_inline_diagnostics(false, window, cx);
18210        }
18211
18212        cx.notify();
18213    }
18214
18215    pub fn toggle_minimap(
18216        &mut self,
18217        _: &ToggleMinimap,
18218        window: &mut Window,
18219        cx: &mut Context<Editor>,
18220    ) {
18221        if self.supports_minimap(cx) {
18222            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18223        }
18224    }
18225
18226    fn refresh_inline_diagnostics(
18227        &mut self,
18228        debounce: bool,
18229        window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) {
18232        let max_severity = ProjectSettings::get_global(cx)
18233            .diagnostics
18234            .inline
18235            .max_severity
18236            .unwrap_or(self.diagnostics_max_severity);
18237
18238        if !self.inline_diagnostics_enabled()
18239            || !self.diagnostics_enabled()
18240            || !self.show_inline_diagnostics
18241            || max_severity == DiagnosticSeverity::Off
18242        {
18243            self.inline_diagnostics_update = Task::ready(());
18244            self.inline_diagnostics.clear();
18245            return;
18246        }
18247
18248        let debounce_ms = ProjectSettings::get_global(cx)
18249            .diagnostics
18250            .inline
18251            .update_debounce_ms;
18252        let debounce = if debounce && debounce_ms > 0 {
18253            Some(Duration::from_millis(debounce_ms))
18254        } else {
18255            None
18256        };
18257        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18258            if let Some(debounce) = debounce {
18259                cx.background_executor().timer(debounce).await;
18260            }
18261            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18262                editor
18263                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18264                    .ok()
18265            }) else {
18266                return;
18267            };
18268
18269            let new_inline_diagnostics = cx
18270                .background_spawn(async move {
18271                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18272                    for diagnostic_entry in
18273                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18274                    {
18275                        let message = diagnostic_entry
18276                            .diagnostic
18277                            .message
18278                            .split_once('\n')
18279                            .map(|(line, _)| line)
18280                            .map(SharedString::new)
18281                            .unwrap_or_else(|| {
18282                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18283                            });
18284                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18285                        let (Ok(i) | Err(i)) = inline_diagnostics
18286                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18287                        inline_diagnostics.insert(
18288                            i,
18289                            (
18290                                start_anchor,
18291                                InlineDiagnostic {
18292                                    message,
18293                                    group_id: diagnostic_entry.diagnostic.group_id,
18294                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18295                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18296                                    severity: diagnostic_entry.diagnostic.severity,
18297                                },
18298                            ),
18299                        );
18300                    }
18301                    inline_diagnostics
18302                })
18303                .await;
18304
18305            editor
18306                .update(cx, |editor, cx| {
18307                    editor.inline_diagnostics = new_inline_diagnostics;
18308                    cx.notify();
18309                })
18310                .ok();
18311        });
18312    }
18313
18314    fn pull_diagnostics(
18315        &mut self,
18316        buffer_id: Option<BufferId>,
18317        window: &Window,
18318        cx: &mut Context<Self>,
18319    ) -> Option<()> {
18320        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18321            return None;
18322        }
18323        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18324            .diagnostics
18325            .lsp_pull_diagnostics;
18326        if !pull_diagnostics_settings.enabled {
18327            return None;
18328        }
18329        let project = self.project()?.downgrade();
18330        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18331        let mut buffers = self.buffer.read(cx).all_buffers();
18332        buffers.retain(|buffer| {
18333            let buffer_id_to_retain = buffer.read(cx).remote_id();
18334            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18335                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18336        });
18337        if buffers.is_empty() {
18338            self.pull_diagnostics_task = Task::ready(());
18339            return None;
18340        }
18341
18342        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18343            cx.background_executor().timer(debounce).await;
18344
18345            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18346                buffers
18347                    .into_iter()
18348                    .filter_map(|buffer| {
18349                        project
18350                            .update(cx, |project, cx| {
18351                                project.lsp_store().update(cx, |lsp_store, cx| {
18352                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18353                                })
18354                            })
18355                            .ok()
18356                    })
18357                    .collect::<FuturesUnordered<_>>()
18358            }) else {
18359                return;
18360            };
18361
18362            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18363                match pull_task {
18364                    Ok(()) => {
18365                        if editor
18366                            .update_in(cx, |editor, window, cx| {
18367                                editor.update_diagnostics_state(window, cx);
18368                            })
18369                            .is_err()
18370                        {
18371                            return;
18372                        }
18373                    }
18374                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18375                }
18376            }
18377        });
18378
18379        Some(())
18380    }
18381
18382    pub fn set_selections_from_remote(
18383        &mut self,
18384        selections: Vec<Selection<Anchor>>,
18385        pending_selection: Option<Selection<Anchor>>,
18386        window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) {
18389        let old_cursor_position = self.selections.newest_anchor().head();
18390        self.selections
18391            .change_with(&self.display_snapshot(cx), |s| {
18392                s.select_anchors(selections);
18393                if let Some(pending_selection) = pending_selection {
18394                    s.set_pending(pending_selection, SelectMode::Character);
18395                } else {
18396                    s.clear_pending();
18397                }
18398            });
18399        self.selections_did_change(
18400            false,
18401            &old_cursor_position,
18402            SelectionEffects::default(),
18403            window,
18404            cx,
18405        );
18406    }
18407
18408    pub fn transact(
18409        &mut self,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18413    ) -> Option<TransactionId> {
18414        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18415            this.start_transaction_at(Instant::now(), window, cx);
18416            update(this, window, cx);
18417            this.end_transaction_at(Instant::now(), cx)
18418        })
18419    }
18420
18421    pub fn start_transaction_at(
18422        &mut self,
18423        now: Instant,
18424        window: &mut Window,
18425        cx: &mut Context<Self>,
18426    ) -> Option<TransactionId> {
18427        self.end_selection(window, cx);
18428        if let Some(tx_id) = self
18429            .buffer
18430            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18431        {
18432            self.selection_history
18433                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18434            cx.emit(EditorEvent::TransactionBegun {
18435                transaction_id: tx_id,
18436            });
18437            Some(tx_id)
18438        } else {
18439            None
18440        }
18441    }
18442
18443    pub fn end_transaction_at(
18444        &mut self,
18445        now: Instant,
18446        cx: &mut Context<Self>,
18447    ) -> Option<TransactionId> {
18448        if let Some(transaction_id) = self
18449            .buffer
18450            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18451        {
18452            if let Some((_, end_selections)) =
18453                self.selection_history.transaction_mut(transaction_id)
18454            {
18455                *end_selections = Some(self.selections.disjoint_anchors_arc());
18456            } else {
18457                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18458            }
18459
18460            cx.emit(EditorEvent::Edited { transaction_id });
18461            Some(transaction_id)
18462        } else {
18463            None
18464        }
18465    }
18466
18467    pub fn modify_transaction_selection_history(
18468        &mut self,
18469        transaction_id: TransactionId,
18470        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18471    ) -> bool {
18472        self.selection_history
18473            .transaction_mut(transaction_id)
18474            .map(modify)
18475            .is_some()
18476    }
18477
18478    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18479        if self.selection_mark_mode {
18480            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18481                s.move_with(|_, sel| {
18482                    sel.collapse_to(sel.head(), SelectionGoal::None);
18483                });
18484            })
18485        }
18486        self.selection_mark_mode = true;
18487        cx.notify();
18488    }
18489
18490    pub fn swap_selection_ends(
18491        &mut self,
18492        _: &actions::SwapSelectionEnds,
18493        window: &mut Window,
18494        cx: &mut Context<Self>,
18495    ) {
18496        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18497            s.move_with(|_, sel| {
18498                if sel.start != sel.end {
18499                    sel.reversed = !sel.reversed
18500                }
18501            });
18502        });
18503        self.request_autoscroll(Autoscroll::newest(), cx);
18504        cx.notify();
18505    }
18506
18507    pub fn toggle_focus(
18508        workspace: &mut Workspace,
18509        _: &actions::ToggleFocus,
18510        window: &mut Window,
18511        cx: &mut Context<Workspace>,
18512    ) {
18513        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18514            return;
18515        };
18516        workspace.activate_item(&item, true, true, window, cx);
18517    }
18518
18519    pub fn toggle_fold(
18520        &mut self,
18521        _: &actions::ToggleFold,
18522        window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18526            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18527            let selection = self.selections.newest::<Point>(&display_map);
18528
18529            let range = if selection.is_empty() {
18530                let point = selection.head().to_display_point(&display_map);
18531                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18532                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18533                    .to_point(&display_map);
18534                start..end
18535            } else {
18536                selection.range()
18537            };
18538            if display_map.folds_in_range(range).next().is_some() {
18539                self.unfold_lines(&Default::default(), window, cx)
18540            } else {
18541                self.fold(&Default::default(), window, cx)
18542            }
18543        } else {
18544            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18545            let buffer_ids: HashSet<_> = self
18546                .selections
18547                .disjoint_anchor_ranges()
18548                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18549                .collect();
18550
18551            let should_unfold = buffer_ids
18552                .iter()
18553                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18554
18555            for buffer_id in buffer_ids {
18556                if should_unfold {
18557                    self.unfold_buffer(buffer_id, cx);
18558                } else {
18559                    self.fold_buffer(buffer_id, cx);
18560                }
18561            }
18562        }
18563    }
18564
18565    pub fn toggle_fold_recursive(
18566        &mut self,
18567        _: &actions::ToggleFoldRecursive,
18568        window: &mut Window,
18569        cx: &mut Context<Self>,
18570    ) {
18571        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18572
18573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18574        let range = if selection.is_empty() {
18575            let point = selection.head().to_display_point(&display_map);
18576            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18577            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18578                .to_point(&display_map);
18579            start..end
18580        } else {
18581            selection.range()
18582        };
18583        if display_map.folds_in_range(range).next().is_some() {
18584            self.unfold_recursive(&Default::default(), window, cx)
18585        } else {
18586            self.fold_recursive(&Default::default(), window, cx)
18587        }
18588    }
18589
18590    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18591        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18592            let mut to_fold = Vec::new();
18593            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18594            let selections = self.selections.all_adjusted(&display_map);
18595
18596            for selection in selections {
18597                let range = selection.range().sorted();
18598                let buffer_start_row = range.start.row;
18599
18600                if range.start.row != range.end.row {
18601                    let mut found = false;
18602                    let mut row = range.start.row;
18603                    while row <= range.end.row {
18604                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18605                        {
18606                            found = true;
18607                            row = crease.range().end.row + 1;
18608                            to_fold.push(crease);
18609                        } else {
18610                            row += 1
18611                        }
18612                    }
18613                    if found {
18614                        continue;
18615                    }
18616                }
18617
18618                for row in (0..=range.start.row).rev() {
18619                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18620                        && crease.range().end.row >= buffer_start_row
18621                    {
18622                        to_fold.push(crease);
18623                        if row <= range.start.row {
18624                            break;
18625                        }
18626                    }
18627                }
18628            }
18629
18630            self.fold_creases(to_fold, true, window, cx);
18631        } else {
18632            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18633            let buffer_ids = self
18634                .selections
18635                .disjoint_anchor_ranges()
18636                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18637                .collect::<HashSet<_>>();
18638            for buffer_id in buffer_ids {
18639                self.fold_buffer(buffer_id, cx);
18640            }
18641        }
18642    }
18643
18644    pub fn toggle_fold_all(
18645        &mut self,
18646        _: &actions::ToggleFoldAll,
18647        window: &mut Window,
18648        cx: &mut Context<Self>,
18649    ) {
18650        if self.buffer.read(cx).is_singleton() {
18651            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18652            let has_folds = display_map
18653                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18654                .next()
18655                .is_some();
18656
18657            if has_folds {
18658                self.unfold_all(&actions::UnfoldAll, window, cx);
18659            } else {
18660                self.fold_all(&actions::FoldAll, window, cx);
18661            }
18662        } else {
18663            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18664            let should_unfold = buffer_ids
18665                .iter()
18666                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18667
18668            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18669                editor
18670                    .update_in(cx, |editor, _, cx| {
18671                        for buffer_id in buffer_ids {
18672                            if should_unfold {
18673                                editor.unfold_buffer(buffer_id, cx);
18674                            } else {
18675                                editor.fold_buffer(buffer_id, cx);
18676                            }
18677                        }
18678                    })
18679                    .ok();
18680            });
18681        }
18682    }
18683
18684    fn fold_at_level(
18685        &mut self,
18686        fold_at: &FoldAtLevel,
18687        window: &mut Window,
18688        cx: &mut Context<Self>,
18689    ) {
18690        if !self.buffer.read(cx).is_singleton() {
18691            return;
18692        }
18693
18694        let fold_at_level = fold_at.0;
18695        let snapshot = self.buffer.read(cx).snapshot(cx);
18696        let mut to_fold = Vec::new();
18697        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18698
18699        let row_ranges_to_keep: Vec<Range<u32>> = self
18700            .selections
18701            .all::<Point>(&self.display_snapshot(cx))
18702            .into_iter()
18703            .map(|sel| sel.start.row..sel.end.row)
18704            .collect();
18705
18706        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18707            while start_row < end_row {
18708                match self
18709                    .snapshot(window, cx)
18710                    .crease_for_buffer_row(MultiBufferRow(start_row))
18711                {
18712                    Some(crease) => {
18713                        let nested_start_row = crease.range().start.row + 1;
18714                        let nested_end_row = crease.range().end.row;
18715
18716                        if current_level < fold_at_level {
18717                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18718                        } else if current_level == fold_at_level {
18719                            // Fold iff there is no selection completely contained within the fold region
18720                            if !row_ranges_to_keep.iter().any(|selection| {
18721                                selection.end >= nested_start_row
18722                                    && selection.start <= nested_end_row
18723                            }) {
18724                                to_fold.push(crease);
18725                            }
18726                        }
18727
18728                        start_row = nested_end_row + 1;
18729                    }
18730                    None => start_row += 1,
18731                }
18732            }
18733        }
18734
18735        self.fold_creases(to_fold, true, window, cx);
18736    }
18737
18738    pub fn fold_at_level_1(
18739        &mut self,
18740        _: &actions::FoldAtLevel1,
18741        window: &mut Window,
18742        cx: &mut Context<Self>,
18743    ) {
18744        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18745    }
18746
18747    pub fn fold_at_level_2(
18748        &mut self,
18749        _: &actions::FoldAtLevel2,
18750        window: &mut Window,
18751        cx: &mut Context<Self>,
18752    ) {
18753        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18754    }
18755
18756    pub fn fold_at_level_3(
18757        &mut self,
18758        _: &actions::FoldAtLevel3,
18759        window: &mut Window,
18760        cx: &mut Context<Self>,
18761    ) {
18762        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18763    }
18764
18765    pub fn fold_at_level_4(
18766        &mut self,
18767        _: &actions::FoldAtLevel4,
18768        window: &mut Window,
18769        cx: &mut Context<Self>,
18770    ) {
18771        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18772    }
18773
18774    pub fn fold_at_level_5(
18775        &mut self,
18776        _: &actions::FoldAtLevel5,
18777        window: &mut Window,
18778        cx: &mut Context<Self>,
18779    ) {
18780        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18781    }
18782
18783    pub fn fold_at_level_6(
18784        &mut self,
18785        _: &actions::FoldAtLevel6,
18786        window: &mut Window,
18787        cx: &mut Context<Self>,
18788    ) {
18789        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18790    }
18791
18792    pub fn fold_at_level_7(
18793        &mut self,
18794        _: &actions::FoldAtLevel7,
18795        window: &mut Window,
18796        cx: &mut Context<Self>,
18797    ) {
18798        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18799    }
18800
18801    pub fn fold_at_level_8(
18802        &mut self,
18803        _: &actions::FoldAtLevel8,
18804        window: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18808    }
18809
18810    pub fn fold_at_level_9(
18811        &mut self,
18812        _: &actions::FoldAtLevel9,
18813        window: &mut Window,
18814        cx: &mut Context<Self>,
18815    ) {
18816        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18817    }
18818
18819    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18820        if self.buffer.read(cx).is_singleton() {
18821            let mut fold_ranges = Vec::new();
18822            let snapshot = self.buffer.read(cx).snapshot(cx);
18823
18824            for row in 0..snapshot.max_row().0 {
18825                if let Some(foldable_range) = self
18826                    .snapshot(window, cx)
18827                    .crease_for_buffer_row(MultiBufferRow(row))
18828                {
18829                    fold_ranges.push(foldable_range);
18830                }
18831            }
18832
18833            self.fold_creases(fold_ranges, true, window, cx);
18834        } else {
18835            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18836                editor
18837                    .update_in(cx, |editor, _, cx| {
18838                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18839                            editor.fold_buffer(buffer_id, cx);
18840                        }
18841                    })
18842                    .ok();
18843            });
18844        }
18845    }
18846
18847    pub fn fold_function_bodies(
18848        &mut self,
18849        _: &actions::FoldFunctionBodies,
18850        window: &mut Window,
18851        cx: &mut Context<Self>,
18852    ) {
18853        let snapshot = self.buffer.read(cx).snapshot(cx);
18854
18855        let ranges = snapshot
18856            .text_object_ranges(
18857                MultiBufferOffset(0)..snapshot.len(),
18858                TreeSitterOptions::default(),
18859            )
18860            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18861            .collect::<Vec<_>>();
18862
18863        let creases = ranges
18864            .into_iter()
18865            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18866            .collect();
18867
18868        self.fold_creases(creases, true, window, cx);
18869    }
18870
18871    pub fn fold_recursive(
18872        &mut self,
18873        _: &actions::FoldRecursive,
18874        window: &mut Window,
18875        cx: &mut Context<Self>,
18876    ) {
18877        let mut to_fold = Vec::new();
18878        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18879        let selections = self.selections.all_adjusted(&display_map);
18880
18881        for selection in selections {
18882            let range = selection.range().sorted();
18883            let buffer_start_row = range.start.row;
18884
18885            if range.start.row != range.end.row {
18886                let mut found = false;
18887                for row in range.start.row..=range.end.row {
18888                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18889                        found = true;
18890                        to_fold.push(crease);
18891                    }
18892                }
18893                if found {
18894                    continue;
18895                }
18896            }
18897
18898            for row in (0..=range.start.row).rev() {
18899                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18900                    if crease.range().end.row >= buffer_start_row {
18901                        to_fold.push(crease);
18902                    } else {
18903                        break;
18904                    }
18905                }
18906            }
18907        }
18908
18909        self.fold_creases(to_fold, true, window, cx);
18910    }
18911
18912    pub fn fold_at(
18913        &mut self,
18914        buffer_row: MultiBufferRow,
18915        window: &mut Window,
18916        cx: &mut Context<Self>,
18917    ) {
18918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18919
18920        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18921            let autoscroll = self
18922                .selections
18923                .all::<Point>(&display_map)
18924                .iter()
18925                .any(|selection| crease.range().overlaps(&selection.range()));
18926
18927            self.fold_creases(vec![crease], autoscroll, window, cx);
18928        }
18929    }
18930
18931    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18932        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18933            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18934            let buffer = display_map.buffer_snapshot();
18935            let selections = self.selections.all::<Point>(&display_map);
18936            let ranges = selections
18937                .iter()
18938                .map(|s| {
18939                    let range = s.display_range(&display_map).sorted();
18940                    let mut start = range.start.to_point(&display_map);
18941                    let mut end = range.end.to_point(&display_map);
18942                    start.column = 0;
18943                    end.column = buffer.line_len(MultiBufferRow(end.row));
18944                    start..end
18945                })
18946                .collect::<Vec<_>>();
18947
18948            self.unfold_ranges(&ranges, true, true, cx);
18949        } else {
18950            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18951            let buffer_ids = self
18952                .selections
18953                .disjoint_anchor_ranges()
18954                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18955                .collect::<HashSet<_>>();
18956            for buffer_id in buffer_ids {
18957                self.unfold_buffer(buffer_id, cx);
18958            }
18959        }
18960    }
18961
18962    pub fn unfold_recursive(
18963        &mut self,
18964        _: &UnfoldRecursive,
18965        _window: &mut Window,
18966        cx: &mut Context<Self>,
18967    ) {
18968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18969        let selections = self.selections.all::<Point>(&display_map);
18970        let ranges = selections
18971            .iter()
18972            .map(|s| {
18973                let mut range = s.display_range(&display_map).sorted();
18974                *range.start.column_mut() = 0;
18975                *range.end.column_mut() = display_map.line_len(range.end.row());
18976                let start = range.start.to_point(&display_map);
18977                let end = range.end.to_point(&display_map);
18978                start..end
18979            })
18980            .collect::<Vec<_>>();
18981
18982        self.unfold_ranges(&ranges, true, true, cx);
18983    }
18984
18985    pub fn unfold_at(
18986        &mut self,
18987        buffer_row: MultiBufferRow,
18988        _window: &mut Window,
18989        cx: &mut Context<Self>,
18990    ) {
18991        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18992
18993        let intersection_range = Point::new(buffer_row.0, 0)
18994            ..Point::new(
18995                buffer_row.0,
18996                display_map.buffer_snapshot().line_len(buffer_row),
18997            );
18998
18999        let autoscroll = self
19000            .selections
19001            .all::<Point>(&display_map)
19002            .iter()
19003            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19004
19005        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19006    }
19007
19008    pub fn unfold_all(
19009        &mut self,
19010        _: &actions::UnfoldAll,
19011        _window: &mut Window,
19012        cx: &mut Context<Self>,
19013    ) {
19014        if self.buffer.read(cx).is_singleton() {
19015            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19016            self.unfold_ranges(
19017                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19018                true,
19019                true,
19020                cx,
19021            );
19022        } else {
19023            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19024                editor
19025                    .update(cx, |editor, cx| {
19026                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19027                            editor.unfold_buffer(buffer_id, cx);
19028                        }
19029                    })
19030                    .ok();
19031            });
19032        }
19033    }
19034
19035    pub fn fold_selected_ranges(
19036        &mut self,
19037        _: &FoldSelectedRanges,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19042        let selections = self.selections.all_adjusted(&display_map);
19043        let ranges = selections
19044            .into_iter()
19045            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19046            .collect::<Vec<_>>();
19047        self.fold_creases(ranges, true, window, cx);
19048    }
19049
19050    pub fn fold_ranges<T: ToOffset + Clone>(
19051        &mut self,
19052        ranges: Vec<Range<T>>,
19053        auto_scroll: bool,
19054        window: &mut Window,
19055        cx: &mut Context<Self>,
19056    ) {
19057        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19058        let ranges = ranges
19059            .into_iter()
19060            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19061            .collect::<Vec<_>>();
19062        self.fold_creases(ranges, auto_scroll, window, cx);
19063    }
19064
19065    pub fn fold_creases<T: ToOffset + Clone>(
19066        &mut self,
19067        creases: Vec<Crease<T>>,
19068        auto_scroll: bool,
19069        _window: &mut Window,
19070        cx: &mut Context<Self>,
19071    ) {
19072        if creases.is_empty() {
19073            return;
19074        }
19075
19076        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19077
19078        if auto_scroll {
19079            self.request_autoscroll(Autoscroll::fit(), cx);
19080        }
19081
19082        cx.notify();
19083
19084        self.scrollbar_marker_state.dirty = true;
19085        self.folds_did_change(cx);
19086    }
19087
19088    /// Removes any folds whose ranges intersect any of the given ranges.
19089    pub fn unfold_ranges<T: ToOffset + Clone>(
19090        &mut self,
19091        ranges: &[Range<T>],
19092        inclusive: bool,
19093        auto_scroll: bool,
19094        cx: &mut Context<Self>,
19095    ) {
19096        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19097            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19098        });
19099        self.folds_did_change(cx);
19100    }
19101
19102    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19103        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19104            return;
19105        }
19106
19107        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19108        self.display_map.update(cx, |display_map, cx| {
19109            display_map.fold_buffers([buffer_id], cx)
19110        });
19111
19112        let snapshot = self.display_snapshot(cx);
19113        self.selections.change_with(&snapshot, |selections| {
19114            selections.remove_selections_from_buffer(buffer_id);
19115        });
19116
19117        cx.emit(EditorEvent::BufferFoldToggled {
19118            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19119            folded: true,
19120        });
19121        cx.notify();
19122    }
19123
19124    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19125        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19126            return;
19127        }
19128        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19129        self.display_map.update(cx, |display_map, cx| {
19130            display_map.unfold_buffers([buffer_id], cx);
19131        });
19132        cx.emit(EditorEvent::BufferFoldToggled {
19133            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19134            folded: false,
19135        });
19136        cx.notify();
19137    }
19138
19139    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19140        self.display_map.read(cx).is_buffer_folded(buffer)
19141    }
19142
19143    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19144        self.display_map.read(cx).folded_buffers()
19145    }
19146
19147    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19148        self.display_map.update(cx, |display_map, cx| {
19149            display_map.disable_header_for_buffer(buffer_id, cx);
19150        });
19151        cx.notify();
19152    }
19153
19154    /// Removes any folds with the given ranges.
19155    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19156        &mut self,
19157        ranges: &[Range<T>],
19158        type_id: TypeId,
19159        auto_scroll: bool,
19160        cx: &mut Context<Self>,
19161    ) {
19162        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19163            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19164        });
19165        self.folds_did_change(cx);
19166    }
19167
19168    fn remove_folds_with<T: ToOffset + Clone>(
19169        &mut self,
19170        ranges: &[Range<T>],
19171        auto_scroll: bool,
19172        cx: &mut Context<Self>,
19173        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19174    ) {
19175        if ranges.is_empty() {
19176            return;
19177        }
19178
19179        let mut buffers_affected = HashSet::default();
19180        let multi_buffer = self.buffer().read(cx);
19181        for range in ranges {
19182            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19183                buffers_affected.insert(buffer.read(cx).remote_id());
19184            };
19185        }
19186
19187        self.display_map.update(cx, update);
19188
19189        if auto_scroll {
19190            self.request_autoscroll(Autoscroll::fit(), cx);
19191        }
19192
19193        cx.notify();
19194        self.scrollbar_marker_state.dirty = true;
19195        self.active_indent_guides_state.dirty = true;
19196    }
19197
19198    pub fn update_renderer_widths(
19199        &mut self,
19200        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19201        cx: &mut Context<Self>,
19202    ) -> bool {
19203        self.display_map
19204            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19205    }
19206
19207    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19208        self.display_map.read(cx).fold_placeholder.clone()
19209    }
19210
19211    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19212        self.use_base_text_line_numbers = show;
19213    }
19214
19215    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19216        self.buffer.update(cx, |buffer, cx| {
19217            buffer.set_all_diff_hunks_expanded(cx);
19218        });
19219    }
19220
19221    pub fn expand_all_diff_hunks(
19222        &mut self,
19223        _: &ExpandAllDiffHunks,
19224        _window: &mut Window,
19225        cx: &mut Context<Self>,
19226    ) {
19227        self.buffer.update(cx, |buffer, cx| {
19228            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19229        });
19230    }
19231
19232    pub fn collapse_all_diff_hunks(
19233        &mut self,
19234        _: &CollapseAllDiffHunks,
19235        _window: &mut Window,
19236        cx: &mut Context<Self>,
19237    ) {
19238        self.buffer.update(cx, |buffer, cx| {
19239            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19240        });
19241    }
19242
19243    pub fn toggle_selected_diff_hunks(
19244        &mut self,
19245        _: &ToggleSelectedDiffHunks,
19246        _window: &mut Window,
19247        cx: &mut Context<Self>,
19248    ) {
19249        let ranges: Vec<_> = self
19250            .selections
19251            .disjoint_anchors()
19252            .iter()
19253            .map(|s| s.range())
19254            .collect();
19255        self.toggle_diff_hunks_in_ranges(ranges, cx);
19256    }
19257
19258    pub fn diff_hunks_in_ranges<'a>(
19259        &'a self,
19260        ranges: &'a [Range<Anchor>],
19261        buffer: &'a MultiBufferSnapshot,
19262    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19263        ranges.iter().flat_map(move |range| {
19264            let end_excerpt_id = range.end.excerpt_id;
19265            let range = range.to_point(buffer);
19266            let mut peek_end = range.end;
19267            if range.end.row < buffer.max_row().0 {
19268                peek_end = Point::new(range.end.row + 1, 0);
19269            }
19270            buffer
19271                .diff_hunks_in_range(range.start..peek_end)
19272                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19273        })
19274    }
19275
19276    pub fn has_stageable_diff_hunks_in_ranges(
19277        &self,
19278        ranges: &[Range<Anchor>],
19279        snapshot: &MultiBufferSnapshot,
19280    ) -> bool {
19281        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19282        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19283    }
19284
19285    pub fn toggle_staged_selected_diff_hunks(
19286        &mut self,
19287        _: &::git::ToggleStaged,
19288        _: &mut Window,
19289        cx: &mut Context<Self>,
19290    ) {
19291        let snapshot = self.buffer.read(cx).snapshot(cx);
19292        let ranges: Vec<_> = self
19293            .selections
19294            .disjoint_anchors()
19295            .iter()
19296            .map(|s| s.range())
19297            .collect();
19298        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19299        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19300    }
19301
19302    pub fn set_render_diff_hunk_controls(
19303        &mut self,
19304        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19305        cx: &mut Context<Self>,
19306    ) {
19307        self.render_diff_hunk_controls = render_diff_hunk_controls;
19308        cx.notify();
19309    }
19310
19311    pub fn stage_and_next(
19312        &mut self,
19313        _: &::git::StageAndNext,
19314        window: &mut Window,
19315        cx: &mut Context<Self>,
19316    ) {
19317        self.do_stage_or_unstage_and_next(true, window, cx);
19318    }
19319
19320    pub fn unstage_and_next(
19321        &mut self,
19322        _: &::git::UnstageAndNext,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) {
19326        self.do_stage_or_unstage_and_next(false, window, cx);
19327    }
19328
19329    pub fn stage_or_unstage_diff_hunks(
19330        &mut self,
19331        stage: bool,
19332        ranges: Vec<Range<Anchor>>,
19333        cx: &mut Context<Self>,
19334    ) {
19335        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19336        cx.spawn(async move |this, cx| {
19337            task.await?;
19338            this.update(cx, |this, cx| {
19339                let snapshot = this.buffer.read(cx).snapshot(cx);
19340                let chunk_by = this
19341                    .diff_hunks_in_ranges(&ranges, &snapshot)
19342                    .chunk_by(|hunk| hunk.buffer_id);
19343                for (buffer_id, hunks) in &chunk_by {
19344                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19345                }
19346            })
19347        })
19348        .detach_and_log_err(cx);
19349    }
19350
19351    fn save_buffers_for_ranges_if_needed(
19352        &mut self,
19353        ranges: &[Range<Anchor>],
19354        cx: &mut Context<Editor>,
19355    ) -> Task<Result<()>> {
19356        let multibuffer = self.buffer.read(cx);
19357        let snapshot = multibuffer.read(cx);
19358        let buffer_ids: HashSet<_> = ranges
19359            .iter()
19360            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19361            .collect();
19362        drop(snapshot);
19363
19364        let mut buffers = HashSet::default();
19365        for buffer_id in buffer_ids {
19366            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19367                let buffer = buffer_entity.read(cx);
19368                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19369                {
19370                    buffers.insert(buffer_entity);
19371                }
19372            }
19373        }
19374
19375        if let Some(project) = &self.project {
19376            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19377        } else {
19378            Task::ready(Ok(()))
19379        }
19380    }
19381
19382    fn do_stage_or_unstage_and_next(
19383        &mut self,
19384        stage: bool,
19385        window: &mut Window,
19386        cx: &mut Context<Self>,
19387    ) {
19388        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19389
19390        if ranges.iter().any(|range| range.start != range.end) {
19391            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19392            return;
19393        }
19394
19395        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19396        let snapshot = self.snapshot(window, cx);
19397        let position = self
19398            .selections
19399            .newest::<Point>(&snapshot.display_snapshot)
19400            .head();
19401        let mut row = snapshot
19402            .buffer_snapshot()
19403            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19404            .find(|hunk| hunk.row_range.start.0 > position.row)
19405            .map(|hunk| hunk.row_range.start);
19406
19407        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19408        // Outside of the project diff editor, wrap around to the beginning.
19409        if !all_diff_hunks_expanded {
19410            row = row.or_else(|| {
19411                snapshot
19412                    .buffer_snapshot()
19413                    .diff_hunks_in_range(Point::zero()..position)
19414                    .find(|hunk| hunk.row_range.end.0 < position.row)
19415                    .map(|hunk| hunk.row_range.start)
19416            });
19417        }
19418
19419        if let Some(row) = row {
19420            let destination = Point::new(row.0, 0);
19421            let autoscroll = Autoscroll::center();
19422
19423            self.unfold_ranges(&[destination..destination], false, false, cx);
19424            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19425                s.select_ranges([destination..destination]);
19426            });
19427        }
19428    }
19429
19430    fn do_stage_or_unstage(
19431        &self,
19432        stage: bool,
19433        buffer_id: BufferId,
19434        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19435        cx: &mut App,
19436    ) -> Option<()> {
19437        let project = self.project()?;
19438        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19439        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19440        let buffer_snapshot = buffer.read(cx).snapshot();
19441        let file_exists = buffer_snapshot
19442            .file()
19443            .is_some_and(|file| file.disk_state().exists());
19444        diff.update(cx, |diff, cx| {
19445            diff.stage_or_unstage_hunks(
19446                stage,
19447                &hunks
19448                    .map(|hunk| buffer_diff::DiffHunk {
19449                        buffer_range: hunk.buffer_range,
19450                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19451                            ..hunk.diff_base_byte_range.end.0,
19452                        secondary_status: hunk.secondary_status,
19453                        range: Point::zero()..Point::zero(), // unused
19454                    })
19455                    .collect::<Vec<_>>(),
19456                &buffer_snapshot,
19457                file_exists,
19458                cx,
19459            )
19460        });
19461        None
19462    }
19463
19464    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19465        let ranges: Vec<_> = self
19466            .selections
19467            .disjoint_anchors()
19468            .iter()
19469            .map(|s| s.range())
19470            .collect();
19471        self.buffer
19472            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19473    }
19474
19475    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19476        self.buffer.update(cx, |buffer, cx| {
19477            let ranges = vec![Anchor::min()..Anchor::max()];
19478            if !buffer.all_diff_hunks_expanded()
19479                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19480            {
19481                buffer.collapse_diff_hunks(ranges, cx);
19482                true
19483            } else {
19484                false
19485            }
19486        })
19487    }
19488
19489    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19490        if self.buffer.read(cx).all_diff_hunks_expanded() {
19491            return true;
19492        }
19493        let ranges = vec![Anchor::min()..Anchor::max()];
19494        self.buffer
19495            .read(cx)
19496            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19497    }
19498
19499    fn toggle_diff_hunks_in_ranges(
19500        &mut self,
19501        ranges: Vec<Range<Anchor>>,
19502        cx: &mut Context<Editor>,
19503    ) {
19504        self.buffer.update(cx, |buffer, cx| {
19505            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19506            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19507        })
19508    }
19509
19510    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19511        self.buffer.update(cx, |buffer, cx| {
19512            let snapshot = buffer.snapshot(cx);
19513            let excerpt_id = range.end.excerpt_id;
19514            let point_range = range.to_point(&snapshot);
19515            let expand = !buffer.single_hunk_is_expanded(range, cx);
19516            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19517        })
19518    }
19519
19520    pub(crate) fn apply_all_diff_hunks(
19521        &mut self,
19522        _: &ApplyAllDiffHunks,
19523        window: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19527
19528        let buffers = self.buffer.read(cx).all_buffers();
19529        for branch_buffer in buffers {
19530            branch_buffer.update(cx, |branch_buffer, cx| {
19531                branch_buffer.merge_into_base(Vec::new(), cx);
19532            });
19533        }
19534
19535        if let Some(project) = self.project.clone() {
19536            self.save(
19537                SaveOptions {
19538                    format: true,
19539                    autosave: false,
19540                },
19541                project,
19542                window,
19543                cx,
19544            )
19545            .detach_and_log_err(cx);
19546        }
19547    }
19548
19549    pub(crate) fn apply_selected_diff_hunks(
19550        &mut self,
19551        _: &ApplyDiffHunk,
19552        window: &mut Window,
19553        cx: &mut Context<Self>,
19554    ) {
19555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19556        let snapshot = self.snapshot(window, cx);
19557        let hunks = snapshot.hunks_for_ranges(
19558            self.selections
19559                .all(&snapshot.display_snapshot)
19560                .into_iter()
19561                .map(|selection| selection.range()),
19562        );
19563        let mut ranges_by_buffer = HashMap::default();
19564        self.transact(window, cx, |editor, _window, cx| {
19565            for hunk in hunks {
19566                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19567                    ranges_by_buffer
19568                        .entry(buffer.clone())
19569                        .or_insert_with(Vec::new)
19570                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19571                }
19572            }
19573
19574            for (buffer, ranges) in ranges_by_buffer {
19575                buffer.update(cx, |buffer, cx| {
19576                    buffer.merge_into_base(ranges, cx);
19577                });
19578            }
19579        });
19580
19581        if let Some(project) = self.project.clone() {
19582            self.save(
19583                SaveOptions {
19584                    format: true,
19585                    autosave: false,
19586                },
19587                project,
19588                window,
19589                cx,
19590            )
19591            .detach_and_log_err(cx);
19592        }
19593    }
19594
19595    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19596        if hovered != self.gutter_hovered {
19597            self.gutter_hovered = hovered;
19598            cx.notify();
19599        }
19600    }
19601
19602    pub fn insert_blocks(
19603        &mut self,
19604        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19605        autoscroll: Option<Autoscroll>,
19606        cx: &mut Context<Self>,
19607    ) -> Vec<CustomBlockId> {
19608        let blocks = self
19609            .display_map
19610            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19611        if let Some(autoscroll) = autoscroll {
19612            self.request_autoscroll(autoscroll, cx);
19613        }
19614        cx.notify();
19615        blocks
19616    }
19617
19618    pub fn resize_blocks(
19619        &mut self,
19620        heights: HashMap<CustomBlockId, u32>,
19621        autoscroll: Option<Autoscroll>,
19622        cx: &mut Context<Self>,
19623    ) {
19624        self.display_map
19625            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19626        if let Some(autoscroll) = autoscroll {
19627            self.request_autoscroll(autoscroll, cx);
19628        }
19629        cx.notify();
19630    }
19631
19632    pub fn replace_blocks(
19633        &mut self,
19634        renderers: HashMap<CustomBlockId, RenderBlock>,
19635        autoscroll: Option<Autoscroll>,
19636        cx: &mut Context<Self>,
19637    ) {
19638        self.display_map
19639            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19640        if let Some(autoscroll) = autoscroll {
19641            self.request_autoscroll(autoscroll, cx);
19642        }
19643        cx.notify();
19644    }
19645
19646    pub fn remove_blocks(
19647        &mut self,
19648        block_ids: HashSet<CustomBlockId>,
19649        autoscroll: Option<Autoscroll>,
19650        cx: &mut Context<Self>,
19651    ) {
19652        self.display_map.update(cx, |display_map, cx| {
19653            display_map.remove_blocks(block_ids, cx)
19654        });
19655        if let Some(autoscroll) = autoscroll {
19656            self.request_autoscroll(autoscroll, cx);
19657        }
19658        cx.notify();
19659    }
19660
19661    pub fn row_for_block(
19662        &self,
19663        block_id: CustomBlockId,
19664        cx: &mut Context<Self>,
19665    ) -> Option<DisplayRow> {
19666        self.display_map
19667            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19668    }
19669
19670    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19671        self.focused_block = Some(focused_block);
19672    }
19673
19674    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19675        self.focused_block.take()
19676    }
19677
19678    pub fn insert_creases(
19679        &mut self,
19680        creases: impl IntoIterator<Item = Crease<Anchor>>,
19681        cx: &mut Context<Self>,
19682    ) -> Vec<CreaseId> {
19683        self.display_map
19684            .update(cx, |map, cx| map.insert_creases(creases, cx))
19685    }
19686
19687    pub fn remove_creases(
19688        &mut self,
19689        ids: impl IntoIterator<Item = CreaseId>,
19690        cx: &mut Context<Self>,
19691    ) -> Vec<(CreaseId, Range<Anchor>)> {
19692        self.display_map
19693            .update(cx, |map, cx| map.remove_creases(ids, cx))
19694    }
19695
19696    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19697        self.display_map
19698            .update(cx, |map, cx| map.snapshot(cx))
19699            .longest_row()
19700    }
19701
19702    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19703        self.display_map
19704            .update(cx, |map, cx| map.snapshot(cx))
19705            .max_point()
19706    }
19707
19708    pub fn text(&self, cx: &App) -> String {
19709        self.buffer.read(cx).read(cx).text()
19710    }
19711
19712    pub fn is_empty(&self, cx: &App) -> bool {
19713        self.buffer.read(cx).read(cx).is_empty()
19714    }
19715
19716    pub fn text_option(&self, cx: &App) -> Option<String> {
19717        let text = self.text(cx);
19718        let text = text.trim();
19719
19720        if text.is_empty() {
19721            return None;
19722        }
19723
19724        Some(text.to_string())
19725    }
19726
19727    pub fn set_text(
19728        &mut self,
19729        text: impl Into<Arc<str>>,
19730        window: &mut Window,
19731        cx: &mut Context<Self>,
19732    ) {
19733        self.transact(window, cx, |this, _, cx| {
19734            this.buffer
19735                .read(cx)
19736                .as_singleton()
19737                .expect("you can only call set_text on editors for singleton buffers")
19738                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19739        });
19740    }
19741
19742    pub fn display_text(&self, cx: &mut App) -> String {
19743        self.display_map
19744            .update(cx, |map, cx| map.snapshot(cx))
19745            .text()
19746    }
19747
19748    fn create_minimap(
19749        &self,
19750        minimap_settings: MinimapSettings,
19751        window: &mut Window,
19752        cx: &mut Context<Self>,
19753    ) -> Option<Entity<Self>> {
19754        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19755            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19756    }
19757
19758    fn initialize_new_minimap(
19759        &self,
19760        minimap_settings: MinimapSettings,
19761        window: &mut Window,
19762        cx: &mut Context<Self>,
19763    ) -> Entity<Self> {
19764        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19765
19766        let mut minimap = Editor::new_internal(
19767            EditorMode::Minimap {
19768                parent: cx.weak_entity(),
19769            },
19770            self.buffer.clone(),
19771            None,
19772            Some(self.display_map.clone()),
19773            window,
19774            cx,
19775        );
19776        minimap.scroll_manager.clone_state(&self.scroll_manager);
19777        minimap.set_text_style_refinement(TextStyleRefinement {
19778            font_size: Some(MINIMAP_FONT_SIZE),
19779            font_weight: Some(MINIMAP_FONT_WEIGHT),
19780            ..Default::default()
19781        });
19782        minimap.update_minimap_configuration(minimap_settings, cx);
19783        cx.new(|_| minimap)
19784    }
19785
19786    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19787        let current_line_highlight = minimap_settings
19788            .current_line_highlight
19789            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19790        self.set_current_line_highlight(Some(current_line_highlight));
19791    }
19792
19793    pub fn minimap(&self) -> Option<&Entity<Self>> {
19794        self.minimap
19795            .as_ref()
19796            .filter(|_| self.minimap_visibility.visible())
19797    }
19798
19799    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19800        let mut wrap_guides = smallvec![];
19801
19802        if self.show_wrap_guides == Some(false) {
19803            return wrap_guides;
19804        }
19805
19806        let settings = self.buffer.read(cx).language_settings(cx);
19807        if settings.show_wrap_guides {
19808            match self.soft_wrap_mode(cx) {
19809                SoftWrap::Column(soft_wrap) => {
19810                    wrap_guides.push((soft_wrap as usize, true));
19811                }
19812                SoftWrap::Bounded(soft_wrap) => {
19813                    wrap_guides.push((soft_wrap as usize, true));
19814                }
19815                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19816            }
19817            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19818        }
19819
19820        wrap_guides
19821    }
19822
19823    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19824        let settings = self.buffer.read(cx).language_settings(cx);
19825        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19826        match mode {
19827            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19828                SoftWrap::None
19829            }
19830            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19831            language_settings::SoftWrap::PreferredLineLength => {
19832                SoftWrap::Column(settings.preferred_line_length)
19833            }
19834            language_settings::SoftWrap::Bounded => {
19835                SoftWrap::Bounded(settings.preferred_line_length)
19836            }
19837        }
19838    }
19839
19840    pub fn set_soft_wrap_mode(
19841        &mut self,
19842        mode: language_settings::SoftWrap,
19843
19844        cx: &mut Context<Self>,
19845    ) {
19846        self.soft_wrap_mode_override = Some(mode);
19847        cx.notify();
19848    }
19849
19850    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19851        self.hard_wrap = hard_wrap;
19852        cx.notify();
19853    }
19854
19855    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19856        self.text_style_refinement = Some(style);
19857    }
19858
19859    /// called by the Element so we know what style we were most recently rendered with.
19860    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19861        // We intentionally do not inform the display map about the minimap style
19862        // so that wrapping is not recalculated and stays consistent for the editor
19863        // and its linked minimap.
19864        if !self.mode.is_minimap() {
19865            let font = style.text.font();
19866            let font_size = style.text.font_size.to_pixels(window.rem_size());
19867            let display_map = self
19868                .placeholder_display_map
19869                .as_ref()
19870                .filter(|_| self.is_empty(cx))
19871                .unwrap_or(&self.display_map);
19872
19873            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19874        }
19875        self.style = Some(style);
19876    }
19877
19878    pub fn style(&self) -> Option<&EditorStyle> {
19879        self.style.as_ref()
19880    }
19881
19882    // Called by the element. This method is not designed to be called outside of the editor
19883    // element's layout code because it does not notify when rewrapping is computed synchronously.
19884    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19885        if self.is_empty(cx) {
19886            self.placeholder_display_map
19887                .as_ref()
19888                .map_or(false, |display_map| {
19889                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19890                })
19891        } else {
19892            self.display_map
19893                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19894        }
19895    }
19896
19897    pub fn set_soft_wrap(&mut self) {
19898        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19899    }
19900
19901    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19902        if self.soft_wrap_mode_override.is_some() {
19903            self.soft_wrap_mode_override.take();
19904        } else {
19905            let soft_wrap = match self.soft_wrap_mode(cx) {
19906                SoftWrap::GitDiff => return,
19907                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19908                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19909                    language_settings::SoftWrap::None
19910                }
19911            };
19912            self.soft_wrap_mode_override = Some(soft_wrap);
19913        }
19914        cx.notify();
19915    }
19916
19917    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19918        let Some(workspace) = self.workspace() else {
19919            return;
19920        };
19921        let fs = workspace.read(cx).app_state().fs.clone();
19922        let current_show = TabBarSettings::get_global(cx).show;
19923        update_settings_file(fs, cx, move |setting, _| {
19924            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19925        });
19926    }
19927
19928    pub fn toggle_indent_guides(
19929        &mut self,
19930        _: &ToggleIndentGuides,
19931        _: &mut Window,
19932        cx: &mut Context<Self>,
19933    ) {
19934        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19935            self.buffer
19936                .read(cx)
19937                .language_settings(cx)
19938                .indent_guides
19939                .enabled
19940        });
19941        self.show_indent_guides = Some(!currently_enabled);
19942        cx.notify();
19943    }
19944
19945    fn should_show_indent_guides(&self) -> Option<bool> {
19946        self.show_indent_guides
19947    }
19948
19949    pub fn toggle_line_numbers(
19950        &mut self,
19951        _: &ToggleLineNumbers,
19952        _: &mut Window,
19953        cx: &mut Context<Self>,
19954    ) {
19955        let mut editor_settings = EditorSettings::get_global(cx).clone();
19956        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19957        EditorSettings::override_global(editor_settings, cx);
19958    }
19959
19960    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19961        if let Some(show_line_numbers) = self.show_line_numbers {
19962            return show_line_numbers;
19963        }
19964        EditorSettings::get_global(cx).gutter.line_numbers
19965    }
19966
19967    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19968        match (
19969            self.use_relative_line_numbers,
19970            EditorSettings::get_global(cx).relative_line_numbers,
19971        ) {
19972            (None, setting) => setting,
19973            (Some(false), _) => RelativeLineNumbers::Disabled,
19974            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19975            (Some(true), _) => RelativeLineNumbers::Enabled,
19976        }
19977    }
19978
19979    pub fn toggle_relative_line_numbers(
19980        &mut self,
19981        _: &ToggleRelativeLineNumbers,
19982        _: &mut Window,
19983        cx: &mut Context<Self>,
19984    ) {
19985        let is_relative = self.relative_line_numbers(cx);
19986        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19987    }
19988
19989    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19990        self.use_relative_line_numbers = is_relative;
19991        cx.notify();
19992    }
19993
19994    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19995        self.show_gutter = show_gutter;
19996        cx.notify();
19997    }
19998
19999    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20000        self.show_scrollbars = ScrollbarAxes {
20001            horizontal: show,
20002            vertical: show,
20003        };
20004        cx.notify();
20005    }
20006
20007    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20008        self.show_scrollbars.vertical = show;
20009        cx.notify();
20010    }
20011
20012    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20013        self.show_scrollbars.horizontal = show;
20014        cx.notify();
20015    }
20016
20017    pub fn set_minimap_visibility(
20018        &mut self,
20019        minimap_visibility: MinimapVisibility,
20020        window: &mut Window,
20021        cx: &mut Context<Self>,
20022    ) {
20023        if self.minimap_visibility != minimap_visibility {
20024            if minimap_visibility.visible() && self.minimap.is_none() {
20025                let minimap_settings = EditorSettings::get_global(cx).minimap;
20026                self.minimap =
20027                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20028            }
20029            self.minimap_visibility = minimap_visibility;
20030            cx.notify();
20031        }
20032    }
20033
20034    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20035        self.set_show_scrollbars(false, cx);
20036        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20037    }
20038
20039    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20040        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20041    }
20042
20043    /// Normally the text in full mode and auto height editors is padded on the
20044    /// left side by roughly half a character width for improved hit testing.
20045    ///
20046    /// Use this method to disable this for cases where this is not wanted (e.g.
20047    /// if you want to align the editor text with some other text above or below)
20048    /// or if you want to add this padding to single-line editors.
20049    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20050        self.offset_content = offset_content;
20051        cx.notify();
20052    }
20053
20054    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20055        self.show_line_numbers = Some(show_line_numbers);
20056        cx.notify();
20057    }
20058
20059    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20060        self.disable_expand_excerpt_buttons = true;
20061        cx.notify();
20062    }
20063
20064    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20065        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20066        cx.notify();
20067    }
20068
20069    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20070        self.show_code_actions = Some(show_code_actions);
20071        cx.notify();
20072    }
20073
20074    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20075        self.show_runnables = Some(show_runnables);
20076        cx.notify();
20077    }
20078
20079    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20080        self.show_breakpoints = Some(show_breakpoints);
20081        cx.notify();
20082    }
20083
20084    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20085        if self.display_map.read(cx).masked != masked {
20086            self.display_map.update(cx, |map, _| map.masked = masked);
20087        }
20088        cx.notify()
20089    }
20090
20091    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20092        self.show_wrap_guides = Some(show_wrap_guides);
20093        cx.notify();
20094    }
20095
20096    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20097        self.show_indent_guides = Some(show_indent_guides);
20098        cx.notify();
20099    }
20100
20101    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20102        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20103            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20104                && let Some(dir) = file.abs_path(cx).parent()
20105            {
20106                return Some(dir.to_owned());
20107            }
20108        }
20109
20110        None
20111    }
20112
20113    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20114        self.active_excerpt(cx)?
20115            .1
20116            .read(cx)
20117            .file()
20118            .and_then(|f| f.as_local())
20119    }
20120
20121    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20122        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20123            let buffer = buffer.read(cx);
20124            if let Some(project_path) = buffer.project_path(cx) {
20125                let project = self.project()?.read(cx);
20126                project.absolute_path(&project_path, cx)
20127            } else {
20128                buffer
20129                    .file()
20130                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20131            }
20132        })
20133    }
20134
20135    pub fn reveal_in_finder(
20136        &mut self,
20137        _: &RevealInFileManager,
20138        _window: &mut Window,
20139        cx: &mut Context<Self>,
20140    ) {
20141        if let Some(target) = self.target_file(cx) {
20142            cx.reveal_path(&target.abs_path(cx));
20143        }
20144    }
20145
20146    pub fn copy_path(
20147        &mut self,
20148        _: &zed_actions::workspace::CopyPath,
20149        _window: &mut Window,
20150        cx: &mut Context<Self>,
20151    ) {
20152        if let Some(path) = self.target_file_abs_path(cx)
20153            && let Some(path) = path.to_str()
20154        {
20155            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20156        } else {
20157            cx.propagate();
20158        }
20159    }
20160
20161    pub fn copy_relative_path(
20162        &mut self,
20163        _: &zed_actions::workspace::CopyRelativePath,
20164        _window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) {
20167        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20168            let project = self.project()?.read(cx);
20169            let path = buffer.read(cx).file()?.path();
20170            let path = path.display(project.path_style(cx));
20171            Some(path)
20172        }) {
20173            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20174        } else {
20175            cx.propagate();
20176        }
20177    }
20178
20179    /// Returns the project path for the editor's buffer, if any buffer is
20180    /// opened in the editor.
20181    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20182        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20183            buffer.read(cx).project_path(cx)
20184        } else {
20185            None
20186        }
20187    }
20188
20189    // Returns true if the editor handled a go-to-line request
20190    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20191        maybe!({
20192            let breakpoint_store = self.breakpoint_store.as_ref()?;
20193
20194            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20195            else {
20196                self.clear_row_highlights::<ActiveDebugLine>();
20197                return None;
20198            };
20199
20200            let position = active_stack_frame.position;
20201            let buffer_id = position.buffer_id?;
20202            let snapshot = self
20203                .project
20204                .as_ref()?
20205                .read(cx)
20206                .buffer_for_id(buffer_id, cx)?
20207                .read(cx)
20208                .snapshot();
20209
20210            let mut handled = false;
20211            for (id, ExcerptRange { context, .. }) in
20212                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20213            {
20214                if context.start.cmp(&position, &snapshot).is_ge()
20215                    || context.end.cmp(&position, &snapshot).is_lt()
20216                {
20217                    continue;
20218                }
20219                let snapshot = self.buffer.read(cx).snapshot(cx);
20220                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20221
20222                handled = true;
20223                self.clear_row_highlights::<ActiveDebugLine>();
20224
20225                self.go_to_line::<ActiveDebugLine>(
20226                    multibuffer_anchor,
20227                    Some(cx.theme().colors().editor_debugger_active_line_background),
20228                    window,
20229                    cx,
20230                );
20231
20232                cx.notify();
20233            }
20234
20235            handled.then_some(())
20236        })
20237        .is_some()
20238    }
20239
20240    pub fn copy_file_name_without_extension(
20241        &mut self,
20242        _: &CopyFileNameWithoutExtension,
20243        _: &mut Window,
20244        cx: &mut Context<Self>,
20245    ) {
20246        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20247            let file = buffer.read(cx).file()?;
20248            file.path().file_stem()
20249        }) {
20250            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20251        }
20252    }
20253
20254    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20255        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20256            let file = buffer.read(cx).file()?;
20257            Some(file.file_name(cx))
20258        }) {
20259            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20260        }
20261    }
20262
20263    pub fn toggle_git_blame(
20264        &mut self,
20265        _: &::git::Blame,
20266        window: &mut Window,
20267        cx: &mut Context<Self>,
20268    ) {
20269        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20270
20271        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20272            self.start_git_blame(true, window, cx);
20273        }
20274
20275        cx.notify();
20276    }
20277
20278    pub fn toggle_git_blame_inline(
20279        &mut self,
20280        _: &ToggleGitBlameInline,
20281        window: &mut Window,
20282        cx: &mut Context<Self>,
20283    ) {
20284        self.toggle_git_blame_inline_internal(true, window, cx);
20285        cx.notify();
20286    }
20287
20288    pub fn open_git_blame_commit(
20289        &mut self,
20290        _: &OpenGitBlameCommit,
20291        window: &mut Window,
20292        cx: &mut Context<Self>,
20293    ) {
20294        self.open_git_blame_commit_internal(window, cx);
20295    }
20296
20297    fn open_git_blame_commit_internal(
20298        &mut self,
20299        window: &mut Window,
20300        cx: &mut Context<Self>,
20301    ) -> Option<()> {
20302        let blame = self.blame.as_ref()?;
20303        let snapshot = self.snapshot(window, cx);
20304        let cursor = self
20305            .selections
20306            .newest::<Point>(&snapshot.display_snapshot)
20307            .head();
20308        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20309        let (_, blame_entry) = blame
20310            .update(cx, |blame, cx| {
20311                blame
20312                    .blame_for_rows(
20313                        &[RowInfo {
20314                            buffer_id: Some(buffer.remote_id()),
20315                            buffer_row: Some(point.row),
20316                            ..Default::default()
20317                        }],
20318                        cx,
20319                    )
20320                    .next()
20321            })
20322            .flatten()?;
20323        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20324        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20325        let workspace = self.workspace()?.downgrade();
20326        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20327        None
20328    }
20329
20330    pub fn git_blame_inline_enabled(&self) -> bool {
20331        self.git_blame_inline_enabled
20332    }
20333
20334    pub fn toggle_selection_menu(
20335        &mut self,
20336        _: &ToggleSelectionMenu,
20337        _: &mut Window,
20338        cx: &mut Context<Self>,
20339    ) {
20340        self.show_selection_menu = self
20341            .show_selection_menu
20342            .map(|show_selections_menu| !show_selections_menu)
20343            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20344
20345        cx.notify();
20346    }
20347
20348    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20349        self.show_selection_menu
20350            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20351    }
20352
20353    fn start_git_blame(
20354        &mut self,
20355        user_triggered: bool,
20356        window: &mut Window,
20357        cx: &mut Context<Self>,
20358    ) {
20359        if let Some(project) = self.project() {
20360            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20361                && buffer.read(cx).file().is_none()
20362            {
20363                return;
20364            }
20365
20366            let focused = self.focus_handle(cx).contains_focused(window, cx);
20367
20368            let project = project.clone();
20369            let blame = cx
20370                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20371            self.blame_subscription =
20372                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20373            self.blame = Some(blame);
20374        }
20375    }
20376
20377    fn toggle_git_blame_inline_internal(
20378        &mut self,
20379        user_triggered: bool,
20380        window: &mut Window,
20381        cx: &mut Context<Self>,
20382    ) {
20383        if self.git_blame_inline_enabled {
20384            self.git_blame_inline_enabled = false;
20385            self.show_git_blame_inline = false;
20386            self.show_git_blame_inline_delay_task.take();
20387        } else {
20388            self.git_blame_inline_enabled = true;
20389            self.start_git_blame_inline(user_triggered, window, cx);
20390        }
20391
20392        cx.notify();
20393    }
20394
20395    fn start_git_blame_inline(
20396        &mut self,
20397        user_triggered: bool,
20398        window: &mut Window,
20399        cx: &mut Context<Self>,
20400    ) {
20401        self.start_git_blame(user_triggered, window, cx);
20402
20403        if ProjectSettings::get_global(cx)
20404            .git
20405            .inline_blame_delay()
20406            .is_some()
20407        {
20408            self.start_inline_blame_timer(window, cx);
20409        } else {
20410            self.show_git_blame_inline = true
20411        }
20412    }
20413
20414    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20415        self.blame.as_ref()
20416    }
20417
20418    pub fn show_git_blame_gutter(&self) -> bool {
20419        self.show_git_blame_gutter
20420    }
20421
20422    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20423        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20424    }
20425
20426    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20427        self.show_git_blame_inline
20428            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20429            && !self.newest_selection_head_on_empty_line(cx)
20430            && self.has_blame_entries(cx)
20431    }
20432
20433    fn has_blame_entries(&self, cx: &App) -> bool {
20434        self.blame()
20435            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20436    }
20437
20438    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20439        let cursor_anchor = self.selections.newest_anchor().head();
20440
20441        let snapshot = self.buffer.read(cx).snapshot(cx);
20442        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20443
20444        snapshot.line_len(buffer_row) == 0
20445    }
20446
20447    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20448        let buffer_and_selection = maybe!({
20449            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20450            let selection_range = selection.range();
20451
20452            let multi_buffer = self.buffer().read(cx);
20453            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20454            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20455
20456            let (buffer, range, _) = if selection.reversed {
20457                buffer_ranges.first()
20458            } else {
20459                buffer_ranges.last()
20460            }?;
20461
20462            let selection = text::ToPoint::to_point(&range.start, buffer).row
20463                ..text::ToPoint::to_point(&range.end, buffer).row;
20464            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20465        });
20466
20467        let Some((buffer, selection)) = buffer_and_selection else {
20468            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20469        };
20470
20471        let Some(project) = self.project() else {
20472            return Task::ready(Err(anyhow!("editor does not have project")));
20473        };
20474
20475        project.update(cx, |project, cx| {
20476            project.get_permalink_to_line(&buffer, selection, cx)
20477        })
20478    }
20479
20480    pub fn copy_permalink_to_line(
20481        &mut self,
20482        _: &CopyPermalinkToLine,
20483        window: &mut Window,
20484        cx: &mut Context<Self>,
20485    ) {
20486        let permalink_task = self.get_permalink_to_line(cx);
20487        let workspace = self.workspace();
20488
20489        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20490            Ok(permalink) => {
20491                cx.update(|_, cx| {
20492                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20493                })
20494                .ok();
20495            }
20496            Err(err) => {
20497                let message = format!("Failed to copy permalink: {err}");
20498
20499                anyhow::Result::<()>::Err(err).log_err();
20500
20501                if let Some(workspace) = workspace {
20502                    workspace
20503                        .update_in(cx, |workspace, _, cx| {
20504                            struct CopyPermalinkToLine;
20505
20506                            workspace.show_toast(
20507                                Toast::new(
20508                                    NotificationId::unique::<CopyPermalinkToLine>(),
20509                                    message,
20510                                ),
20511                                cx,
20512                            )
20513                        })
20514                        .ok();
20515                }
20516            }
20517        })
20518        .detach();
20519    }
20520
20521    pub fn copy_file_location(
20522        &mut self,
20523        _: &CopyFileLocation,
20524        _: &mut Window,
20525        cx: &mut Context<Self>,
20526    ) {
20527        let selection = self
20528            .selections
20529            .newest::<Point>(&self.display_snapshot(cx))
20530            .start
20531            .row
20532            + 1;
20533        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20534            let project = self.project()?.read(cx);
20535            let file = buffer.read(cx).file()?;
20536            let path = file.path().display(project.path_style(cx));
20537
20538            Some(format!("{path}:{selection}"))
20539        }) {
20540            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20541        }
20542    }
20543
20544    pub fn open_permalink_to_line(
20545        &mut self,
20546        _: &OpenPermalinkToLine,
20547        window: &mut Window,
20548        cx: &mut Context<Self>,
20549    ) {
20550        let permalink_task = self.get_permalink_to_line(cx);
20551        let workspace = self.workspace();
20552
20553        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20554            Ok(permalink) => {
20555                cx.update(|_, cx| {
20556                    cx.open_url(permalink.as_ref());
20557                })
20558                .ok();
20559            }
20560            Err(err) => {
20561                let message = format!("Failed to open permalink: {err}");
20562
20563                anyhow::Result::<()>::Err(err).log_err();
20564
20565                if let Some(workspace) = workspace {
20566                    workspace
20567                        .update(cx, |workspace, cx| {
20568                            struct OpenPermalinkToLine;
20569
20570                            workspace.show_toast(
20571                                Toast::new(
20572                                    NotificationId::unique::<OpenPermalinkToLine>(),
20573                                    message,
20574                                ),
20575                                cx,
20576                            )
20577                        })
20578                        .ok();
20579                }
20580            }
20581        })
20582        .detach();
20583    }
20584
20585    pub fn insert_uuid_v4(
20586        &mut self,
20587        _: &InsertUuidV4,
20588        window: &mut Window,
20589        cx: &mut Context<Self>,
20590    ) {
20591        self.insert_uuid(UuidVersion::V4, window, cx);
20592    }
20593
20594    pub fn insert_uuid_v7(
20595        &mut self,
20596        _: &InsertUuidV7,
20597        window: &mut Window,
20598        cx: &mut Context<Self>,
20599    ) {
20600        self.insert_uuid(UuidVersion::V7, window, cx);
20601    }
20602
20603    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20605        self.transact(window, cx, |this, window, cx| {
20606            let edits = this
20607                .selections
20608                .all::<Point>(&this.display_snapshot(cx))
20609                .into_iter()
20610                .map(|selection| {
20611                    let uuid = match version {
20612                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20613                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20614                    };
20615
20616                    (selection.range(), uuid.to_string())
20617                });
20618            this.edit(edits, cx);
20619            this.refresh_edit_prediction(true, false, window, cx);
20620        });
20621    }
20622
20623    pub fn open_selections_in_multibuffer(
20624        &mut self,
20625        _: &OpenSelectionsInMultibuffer,
20626        window: &mut Window,
20627        cx: &mut Context<Self>,
20628    ) {
20629        let multibuffer = self.buffer.read(cx);
20630
20631        let Some(buffer) = multibuffer.as_singleton() else {
20632            return;
20633        };
20634
20635        let Some(workspace) = self.workspace() else {
20636            return;
20637        };
20638
20639        let title = multibuffer.title(cx).to_string();
20640
20641        let locations = self
20642            .selections
20643            .all_anchors(&self.display_snapshot(cx))
20644            .iter()
20645            .map(|selection| {
20646                (
20647                    buffer.clone(),
20648                    (selection.start.text_anchor..selection.end.text_anchor)
20649                        .to_point(buffer.read(cx)),
20650                )
20651            })
20652            .into_group_map();
20653
20654        cx.spawn_in(window, async move |_, cx| {
20655            workspace.update_in(cx, |workspace, window, cx| {
20656                Self::open_locations_in_multibuffer(
20657                    workspace,
20658                    locations,
20659                    format!("Selections for '{title}'"),
20660                    false,
20661                    MultibufferSelectionMode::All,
20662                    window,
20663                    cx,
20664                );
20665            })
20666        })
20667        .detach();
20668    }
20669
20670    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20671    /// last highlight added will be used.
20672    ///
20673    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20674    pub fn highlight_rows<T: 'static>(
20675        &mut self,
20676        range: Range<Anchor>,
20677        color: Hsla,
20678        options: RowHighlightOptions,
20679        cx: &mut Context<Self>,
20680    ) {
20681        let snapshot = self.buffer().read(cx).snapshot(cx);
20682        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20683        let ix = row_highlights.binary_search_by(|highlight| {
20684            Ordering::Equal
20685                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20686                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20687        });
20688
20689        if let Err(mut ix) = ix {
20690            let index = post_inc(&mut self.highlight_order);
20691
20692            // If this range intersects with the preceding highlight, then merge it with
20693            // the preceding highlight. Otherwise insert a new highlight.
20694            let mut merged = false;
20695            if ix > 0 {
20696                let prev_highlight = &mut row_highlights[ix - 1];
20697                if prev_highlight
20698                    .range
20699                    .end
20700                    .cmp(&range.start, &snapshot)
20701                    .is_ge()
20702                {
20703                    ix -= 1;
20704                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20705                        prev_highlight.range.end = range.end;
20706                    }
20707                    merged = true;
20708                    prev_highlight.index = index;
20709                    prev_highlight.color = color;
20710                    prev_highlight.options = options;
20711                }
20712            }
20713
20714            if !merged {
20715                row_highlights.insert(
20716                    ix,
20717                    RowHighlight {
20718                        range,
20719                        index,
20720                        color,
20721                        options,
20722                        type_id: TypeId::of::<T>(),
20723                    },
20724                );
20725            }
20726
20727            // If any of the following highlights intersect with this one, merge them.
20728            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20729                let highlight = &row_highlights[ix];
20730                if next_highlight
20731                    .range
20732                    .start
20733                    .cmp(&highlight.range.end, &snapshot)
20734                    .is_le()
20735                {
20736                    if next_highlight
20737                        .range
20738                        .end
20739                        .cmp(&highlight.range.end, &snapshot)
20740                        .is_gt()
20741                    {
20742                        row_highlights[ix].range.end = next_highlight.range.end;
20743                    }
20744                    row_highlights.remove(ix + 1);
20745                } else {
20746                    break;
20747                }
20748            }
20749        }
20750    }
20751
20752    /// Remove any highlighted row ranges of the given type that intersect the
20753    /// given ranges.
20754    pub fn remove_highlighted_rows<T: 'static>(
20755        &mut self,
20756        ranges_to_remove: Vec<Range<Anchor>>,
20757        cx: &mut Context<Self>,
20758    ) {
20759        let snapshot = self.buffer().read(cx).snapshot(cx);
20760        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20761        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20762        row_highlights.retain(|highlight| {
20763            while let Some(range_to_remove) = ranges_to_remove.peek() {
20764                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20765                    Ordering::Less | Ordering::Equal => {
20766                        ranges_to_remove.next();
20767                    }
20768                    Ordering::Greater => {
20769                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20770                            Ordering::Less | Ordering::Equal => {
20771                                return false;
20772                            }
20773                            Ordering::Greater => break,
20774                        }
20775                    }
20776                }
20777            }
20778
20779            true
20780        })
20781    }
20782
20783    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20784    pub fn clear_row_highlights<T: 'static>(&mut self) {
20785        self.highlighted_rows.remove(&TypeId::of::<T>());
20786    }
20787
20788    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20789    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20790        self.highlighted_rows
20791            .get(&TypeId::of::<T>())
20792            .map_or(&[] as &[_], |vec| vec.as_slice())
20793            .iter()
20794            .map(|highlight| (highlight.range.clone(), highlight.color))
20795    }
20796
20797    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20798    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20799    /// Allows to ignore certain kinds of highlights.
20800    pub fn highlighted_display_rows(
20801        &self,
20802        window: &mut Window,
20803        cx: &mut App,
20804    ) -> BTreeMap<DisplayRow, LineHighlight> {
20805        let snapshot = self.snapshot(window, cx);
20806        let mut used_highlight_orders = HashMap::default();
20807        self.highlighted_rows
20808            .iter()
20809            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20810            .fold(
20811                BTreeMap::<DisplayRow, LineHighlight>::new(),
20812                |mut unique_rows, highlight| {
20813                    let start = highlight.range.start.to_display_point(&snapshot);
20814                    let end = highlight.range.end.to_display_point(&snapshot);
20815                    let start_row = start.row().0;
20816                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20817                    {
20818                        end.row().0.saturating_sub(1)
20819                    } else {
20820                        end.row().0
20821                    };
20822                    for row in start_row..=end_row {
20823                        let used_index =
20824                            used_highlight_orders.entry(row).or_insert(highlight.index);
20825                        if highlight.index >= *used_index {
20826                            *used_index = highlight.index;
20827                            unique_rows.insert(
20828                                DisplayRow(row),
20829                                LineHighlight {
20830                                    include_gutter: highlight.options.include_gutter,
20831                                    border: None,
20832                                    background: highlight.color.into(),
20833                                    type_id: Some(highlight.type_id),
20834                                },
20835                            );
20836                        }
20837                    }
20838                    unique_rows
20839                },
20840            )
20841    }
20842
20843    pub fn highlighted_display_row_for_autoscroll(
20844        &self,
20845        snapshot: &DisplaySnapshot,
20846    ) -> Option<DisplayRow> {
20847        self.highlighted_rows
20848            .values()
20849            .flat_map(|highlighted_rows| highlighted_rows.iter())
20850            .filter_map(|highlight| {
20851                if highlight.options.autoscroll {
20852                    Some(highlight.range.start.to_display_point(snapshot).row())
20853                } else {
20854                    None
20855                }
20856            })
20857            .min()
20858    }
20859
20860    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20861        self.highlight_background::<SearchWithinRange>(
20862            ranges,
20863            |colors| colors.colors().editor_document_highlight_read_background,
20864            cx,
20865        )
20866    }
20867
20868    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20869        self.breadcrumb_header = Some(new_header);
20870    }
20871
20872    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20873        self.clear_background_highlights::<SearchWithinRange>(cx);
20874    }
20875
20876    pub fn highlight_background<T: 'static>(
20877        &mut self,
20878        ranges: &[Range<Anchor>],
20879        color_fetcher: fn(&Theme) -> Hsla,
20880        cx: &mut Context<Self>,
20881    ) {
20882        self.background_highlights.insert(
20883            HighlightKey::Type(TypeId::of::<T>()),
20884            (color_fetcher, Arc::from(ranges)),
20885        );
20886        self.scrollbar_marker_state.dirty = true;
20887        cx.notify();
20888    }
20889
20890    pub fn highlight_background_key<T: 'static>(
20891        &mut self,
20892        key: usize,
20893        ranges: &[Range<Anchor>],
20894        color_fetcher: fn(&Theme) -> Hsla,
20895        cx: &mut Context<Self>,
20896    ) {
20897        self.background_highlights.insert(
20898            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20899            (color_fetcher, Arc::from(ranges)),
20900        );
20901        self.scrollbar_marker_state.dirty = true;
20902        cx.notify();
20903    }
20904
20905    pub fn clear_background_highlights<T: 'static>(
20906        &mut self,
20907        cx: &mut Context<Self>,
20908    ) -> Option<BackgroundHighlight> {
20909        let text_highlights = self
20910            .background_highlights
20911            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20912        if !text_highlights.1.is_empty() {
20913            self.scrollbar_marker_state.dirty = true;
20914            cx.notify();
20915        }
20916        Some(text_highlights)
20917    }
20918
20919    pub fn highlight_gutter<T: 'static>(
20920        &mut self,
20921        ranges: impl Into<Vec<Range<Anchor>>>,
20922        color_fetcher: fn(&App) -> Hsla,
20923        cx: &mut Context<Self>,
20924    ) {
20925        self.gutter_highlights
20926            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20927        cx.notify();
20928    }
20929
20930    pub fn clear_gutter_highlights<T: 'static>(
20931        &mut self,
20932        cx: &mut Context<Self>,
20933    ) -> Option<GutterHighlight> {
20934        cx.notify();
20935        self.gutter_highlights.remove(&TypeId::of::<T>())
20936    }
20937
20938    pub fn insert_gutter_highlight<T: 'static>(
20939        &mut self,
20940        range: Range<Anchor>,
20941        color_fetcher: fn(&App) -> Hsla,
20942        cx: &mut Context<Self>,
20943    ) {
20944        let snapshot = self.buffer().read(cx).snapshot(cx);
20945        let mut highlights = self
20946            .gutter_highlights
20947            .remove(&TypeId::of::<T>())
20948            .map(|(_, highlights)| highlights)
20949            .unwrap_or_default();
20950        let ix = highlights.binary_search_by(|highlight| {
20951            Ordering::Equal
20952                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20953                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20954        });
20955        if let Err(ix) = ix {
20956            highlights.insert(ix, range);
20957        }
20958        self.gutter_highlights
20959            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20960    }
20961
20962    pub fn remove_gutter_highlights<T: 'static>(
20963        &mut self,
20964        ranges_to_remove: Vec<Range<Anchor>>,
20965        cx: &mut Context<Self>,
20966    ) {
20967        let snapshot = self.buffer().read(cx).snapshot(cx);
20968        let Some((color_fetcher, mut gutter_highlights)) =
20969            self.gutter_highlights.remove(&TypeId::of::<T>())
20970        else {
20971            return;
20972        };
20973        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20974        gutter_highlights.retain(|highlight| {
20975            while let Some(range_to_remove) = ranges_to_remove.peek() {
20976                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20977                    Ordering::Less | Ordering::Equal => {
20978                        ranges_to_remove.next();
20979                    }
20980                    Ordering::Greater => {
20981                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20982                            Ordering::Less | Ordering::Equal => {
20983                                return false;
20984                            }
20985                            Ordering::Greater => break,
20986                        }
20987                    }
20988                }
20989            }
20990
20991            true
20992        });
20993        self.gutter_highlights
20994            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20995    }
20996
20997    #[cfg(feature = "test-support")]
20998    pub fn all_text_highlights(
20999        &self,
21000        window: &mut Window,
21001        cx: &mut Context<Self>,
21002    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21003        let snapshot = self.snapshot(window, cx);
21004        self.display_map.update(cx, |display_map, _| {
21005            display_map
21006                .all_text_highlights()
21007                .map(|highlight| {
21008                    let (style, ranges) = highlight.as_ref();
21009                    (
21010                        *style,
21011                        ranges
21012                            .iter()
21013                            .map(|range| range.clone().to_display_points(&snapshot))
21014                            .collect(),
21015                    )
21016                })
21017                .collect()
21018        })
21019    }
21020
21021    #[cfg(feature = "test-support")]
21022    pub fn all_text_background_highlights(
21023        &self,
21024        window: &mut Window,
21025        cx: &mut Context<Self>,
21026    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21027        let snapshot = self.snapshot(window, cx);
21028        let buffer = &snapshot.buffer_snapshot();
21029        let start = buffer.anchor_before(MultiBufferOffset(0));
21030        let end = buffer.anchor_after(buffer.len());
21031        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21032    }
21033
21034    #[cfg(any(test, feature = "test-support"))]
21035    pub fn sorted_background_highlights_in_range(
21036        &self,
21037        search_range: Range<Anchor>,
21038        display_snapshot: &DisplaySnapshot,
21039        theme: &Theme,
21040    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21041        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21042        res.sort_by(|a, b| {
21043            a.0.start
21044                .cmp(&b.0.start)
21045                .then_with(|| a.0.end.cmp(&b.0.end))
21046                .then_with(|| a.1.cmp(&b.1))
21047        });
21048        res
21049    }
21050
21051    #[cfg(feature = "test-support")]
21052    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21053        let snapshot = self.buffer().read(cx).snapshot(cx);
21054
21055        let highlights = self
21056            .background_highlights
21057            .get(&HighlightKey::Type(TypeId::of::<
21058                items::BufferSearchHighlights,
21059            >()));
21060
21061        if let Some((_color, ranges)) = highlights {
21062            ranges
21063                .iter()
21064                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21065                .collect_vec()
21066        } else {
21067            vec![]
21068        }
21069    }
21070
21071    fn document_highlights_for_position<'a>(
21072        &'a self,
21073        position: Anchor,
21074        buffer: &'a MultiBufferSnapshot,
21075    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21076        let read_highlights = self
21077            .background_highlights
21078            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21079            .map(|h| &h.1);
21080        let write_highlights = self
21081            .background_highlights
21082            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21083            .map(|h| &h.1);
21084        let left_position = position.bias_left(buffer);
21085        let right_position = position.bias_right(buffer);
21086        read_highlights
21087            .into_iter()
21088            .chain(write_highlights)
21089            .flat_map(move |ranges| {
21090                let start_ix = match ranges.binary_search_by(|probe| {
21091                    let cmp = probe.end.cmp(&left_position, buffer);
21092                    if cmp.is_ge() {
21093                        Ordering::Greater
21094                    } else {
21095                        Ordering::Less
21096                    }
21097                }) {
21098                    Ok(i) | Err(i) => i,
21099                };
21100
21101                ranges[start_ix..]
21102                    .iter()
21103                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21104            })
21105    }
21106
21107    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21108        self.background_highlights
21109            .get(&HighlightKey::Type(TypeId::of::<T>()))
21110            .is_some_and(|(_, highlights)| !highlights.is_empty())
21111    }
21112
21113    /// Returns all background highlights for a given range.
21114    ///
21115    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21116    pub fn background_highlights_in_range(
21117        &self,
21118        search_range: Range<Anchor>,
21119        display_snapshot: &DisplaySnapshot,
21120        theme: &Theme,
21121    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21122        let mut results = Vec::new();
21123        for (color_fetcher, ranges) in self.background_highlights.values() {
21124            let color = color_fetcher(theme);
21125            let start_ix = match ranges.binary_search_by(|probe| {
21126                let cmp = probe
21127                    .end
21128                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21129                if cmp.is_gt() {
21130                    Ordering::Greater
21131                } else {
21132                    Ordering::Less
21133                }
21134            }) {
21135                Ok(i) | Err(i) => i,
21136            };
21137            for range in &ranges[start_ix..] {
21138                if range
21139                    .start
21140                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21141                    .is_ge()
21142                {
21143                    break;
21144                }
21145
21146                let start = range.start.to_display_point(display_snapshot);
21147                let end = range.end.to_display_point(display_snapshot);
21148                results.push((start..end, color))
21149            }
21150        }
21151        results
21152    }
21153
21154    pub fn gutter_highlights_in_range(
21155        &self,
21156        search_range: Range<Anchor>,
21157        display_snapshot: &DisplaySnapshot,
21158        cx: &App,
21159    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21160        let mut results = Vec::new();
21161        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21162            let color = color_fetcher(cx);
21163            let start_ix = match ranges.binary_search_by(|probe| {
21164                let cmp = probe
21165                    .end
21166                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21167                if cmp.is_gt() {
21168                    Ordering::Greater
21169                } else {
21170                    Ordering::Less
21171                }
21172            }) {
21173                Ok(i) | Err(i) => i,
21174            };
21175            for range in &ranges[start_ix..] {
21176                if range
21177                    .start
21178                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21179                    .is_ge()
21180                {
21181                    break;
21182                }
21183
21184                let start = range.start.to_display_point(display_snapshot);
21185                let end = range.end.to_display_point(display_snapshot);
21186                results.push((start..end, color))
21187            }
21188        }
21189        results
21190    }
21191
21192    /// Get the text ranges corresponding to the redaction query
21193    pub fn redacted_ranges(
21194        &self,
21195        search_range: Range<Anchor>,
21196        display_snapshot: &DisplaySnapshot,
21197        cx: &App,
21198    ) -> Vec<Range<DisplayPoint>> {
21199        display_snapshot
21200            .buffer_snapshot()
21201            .redacted_ranges(search_range, |file| {
21202                if let Some(file) = file {
21203                    file.is_private()
21204                        && EditorSettings::get(
21205                            Some(SettingsLocation {
21206                                worktree_id: file.worktree_id(cx),
21207                                path: file.path().as_ref(),
21208                            }),
21209                            cx,
21210                        )
21211                        .redact_private_values
21212                } else {
21213                    false
21214                }
21215            })
21216            .map(|range| {
21217                range.start.to_display_point(display_snapshot)
21218                    ..range.end.to_display_point(display_snapshot)
21219            })
21220            .collect()
21221    }
21222
21223    pub fn highlight_text_key<T: 'static>(
21224        &mut self,
21225        key: usize,
21226        ranges: Vec<Range<Anchor>>,
21227        style: HighlightStyle,
21228        merge: bool,
21229        cx: &mut Context<Self>,
21230    ) {
21231        self.display_map.update(cx, |map, cx| {
21232            map.highlight_text(
21233                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21234                ranges,
21235                style,
21236                merge,
21237                cx,
21238            );
21239        });
21240        cx.notify();
21241    }
21242
21243    pub fn highlight_text<T: 'static>(
21244        &mut self,
21245        ranges: Vec<Range<Anchor>>,
21246        style: HighlightStyle,
21247        cx: &mut Context<Self>,
21248    ) {
21249        self.display_map.update(cx, |map, cx| {
21250            map.highlight_text(
21251                HighlightKey::Type(TypeId::of::<T>()),
21252                ranges,
21253                style,
21254                false,
21255                cx,
21256            )
21257        });
21258        cx.notify();
21259    }
21260
21261    pub fn text_highlights<'a, T: 'static>(
21262        &'a self,
21263        cx: &'a App,
21264    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21265        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21266    }
21267
21268    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21269        let cleared = self
21270            .display_map
21271            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21272        if cleared {
21273            cx.notify();
21274        }
21275    }
21276
21277    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21278        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21279            && self.focus_handle.is_focused(window)
21280    }
21281
21282    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21283        self.show_cursor_when_unfocused = is_enabled;
21284        cx.notify();
21285    }
21286
21287    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21288        cx.notify();
21289    }
21290
21291    fn on_debug_session_event(
21292        &mut self,
21293        _session: Entity<Session>,
21294        event: &SessionEvent,
21295        cx: &mut Context<Self>,
21296    ) {
21297        if let SessionEvent::InvalidateInlineValue = event {
21298            self.refresh_inline_values(cx);
21299        }
21300    }
21301
21302    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21303        let Some(project) = self.project.clone() else {
21304            return;
21305        };
21306
21307        if !self.inline_value_cache.enabled {
21308            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21309            self.splice_inlays(&inlays, Vec::new(), cx);
21310            return;
21311        }
21312
21313        let current_execution_position = self
21314            .highlighted_rows
21315            .get(&TypeId::of::<ActiveDebugLine>())
21316            .and_then(|lines| lines.last().map(|line| line.range.end));
21317
21318        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21319            let inline_values = editor
21320                .update(cx, |editor, cx| {
21321                    let Some(current_execution_position) = current_execution_position else {
21322                        return Some(Task::ready(Ok(Vec::new())));
21323                    };
21324
21325                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21326                        let snapshot = buffer.snapshot(cx);
21327
21328                        let excerpt = snapshot.excerpt_containing(
21329                            current_execution_position..current_execution_position,
21330                        )?;
21331
21332                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21333                    })?;
21334
21335                    let range =
21336                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21337
21338                    project.inline_values(buffer, range, cx)
21339                })
21340                .ok()
21341                .flatten()?
21342                .await
21343                .context("refreshing debugger inlays")
21344                .log_err()?;
21345
21346            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21347
21348            for (buffer_id, inline_value) in inline_values
21349                .into_iter()
21350                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21351            {
21352                buffer_inline_values
21353                    .entry(buffer_id)
21354                    .or_default()
21355                    .push(inline_value);
21356            }
21357
21358            editor
21359                .update(cx, |editor, cx| {
21360                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21361                    let mut new_inlays = Vec::default();
21362
21363                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21364                        let buffer_id = buffer_snapshot.remote_id();
21365                        buffer_inline_values
21366                            .get(&buffer_id)
21367                            .into_iter()
21368                            .flatten()
21369                            .for_each(|hint| {
21370                                let inlay = Inlay::debugger(
21371                                    post_inc(&mut editor.next_inlay_id),
21372                                    Anchor::in_buffer(excerpt_id, hint.position),
21373                                    hint.text(),
21374                                );
21375                                if !inlay.text().chars().contains(&'\n') {
21376                                    new_inlays.push(inlay);
21377                                }
21378                            });
21379                    }
21380
21381                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21382                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21383
21384                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21385                })
21386                .ok()?;
21387            Some(())
21388        });
21389    }
21390
21391    fn on_buffer_event(
21392        &mut self,
21393        multibuffer: &Entity<MultiBuffer>,
21394        event: &multi_buffer::Event,
21395        window: &mut Window,
21396        cx: &mut Context<Self>,
21397    ) {
21398        match event {
21399            multi_buffer::Event::Edited { edited_buffer } => {
21400                self.scrollbar_marker_state.dirty = true;
21401                self.active_indent_guides_state.dirty = true;
21402                self.refresh_active_diagnostics(cx);
21403                self.refresh_code_actions(window, cx);
21404                self.refresh_single_line_folds(window, cx);
21405                self.refresh_matching_bracket_highlights(window, cx);
21406                if self.has_active_edit_prediction() {
21407                    self.update_visible_edit_prediction(window, cx);
21408                }
21409
21410                if let Some(buffer) = edited_buffer {
21411                    if buffer.read(cx).file().is_none() {
21412                        cx.emit(EditorEvent::TitleChanged);
21413                    }
21414
21415                    if self.project.is_some() {
21416                        let buffer_id = buffer.read(cx).remote_id();
21417                        self.register_buffer(buffer_id, cx);
21418                        self.update_lsp_data(Some(buffer_id), window, cx);
21419                        self.refresh_inlay_hints(
21420                            InlayHintRefreshReason::BufferEdited(buffer_id),
21421                            cx,
21422                        );
21423                    }
21424                }
21425
21426                cx.emit(EditorEvent::BufferEdited);
21427                cx.emit(SearchEvent::MatchesInvalidated);
21428
21429                let Some(project) = &self.project else { return };
21430                let (telemetry, is_via_ssh) = {
21431                    let project = project.read(cx);
21432                    let telemetry = project.client().telemetry().clone();
21433                    let is_via_ssh = project.is_via_remote_server();
21434                    (telemetry, is_via_ssh)
21435                };
21436                telemetry.log_edit_event("editor", is_via_ssh);
21437            }
21438            multi_buffer::Event::ExcerptsAdded {
21439                buffer,
21440                predecessor,
21441                excerpts,
21442            } => {
21443                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21444                let buffer_id = buffer.read(cx).remote_id();
21445                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21446                    && let Some(project) = &self.project
21447                {
21448                    update_uncommitted_diff_for_buffer(
21449                        cx.entity(),
21450                        project,
21451                        [buffer.clone()],
21452                        self.buffer.clone(),
21453                        cx,
21454                    )
21455                    .detach();
21456                }
21457                self.update_lsp_data(Some(buffer_id), window, cx);
21458                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21459                self.colorize_brackets(false, cx);
21460                cx.emit(EditorEvent::ExcerptsAdded {
21461                    buffer: buffer.clone(),
21462                    predecessor: *predecessor,
21463                    excerpts: excerpts.clone(),
21464                });
21465            }
21466            multi_buffer::Event::ExcerptsRemoved {
21467                ids,
21468                removed_buffer_ids,
21469            } => {
21470                if let Some(inlay_hints) = &mut self.inlay_hints {
21471                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21472                }
21473                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21474                for buffer_id in removed_buffer_ids {
21475                    self.registered_buffers.remove(buffer_id);
21476                }
21477                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21478                cx.emit(EditorEvent::ExcerptsRemoved {
21479                    ids: ids.clone(),
21480                    removed_buffer_ids: removed_buffer_ids.clone(),
21481                });
21482            }
21483            multi_buffer::Event::ExcerptsEdited {
21484                excerpt_ids,
21485                buffer_ids,
21486            } => {
21487                self.display_map.update(cx, |map, cx| {
21488                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21489                });
21490                cx.emit(EditorEvent::ExcerptsEdited {
21491                    ids: excerpt_ids.clone(),
21492                });
21493            }
21494            multi_buffer::Event::ExcerptsExpanded { ids } => {
21495                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21496                self.refresh_document_highlights(cx);
21497                for id in ids {
21498                    self.fetched_tree_sitter_chunks.remove(id);
21499                }
21500                self.colorize_brackets(false, cx);
21501                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21502            }
21503            multi_buffer::Event::Reparsed(buffer_id) => {
21504                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21505                self.refresh_selected_text_highlights(true, window, cx);
21506                self.colorize_brackets(true, cx);
21507                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21508
21509                cx.emit(EditorEvent::Reparsed(*buffer_id));
21510            }
21511            multi_buffer::Event::DiffHunksToggled => {
21512                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21513            }
21514            multi_buffer::Event::LanguageChanged(buffer_id) => {
21515                self.registered_buffers.remove(&buffer_id);
21516                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21517                cx.emit(EditorEvent::Reparsed(*buffer_id));
21518                cx.notify();
21519            }
21520            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21521            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21522            multi_buffer::Event::FileHandleChanged
21523            | multi_buffer::Event::Reloaded
21524            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21525            multi_buffer::Event::DiagnosticsUpdated => {
21526                self.update_diagnostics_state(window, cx);
21527            }
21528            _ => {}
21529        };
21530    }
21531
21532    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21533        if !self.diagnostics_enabled() {
21534            return;
21535        }
21536        self.refresh_active_diagnostics(cx);
21537        self.refresh_inline_diagnostics(true, window, cx);
21538        self.scrollbar_marker_state.dirty = true;
21539        cx.notify();
21540    }
21541
21542    pub fn start_temporary_diff_override(&mut self) {
21543        self.load_diff_task.take();
21544        self.temporary_diff_override = true;
21545    }
21546
21547    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21548        self.temporary_diff_override = false;
21549        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21550        self.buffer.update(cx, |buffer, cx| {
21551            buffer.set_all_diff_hunks_collapsed(cx);
21552        });
21553
21554        if let Some(project) = self.project.clone() {
21555            self.load_diff_task = Some(
21556                update_uncommitted_diff_for_buffer(
21557                    cx.entity(),
21558                    &project,
21559                    self.buffer.read(cx).all_buffers(),
21560                    self.buffer.clone(),
21561                    cx,
21562                )
21563                .shared(),
21564            );
21565        }
21566    }
21567
21568    fn on_display_map_changed(
21569        &mut self,
21570        _: Entity<DisplayMap>,
21571        _: &mut Window,
21572        cx: &mut Context<Self>,
21573    ) {
21574        cx.notify();
21575    }
21576
21577    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21578        if !self.mode.is_full() {
21579            return Vec::new();
21580        }
21581
21582        let theme_settings = theme::ThemeSettings::get_global(cx);
21583
21584        theme_settings
21585            .theme_overrides
21586            .get(cx.theme().name.as_ref())
21587            .map(|theme_style| &theme_style.accents)
21588            .into_iter()
21589            .flatten()
21590            .chain(
21591                theme_settings
21592                    .experimental_theme_overrides
21593                    .as_ref()
21594                    .map(|overrides| &overrides.accents)
21595                    .into_iter()
21596                    .flatten(),
21597            )
21598            .flat_map(|accent| accent.0.clone())
21599            .collect()
21600    }
21601
21602    fn fetch_applicable_language_settings(
21603        &self,
21604        cx: &App,
21605    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21606        if !self.mode.is_full() {
21607            return HashMap::default();
21608        }
21609
21610        self.buffer().read(cx).all_buffers().into_iter().fold(
21611            HashMap::default(),
21612            |mut acc, buffer| {
21613                let buffer = buffer.read(cx);
21614                let language = buffer.language().map(|language| language.name());
21615                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21616                    let file = buffer.file();
21617                    v.insert(language_settings(language, file, cx).into_owned());
21618                }
21619                acc
21620            },
21621        )
21622    }
21623
21624    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21625        let new_language_settings = self.fetch_applicable_language_settings(cx);
21626        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21627        self.applicable_language_settings = new_language_settings;
21628
21629        let new_accent_overrides = self.fetch_accent_overrides(cx);
21630        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21631        self.accent_overrides = new_accent_overrides;
21632
21633        if self.diagnostics_enabled() {
21634            let new_severity = EditorSettings::get_global(cx)
21635                .diagnostics_max_severity
21636                .unwrap_or(DiagnosticSeverity::Hint);
21637            self.set_max_diagnostics_severity(new_severity, cx);
21638        }
21639        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21640        self.update_edit_prediction_settings(cx);
21641        self.refresh_edit_prediction(true, false, window, cx);
21642        self.refresh_inline_values(cx);
21643        self.refresh_inlay_hints(
21644            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21645                self.selections.newest_anchor().head(),
21646                &self.buffer.read(cx).snapshot(cx),
21647                cx,
21648            )),
21649            cx,
21650        );
21651
21652        let old_cursor_shape = self.cursor_shape;
21653        let old_show_breadcrumbs = self.show_breadcrumbs;
21654
21655        {
21656            let editor_settings = EditorSettings::get_global(cx);
21657            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21658            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21659            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21660            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21661        }
21662
21663        if old_cursor_shape != self.cursor_shape {
21664            cx.emit(EditorEvent::CursorShapeChanged);
21665        }
21666
21667        if old_show_breadcrumbs != self.show_breadcrumbs {
21668            cx.emit(EditorEvent::BreadcrumbsChanged);
21669        }
21670
21671        let project_settings = ProjectSettings::get_global(cx);
21672        self.buffer_serialization = self
21673            .should_serialize_buffer()
21674            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21675
21676        if self.mode.is_full() {
21677            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21678            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21679            if self.show_inline_diagnostics != show_inline_diagnostics {
21680                self.show_inline_diagnostics = show_inline_diagnostics;
21681                self.refresh_inline_diagnostics(false, window, cx);
21682            }
21683
21684            if self.git_blame_inline_enabled != inline_blame_enabled {
21685                self.toggle_git_blame_inline_internal(false, window, cx);
21686            }
21687
21688            let minimap_settings = EditorSettings::get_global(cx).minimap;
21689            if self.minimap_visibility != MinimapVisibility::Disabled {
21690                if self.minimap_visibility.settings_visibility()
21691                    != minimap_settings.minimap_enabled()
21692                {
21693                    self.set_minimap_visibility(
21694                        MinimapVisibility::for_mode(self.mode(), cx),
21695                        window,
21696                        cx,
21697                    );
21698                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21699                    minimap_entity.update(cx, |minimap_editor, cx| {
21700                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21701                    })
21702                }
21703            }
21704
21705            if language_settings_changed || accent_overrides_changed {
21706                self.colorize_brackets(true, cx);
21707            }
21708
21709            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21710                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21711            }) {
21712                if !inlay_splice.is_empty() {
21713                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21714                }
21715                self.refresh_colors_for_visible_range(None, window, cx);
21716            }
21717        }
21718
21719        cx.notify();
21720    }
21721
21722    pub fn set_searchable(&mut self, searchable: bool) {
21723        self.searchable = searchable;
21724    }
21725
21726    pub fn searchable(&self) -> bool {
21727        self.searchable
21728    }
21729
21730    pub fn open_excerpts_in_split(
21731        &mut self,
21732        _: &OpenExcerptsSplit,
21733        window: &mut Window,
21734        cx: &mut Context<Self>,
21735    ) {
21736        self.open_excerpts_common(None, true, window, cx)
21737    }
21738
21739    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21740        self.open_excerpts_common(None, false, window, cx)
21741    }
21742
21743    fn open_excerpts_common(
21744        &mut self,
21745        jump_data: Option<JumpData>,
21746        split: bool,
21747        window: &mut Window,
21748        cx: &mut Context<Self>,
21749    ) {
21750        let Some(workspace) = self.workspace() else {
21751            cx.propagate();
21752            return;
21753        };
21754
21755        if self.buffer.read(cx).is_singleton() {
21756            cx.propagate();
21757            return;
21758        }
21759
21760        let mut new_selections_by_buffer = HashMap::default();
21761        match &jump_data {
21762            Some(JumpData::MultiBufferPoint {
21763                excerpt_id,
21764                position,
21765                anchor,
21766                line_offset_from_top,
21767            }) => {
21768                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21769                if let Some(buffer) = multi_buffer_snapshot
21770                    .buffer_id_for_excerpt(*excerpt_id)
21771                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21772                {
21773                    let buffer_snapshot = buffer.read(cx).snapshot();
21774                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21775                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21776                    } else {
21777                        buffer_snapshot.clip_point(*position, Bias::Left)
21778                    };
21779                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21780                    new_selections_by_buffer.insert(
21781                        buffer,
21782                        (
21783                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21784                            Some(*line_offset_from_top),
21785                        ),
21786                    );
21787                }
21788            }
21789            Some(JumpData::MultiBufferRow {
21790                row,
21791                line_offset_from_top,
21792            }) => {
21793                let point = MultiBufferPoint::new(row.0, 0);
21794                if let Some((buffer, buffer_point, _)) =
21795                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21796                {
21797                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21798                    new_selections_by_buffer
21799                        .entry(buffer)
21800                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21801                        .0
21802                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21803                }
21804            }
21805            None => {
21806                let selections = self
21807                    .selections
21808                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21809                let multi_buffer = self.buffer.read(cx);
21810                for selection in selections {
21811                    for (snapshot, range, _, anchor) in multi_buffer
21812                        .snapshot(cx)
21813                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21814                    {
21815                        if let Some(anchor) = anchor {
21816                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21817                            else {
21818                                continue;
21819                            };
21820                            let offset = text::ToOffset::to_offset(
21821                                &anchor.text_anchor,
21822                                &buffer_handle.read(cx).snapshot(),
21823                            );
21824                            let range = BufferOffset(offset)..BufferOffset(offset);
21825                            new_selections_by_buffer
21826                                .entry(buffer_handle)
21827                                .or_insert((Vec::new(), None))
21828                                .0
21829                                .push(range)
21830                        } else {
21831                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21832                            else {
21833                                continue;
21834                            };
21835                            new_selections_by_buffer
21836                                .entry(buffer_handle)
21837                                .or_insert((Vec::new(), None))
21838                                .0
21839                                .push(range)
21840                        }
21841                    }
21842                }
21843            }
21844        }
21845
21846        new_selections_by_buffer
21847            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21848
21849        if new_selections_by_buffer.is_empty() {
21850            return;
21851        }
21852
21853        // We defer the pane interaction because we ourselves are a workspace item
21854        // and activating a new item causes the pane to call a method on us reentrantly,
21855        // which panics if we're on the stack.
21856        window.defer(cx, move |window, cx| {
21857            workspace.update(cx, |workspace, cx| {
21858                let pane = if split {
21859                    workspace.adjacent_pane(window, cx)
21860                } else {
21861                    workspace.active_pane().clone()
21862                };
21863
21864                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21865                    let editor = buffer
21866                        .read(cx)
21867                        .file()
21868                        .is_none()
21869                        .then(|| {
21870                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21871                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21872                            // Instead, we try to activate the existing editor in the pane first.
21873                            let (editor, pane_item_index) =
21874                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21875                                    let editor = item.downcast::<Editor>()?;
21876                                    let singleton_buffer =
21877                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21878                                    if singleton_buffer == buffer {
21879                                        Some((editor, i))
21880                                    } else {
21881                                        None
21882                                    }
21883                                })?;
21884                            pane.update(cx, |pane, cx| {
21885                                pane.activate_item(pane_item_index, true, true, window, cx)
21886                            });
21887                            Some(editor)
21888                        })
21889                        .flatten()
21890                        .unwrap_or_else(|| {
21891                            workspace.open_project_item::<Self>(
21892                                pane.clone(),
21893                                buffer,
21894                                true,
21895                                true,
21896                                window,
21897                                cx,
21898                            )
21899                        });
21900
21901                    editor.update(cx, |editor, cx| {
21902                        let autoscroll = match scroll_offset {
21903                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21904                            None => Autoscroll::newest(),
21905                        };
21906                        let nav_history = editor.nav_history.take();
21907                        editor.change_selections(
21908                            SelectionEffects::scroll(autoscroll),
21909                            window,
21910                            cx,
21911                            |s| {
21912                                s.select_ranges(ranges.into_iter().map(|range| {
21913                                    // we checked that the editor is a singleton editor so the offsets are valid
21914                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21915                                }));
21916                            },
21917                        );
21918                        editor.nav_history = nav_history;
21919                    });
21920                }
21921            })
21922        });
21923    }
21924
21925    // For now, don't allow opening excerpts in buffers that aren't backed by
21926    // regular project files.
21927    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21928        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21929    }
21930
21931    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21932        let snapshot = self.buffer.read(cx).read(cx);
21933        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21934        Some(
21935            ranges
21936                .iter()
21937                .map(move |range| {
21938                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21939                })
21940                .collect(),
21941        )
21942    }
21943
21944    fn selection_replacement_ranges(
21945        &self,
21946        range: Range<MultiBufferOffsetUtf16>,
21947        cx: &mut App,
21948    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21949        let selections = self
21950            .selections
21951            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21952        let newest_selection = selections
21953            .iter()
21954            .max_by_key(|selection| selection.id)
21955            .unwrap();
21956        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21957        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21958        let snapshot = self.buffer.read(cx).read(cx);
21959        selections
21960            .into_iter()
21961            .map(|mut selection| {
21962                selection.start.0.0 =
21963                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21964                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21965                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21966                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21967            })
21968            .collect()
21969    }
21970
21971    fn report_editor_event(
21972        &self,
21973        reported_event: ReportEditorEvent,
21974        file_extension: Option<String>,
21975        cx: &App,
21976    ) {
21977        if cfg!(any(test, feature = "test-support")) {
21978            return;
21979        }
21980
21981        let Some(project) = &self.project else { return };
21982
21983        // If None, we are in a file without an extension
21984        let file = self
21985            .buffer
21986            .read(cx)
21987            .as_singleton()
21988            .and_then(|b| b.read(cx).file());
21989        let file_extension = file_extension.or(file
21990            .as_ref()
21991            .and_then(|file| Path::new(file.file_name(cx)).extension())
21992            .and_then(|e| e.to_str())
21993            .map(|a| a.to_string()));
21994
21995        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21996            .map(|vim_mode| vim_mode.0)
21997            .unwrap_or(false);
21998
21999        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22000        let copilot_enabled = edit_predictions_provider
22001            == language::language_settings::EditPredictionProvider::Copilot;
22002        let copilot_enabled_for_language = self
22003            .buffer
22004            .read(cx)
22005            .language_settings(cx)
22006            .show_edit_predictions;
22007
22008        let project = project.read(cx);
22009        let event_type = reported_event.event_type();
22010
22011        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22012            telemetry::event!(
22013                event_type,
22014                type = if auto_saved {"autosave"} else {"manual"},
22015                file_extension,
22016                vim_mode,
22017                copilot_enabled,
22018                copilot_enabled_for_language,
22019                edit_predictions_provider,
22020                is_via_ssh = project.is_via_remote_server(),
22021            );
22022        } else {
22023            telemetry::event!(
22024                event_type,
22025                file_extension,
22026                vim_mode,
22027                copilot_enabled,
22028                copilot_enabled_for_language,
22029                edit_predictions_provider,
22030                is_via_ssh = project.is_via_remote_server(),
22031            );
22032        };
22033    }
22034
22035    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22036    /// with each line being an array of {text, highlight} objects.
22037    fn copy_highlight_json(
22038        &mut self,
22039        _: &CopyHighlightJson,
22040        window: &mut Window,
22041        cx: &mut Context<Self>,
22042    ) {
22043        #[derive(Serialize)]
22044        struct Chunk<'a> {
22045            text: String,
22046            highlight: Option<&'a str>,
22047        }
22048
22049        let snapshot = self.buffer.read(cx).snapshot(cx);
22050        let range = self
22051            .selected_text_range(false, window, cx)
22052            .and_then(|selection| {
22053                if selection.range.is_empty() {
22054                    None
22055                } else {
22056                    Some(
22057                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22058                            selection.range.start,
22059                        )))
22060                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22061                                selection.range.end,
22062                            ))),
22063                    )
22064                }
22065            })
22066            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22067
22068        let chunks = snapshot.chunks(range, true);
22069        let mut lines = Vec::new();
22070        let mut line: VecDeque<Chunk> = VecDeque::new();
22071
22072        let Some(style) = self.style.as_ref() else {
22073            return;
22074        };
22075
22076        for chunk in chunks {
22077            let highlight = chunk
22078                .syntax_highlight_id
22079                .and_then(|id| id.name(&style.syntax));
22080            let mut chunk_lines = chunk.text.split('\n').peekable();
22081            while let Some(text) = chunk_lines.next() {
22082                let mut merged_with_last_token = false;
22083                if let Some(last_token) = line.back_mut()
22084                    && last_token.highlight == highlight
22085                {
22086                    last_token.text.push_str(text);
22087                    merged_with_last_token = true;
22088                }
22089
22090                if !merged_with_last_token {
22091                    line.push_back(Chunk {
22092                        text: text.into(),
22093                        highlight,
22094                    });
22095                }
22096
22097                if chunk_lines.peek().is_some() {
22098                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22099                        line.pop_front();
22100                    }
22101                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22102                        line.pop_back();
22103                    }
22104
22105                    lines.push(mem::take(&mut line));
22106                }
22107            }
22108        }
22109
22110        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22111            return;
22112        };
22113        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22114    }
22115
22116    pub fn open_context_menu(
22117        &mut self,
22118        _: &OpenContextMenu,
22119        window: &mut Window,
22120        cx: &mut Context<Self>,
22121    ) {
22122        self.request_autoscroll(Autoscroll::newest(), cx);
22123        let position = self
22124            .selections
22125            .newest_display(&self.display_snapshot(cx))
22126            .start;
22127        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22128    }
22129
22130    pub fn replay_insert_event(
22131        &mut self,
22132        text: &str,
22133        relative_utf16_range: Option<Range<isize>>,
22134        window: &mut Window,
22135        cx: &mut Context<Self>,
22136    ) {
22137        if !self.input_enabled {
22138            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22139            return;
22140        }
22141        if let Some(relative_utf16_range) = relative_utf16_range {
22142            let selections = self
22143                .selections
22144                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22145            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22146                let new_ranges = selections.into_iter().map(|range| {
22147                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22148                        range
22149                            .head()
22150                            .0
22151                            .0
22152                            .saturating_add_signed(relative_utf16_range.start),
22153                    ));
22154                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22155                        range
22156                            .head()
22157                            .0
22158                            .0
22159                            .saturating_add_signed(relative_utf16_range.end),
22160                    ));
22161                    start..end
22162                });
22163                s.select_ranges(new_ranges);
22164            });
22165        }
22166
22167        self.handle_input(text, window, cx);
22168    }
22169
22170    pub fn is_focused(&self, window: &Window) -> bool {
22171        self.focus_handle.is_focused(window)
22172    }
22173
22174    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22175        cx.emit(EditorEvent::Focused);
22176
22177        if let Some(descendant) = self
22178            .last_focused_descendant
22179            .take()
22180            .and_then(|descendant| descendant.upgrade())
22181        {
22182            window.focus(&descendant);
22183        } else {
22184            if let Some(blame) = self.blame.as_ref() {
22185                blame.update(cx, GitBlame::focus)
22186            }
22187
22188            self.blink_manager.update(cx, BlinkManager::enable);
22189            self.show_cursor_names(window, cx);
22190            self.buffer.update(cx, |buffer, cx| {
22191                buffer.finalize_last_transaction(cx);
22192                if self.leader_id.is_none() {
22193                    buffer.set_active_selections(
22194                        &self.selections.disjoint_anchors_arc(),
22195                        self.selections.line_mode(),
22196                        self.cursor_shape,
22197                        cx,
22198                    );
22199                }
22200            });
22201
22202            if let Some(position_map) = self.last_position_map.clone() {
22203                EditorElement::mouse_moved(
22204                    self,
22205                    &MouseMoveEvent {
22206                        position: window.mouse_position(),
22207                        pressed_button: None,
22208                        modifiers: window.modifiers(),
22209                    },
22210                    &position_map,
22211                    window,
22212                    cx,
22213                );
22214            }
22215        }
22216    }
22217
22218    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22219        cx.emit(EditorEvent::FocusedIn)
22220    }
22221
22222    fn handle_focus_out(
22223        &mut self,
22224        event: FocusOutEvent,
22225        _window: &mut Window,
22226        cx: &mut Context<Self>,
22227    ) {
22228        if event.blurred != self.focus_handle {
22229            self.last_focused_descendant = Some(event.blurred);
22230        }
22231        self.selection_drag_state = SelectionDragState::None;
22232        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22233    }
22234
22235    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22236        self.blink_manager.update(cx, BlinkManager::disable);
22237        self.buffer
22238            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22239
22240        if let Some(blame) = self.blame.as_ref() {
22241            blame.update(cx, GitBlame::blur)
22242        }
22243        if !self.hover_state.focused(window, cx) {
22244            hide_hover(self, cx);
22245        }
22246        if !self
22247            .context_menu
22248            .borrow()
22249            .as_ref()
22250            .is_some_and(|context_menu| context_menu.focused(window, cx))
22251        {
22252            self.hide_context_menu(window, cx);
22253        }
22254        self.take_active_edit_prediction(cx);
22255        cx.emit(EditorEvent::Blurred);
22256        cx.notify();
22257    }
22258
22259    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22260        let mut pending: String = window
22261            .pending_input_keystrokes()
22262            .into_iter()
22263            .flatten()
22264            .filter_map(|keystroke| keystroke.key_char.clone())
22265            .collect();
22266
22267        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22268            pending = "".to_string();
22269        }
22270
22271        let existing_pending = self
22272            .text_highlights::<PendingInput>(cx)
22273            .map(|(_, ranges)| ranges.to_vec());
22274        if existing_pending.is_none() && pending.is_empty() {
22275            return;
22276        }
22277        let transaction =
22278            self.transact(window, cx, |this, window, cx| {
22279                let selections = this
22280                    .selections
22281                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22282                let edits = selections
22283                    .iter()
22284                    .map(|selection| (selection.end..selection.end, pending.clone()));
22285                this.edit(edits, cx);
22286                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22287                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22288                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22289                    }));
22290                });
22291                if let Some(existing_ranges) = existing_pending {
22292                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22293                    this.edit(edits, cx);
22294                }
22295            });
22296
22297        let snapshot = self.snapshot(window, cx);
22298        let ranges = self
22299            .selections
22300            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22301            .into_iter()
22302            .map(|selection| {
22303                snapshot.buffer_snapshot().anchor_after(selection.end)
22304                    ..snapshot
22305                        .buffer_snapshot()
22306                        .anchor_before(selection.end + pending.len())
22307            })
22308            .collect();
22309
22310        if pending.is_empty() {
22311            self.clear_highlights::<PendingInput>(cx);
22312        } else {
22313            self.highlight_text::<PendingInput>(
22314                ranges,
22315                HighlightStyle {
22316                    underline: Some(UnderlineStyle {
22317                        thickness: px(1.),
22318                        color: None,
22319                        wavy: false,
22320                    }),
22321                    ..Default::default()
22322                },
22323                cx,
22324            );
22325        }
22326
22327        self.ime_transaction = self.ime_transaction.or(transaction);
22328        if let Some(transaction) = self.ime_transaction {
22329            self.buffer.update(cx, |buffer, cx| {
22330                buffer.group_until_transaction(transaction, cx);
22331            });
22332        }
22333
22334        if self.text_highlights::<PendingInput>(cx).is_none() {
22335            self.ime_transaction.take();
22336        }
22337    }
22338
22339    pub fn register_action_renderer(
22340        &mut self,
22341        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22342    ) -> Subscription {
22343        let id = self.next_editor_action_id.post_inc();
22344        self.editor_actions
22345            .borrow_mut()
22346            .insert(id, Box::new(listener));
22347
22348        let editor_actions = self.editor_actions.clone();
22349        Subscription::new(move || {
22350            editor_actions.borrow_mut().remove(&id);
22351        })
22352    }
22353
22354    pub fn register_action<A: Action>(
22355        &mut self,
22356        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22357    ) -> Subscription {
22358        let id = self.next_editor_action_id.post_inc();
22359        let listener = Arc::new(listener);
22360        self.editor_actions.borrow_mut().insert(
22361            id,
22362            Box::new(move |_, window, _| {
22363                let listener = listener.clone();
22364                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22365                    let action = action.downcast_ref().unwrap();
22366                    if phase == DispatchPhase::Bubble {
22367                        listener(action, window, cx)
22368                    }
22369                })
22370            }),
22371        );
22372
22373        let editor_actions = self.editor_actions.clone();
22374        Subscription::new(move || {
22375            editor_actions.borrow_mut().remove(&id);
22376        })
22377    }
22378
22379    pub fn file_header_size(&self) -> u32 {
22380        FILE_HEADER_HEIGHT
22381    }
22382
22383    pub fn restore(
22384        &mut self,
22385        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22386        window: &mut Window,
22387        cx: &mut Context<Self>,
22388    ) {
22389        let workspace = self.workspace();
22390        let project = self.project();
22391        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22392            let mut tasks = Vec::new();
22393            for (buffer_id, changes) in revert_changes {
22394                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22395                    buffer.update(cx, |buffer, cx| {
22396                        buffer.edit(
22397                            changes
22398                                .into_iter()
22399                                .map(|(range, text)| (range, text.to_string())),
22400                            None,
22401                            cx,
22402                        );
22403                    });
22404
22405                    if let Some(project) =
22406                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22407                    {
22408                        project.update(cx, |project, cx| {
22409                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22410                        })
22411                    }
22412                }
22413            }
22414            tasks
22415        });
22416        cx.spawn_in(window, async move |_, cx| {
22417            for (buffer, task) in save_tasks {
22418                let result = task.await;
22419                if result.is_err() {
22420                    let Some(path) = buffer
22421                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22422                        .ok()
22423                    else {
22424                        continue;
22425                    };
22426                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22427                        let Some(task) = cx
22428                            .update_window_entity(workspace, |workspace, window, cx| {
22429                                workspace
22430                                    .open_path_preview(path, None, false, false, false, window, cx)
22431                            })
22432                            .ok()
22433                        else {
22434                            continue;
22435                        };
22436                        task.await.log_err();
22437                    }
22438                }
22439            }
22440        })
22441        .detach();
22442        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22443            selections.refresh()
22444        });
22445    }
22446
22447    pub fn to_pixel_point(
22448        &self,
22449        source: multi_buffer::Anchor,
22450        editor_snapshot: &EditorSnapshot,
22451        window: &mut Window,
22452    ) -> Option<gpui::Point<Pixels>> {
22453        let source_point = source.to_display_point(editor_snapshot);
22454        self.display_to_pixel_point(source_point, editor_snapshot, window)
22455    }
22456
22457    pub fn display_to_pixel_point(
22458        &self,
22459        source: DisplayPoint,
22460        editor_snapshot: &EditorSnapshot,
22461        window: &mut Window,
22462    ) -> Option<gpui::Point<Pixels>> {
22463        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22464        let text_layout_details = self.text_layout_details(window);
22465        let scroll_top = text_layout_details
22466            .scroll_anchor
22467            .scroll_position(editor_snapshot)
22468            .y;
22469
22470        if source.row().as_f64() < scroll_top.floor() {
22471            return None;
22472        }
22473        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22474        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22475        Some(gpui::Point::new(source_x, source_y))
22476    }
22477
22478    pub fn has_visible_completions_menu(&self) -> bool {
22479        !self.edit_prediction_preview_is_active()
22480            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22481                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22482            })
22483    }
22484
22485    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22486        if self.mode.is_minimap() {
22487            return;
22488        }
22489        self.addons
22490            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22491    }
22492
22493    pub fn unregister_addon<T: Addon>(&mut self) {
22494        self.addons.remove(&std::any::TypeId::of::<T>());
22495    }
22496
22497    pub fn addon<T: Addon>(&self) -> Option<&T> {
22498        let type_id = std::any::TypeId::of::<T>();
22499        self.addons
22500            .get(&type_id)
22501            .and_then(|item| item.to_any().downcast_ref::<T>())
22502    }
22503
22504    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22505        let type_id = std::any::TypeId::of::<T>();
22506        self.addons
22507            .get_mut(&type_id)
22508            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22509    }
22510
22511    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22512        let text_layout_details = self.text_layout_details(window);
22513        let style = &text_layout_details.editor_style;
22514        let font_id = window.text_system().resolve_font(&style.text.font());
22515        let font_size = style.text.font_size.to_pixels(window.rem_size());
22516        let line_height = style.text.line_height_in_pixels(window.rem_size());
22517        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22518        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22519
22520        CharacterDimensions {
22521            em_width,
22522            em_advance,
22523            line_height,
22524        }
22525    }
22526
22527    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22528        self.load_diff_task.clone()
22529    }
22530
22531    fn read_metadata_from_db(
22532        &mut self,
22533        item_id: u64,
22534        workspace_id: WorkspaceId,
22535        window: &mut Window,
22536        cx: &mut Context<Editor>,
22537    ) {
22538        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22539            && !self.mode.is_minimap()
22540            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22541        {
22542            let buffer_snapshot = OnceCell::new();
22543
22544            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22545                && !folds.is_empty()
22546            {
22547                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22548                self.fold_ranges(
22549                    folds
22550                        .into_iter()
22551                        .map(|(start, end)| {
22552                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22553                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22554                        })
22555                        .collect(),
22556                    false,
22557                    window,
22558                    cx,
22559                );
22560            }
22561
22562            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22563                && !selections.is_empty()
22564            {
22565                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22566                // skip adding the initial selection to selection history
22567                self.selection_history.mode = SelectionHistoryMode::Skipping;
22568                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22569                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22570                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22571                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22572                    }));
22573                });
22574                self.selection_history.mode = SelectionHistoryMode::Normal;
22575            };
22576        }
22577
22578        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22579    }
22580
22581    fn update_lsp_data(
22582        &mut self,
22583        for_buffer: Option<BufferId>,
22584        window: &mut Window,
22585        cx: &mut Context<'_, Self>,
22586    ) {
22587        self.pull_diagnostics(for_buffer, window, cx);
22588        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22589    }
22590
22591    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22592        if self.ignore_lsp_data() {
22593            return;
22594        }
22595        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22596            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22597        }
22598    }
22599
22600    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22601        if self.ignore_lsp_data() {
22602            return;
22603        }
22604
22605        if !self.registered_buffers.contains_key(&buffer_id)
22606            && let Some(project) = self.project.as_ref()
22607        {
22608            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22609                project.update(cx, |project, cx| {
22610                    self.registered_buffers.insert(
22611                        buffer_id,
22612                        project.register_buffer_with_language_servers(&buffer, cx),
22613                    );
22614                });
22615            } else {
22616                self.registered_buffers.remove(&buffer_id);
22617            }
22618        }
22619    }
22620
22621    fn ignore_lsp_data(&self) -> bool {
22622        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22623        // skip any LSP updates for it.
22624        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22625    }
22626}
22627
22628fn edit_for_markdown_paste<'a>(
22629    buffer: &MultiBufferSnapshot,
22630    range: Range<MultiBufferOffset>,
22631    to_insert: &'a str,
22632    url: Option<url::Url>,
22633) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22634    if url.is_none() {
22635        return (range, Cow::Borrowed(to_insert));
22636    };
22637
22638    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22639
22640    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22641        Cow::Borrowed(to_insert)
22642    } else {
22643        Cow::Owned(format!("[{old_text}]({to_insert})"))
22644    };
22645    (range, new_text)
22646}
22647
22648fn process_completion_for_edit(
22649    completion: &Completion,
22650    intent: CompletionIntent,
22651    buffer: &Entity<Buffer>,
22652    cursor_position: &text::Anchor,
22653    cx: &mut Context<Editor>,
22654) -> CompletionEdit {
22655    let buffer = buffer.read(cx);
22656    let buffer_snapshot = buffer.snapshot();
22657    let (snippet, new_text) = if completion.is_snippet() {
22658        let mut snippet_source = completion.new_text.clone();
22659        // Workaround for typescript language server issues so that methods don't expand within
22660        // strings and functions with type expressions. The previous point is used because the query
22661        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22662        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22663        let previous_point = if previous_point.column > 0 {
22664            cursor_position.to_previous_offset(&buffer_snapshot)
22665        } else {
22666            cursor_position.to_offset(&buffer_snapshot)
22667        };
22668        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22669            && scope.prefers_label_for_snippet_in_completion()
22670            && let Some(label) = completion.label()
22671            && matches!(
22672                completion.kind(),
22673                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22674            )
22675        {
22676            snippet_source = label;
22677        }
22678        match Snippet::parse(&snippet_source).log_err() {
22679            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22680            None => (None, completion.new_text.clone()),
22681        }
22682    } else {
22683        (None, completion.new_text.clone())
22684    };
22685
22686    let mut range_to_replace = {
22687        let replace_range = &completion.replace_range;
22688        if let CompletionSource::Lsp {
22689            insert_range: Some(insert_range),
22690            ..
22691        } = &completion.source
22692        {
22693            debug_assert_eq!(
22694                insert_range.start, replace_range.start,
22695                "insert_range and replace_range should start at the same position"
22696            );
22697            debug_assert!(
22698                insert_range
22699                    .start
22700                    .cmp(cursor_position, &buffer_snapshot)
22701                    .is_le(),
22702                "insert_range should start before or at cursor position"
22703            );
22704            debug_assert!(
22705                replace_range
22706                    .start
22707                    .cmp(cursor_position, &buffer_snapshot)
22708                    .is_le(),
22709                "replace_range should start before or at cursor position"
22710            );
22711
22712            let should_replace = match intent {
22713                CompletionIntent::CompleteWithInsert => false,
22714                CompletionIntent::CompleteWithReplace => true,
22715                CompletionIntent::Complete | CompletionIntent::Compose => {
22716                    let insert_mode =
22717                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22718                            .completions
22719                            .lsp_insert_mode;
22720                    match insert_mode {
22721                        LspInsertMode::Insert => false,
22722                        LspInsertMode::Replace => true,
22723                        LspInsertMode::ReplaceSubsequence => {
22724                            let mut text_to_replace = buffer.chars_for_range(
22725                                buffer.anchor_before(replace_range.start)
22726                                    ..buffer.anchor_after(replace_range.end),
22727                            );
22728                            let mut current_needle = text_to_replace.next();
22729                            for haystack_ch in completion.label.text.chars() {
22730                                if let Some(needle_ch) = current_needle
22731                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22732                                {
22733                                    current_needle = text_to_replace.next();
22734                                }
22735                            }
22736                            current_needle.is_none()
22737                        }
22738                        LspInsertMode::ReplaceSuffix => {
22739                            if replace_range
22740                                .end
22741                                .cmp(cursor_position, &buffer_snapshot)
22742                                .is_gt()
22743                            {
22744                                let range_after_cursor = *cursor_position..replace_range.end;
22745                                let text_after_cursor = buffer
22746                                    .text_for_range(
22747                                        buffer.anchor_before(range_after_cursor.start)
22748                                            ..buffer.anchor_after(range_after_cursor.end),
22749                                    )
22750                                    .collect::<String>()
22751                                    .to_ascii_lowercase();
22752                                completion
22753                                    .label
22754                                    .text
22755                                    .to_ascii_lowercase()
22756                                    .ends_with(&text_after_cursor)
22757                            } else {
22758                                true
22759                            }
22760                        }
22761                    }
22762                }
22763            };
22764
22765            if should_replace {
22766                replace_range.clone()
22767            } else {
22768                insert_range.clone()
22769            }
22770        } else {
22771            replace_range.clone()
22772        }
22773    };
22774
22775    if range_to_replace
22776        .end
22777        .cmp(cursor_position, &buffer_snapshot)
22778        .is_lt()
22779    {
22780        range_to_replace.end = *cursor_position;
22781    }
22782
22783    let replace_range = range_to_replace.to_offset(buffer);
22784    CompletionEdit {
22785        new_text,
22786        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22787        snippet,
22788    }
22789}
22790
22791struct CompletionEdit {
22792    new_text: String,
22793    replace_range: Range<BufferOffset>,
22794    snippet: Option<Snippet>,
22795}
22796
22797fn insert_extra_newline_brackets(
22798    buffer: &MultiBufferSnapshot,
22799    range: Range<MultiBufferOffset>,
22800    language: &language::LanguageScope,
22801) -> bool {
22802    let leading_whitespace_len = buffer
22803        .reversed_chars_at(range.start)
22804        .take_while(|c| c.is_whitespace() && *c != '\n')
22805        .map(|c| c.len_utf8())
22806        .sum::<usize>();
22807    let trailing_whitespace_len = buffer
22808        .chars_at(range.end)
22809        .take_while(|c| c.is_whitespace() && *c != '\n')
22810        .map(|c| c.len_utf8())
22811        .sum::<usize>();
22812    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22813
22814    language.brackets().any(|(pair, enabled)| {
22815        let pair_start = pair.start.trim_end();
22816        let pair_end = pair.end.trim_start();
22817
22818        enabled
22819            && pair.newline
22820            && buffer.contains_str_at(range.end, pair_end)
22821            && buffer.contains_str_at(
22822                range.start.saturating_sub_usize(pair_start.len()),
22823                pair_start,
22824            )
22825    })
22826}
22827
22828fn insert_extra_newline_tree_sitter(
22829    buffer: &MultiBufferSnapshot,
22830    range: Range<MultiBufferOffset>,
22831) -> bool {
22832    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22833        [(buffer, range, _)] => (*buffer, range.clone()),
22834        _ => return false,
22835    };
22836    let pair = {
22837        let mut result: Option<BracketMatch<usize>> = None;
22838
22839        for pair in buffer
22840            .all_bracket_ranges(range.start.0..range.end.0)
22841            .filter(move |pair| {
22842                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22843            })
22844        {
22845            let len = pair.close_range.end - pair.open_range.start;
22846
22847            if let Some(existing) = &result {
22848                let existing_len = existing.close_range.end - existing.open_range.start;
22849                if len > existing_len {
22850                    continue;
22851                }
22852            }
22853
22854            result = Some(pair);
22855        }
22856
22857        result
22858    };
22859    let Some(pair) = pair else {
22860        return false;
22861    };
22862    pair.newline_only
22863        && buffer
22864            .chars_for_range(pair.open_range.end..range.start.0)
22865            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22866            .all(|c| c.is_whitespace() && c != '\n')
22867}
22868
22869fn update_uncommitted_diff_for_buffer(
22870    editor: Entity<Editor>,
22871    project: &Entity<Project>,
22872    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22873    buffer: Entity<MultiBuffer>,
22874    cx: &mut App,
22875) -> Task<()> {
22876    let mut tasks = Vec::new();
22877    project.update(cx, |project, cx| {
22878        for buffer in buffers {
22879            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22880                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22881            }
22882        }
22883    });
22884    cx.spawn(async move |cx| {
22885        let diffs = future::join_all(tasks).await;
22886        if editor
22887            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22888            .unwrap_or(false)
22889        {
22890            return;
22891        }
22892
22893        buffer
22894            .update(cx, |buffer, cx| {
22895                for diff in diffs.into_iter().flatten() {
22896                    buffer.add_diff(diff, cx);
22897                }
22898            })
22899            .ok();
22900    })
22901}
22902
22903fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22904    let tab_size = tab_size.get() as usize;
22905    let mut width = offset;
22906
22907    for ch in text.chars() {
22908        width += if ch == '\t' {
22909            tab_size - (width % tab_size)
22910        } else {
22911            1
22912        };
22913    }
22914
22915    width - offset
22916}
22917
22918#[cfg(test)]
22919mod tests {
22920    use super::*;
22921
22922    #[test]
22923    fn test_string_size_with_expanded_tabs() {
22924        let nz = |val| NonZeroU32::new(val).unwrap();
22925        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22926        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22927        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22928        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22929        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22930        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22931        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22932        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22933    }
22934}
22935
22936/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22937struct WordBreakingTokenizer<'a> {
22938    input: &'a str,
22939}
22940
22941impl<'a> WordBreakingTokenizer<'a> {
22942    fn new(input: &'a str) -> Self {
22943        Self { input }
22944    }
22945}
22946
22947fn is_char_ideographic(ch: char) -> bool {
22948    use unicode_script::Script::*;
22949    use unicode_script::UnicodeScript;
22950    matches!(ch.script(), Han | Tangut | Yi)
22951}
22952
22953fn is_grapheme_ideographic(text: &str) -> bool {
22954    text.chars().any(is_char_ideographic)
22955}
22956
22957fn is_grapheme_whitespace(text: &str) -> bool {
22958    text.chars().any(|x| x.is_whitespace())
22959}
22960
22961fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22962    text.chars()
22963        .next()
22964        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22965}
22966
22967#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22968enum WordBreakToken<'a> {
22969    Word { token: &'a str, grapheme_len: usize },
22970    InlineWhitespace { token: &'a str, grapheme_len: usize },
22971    Newline,
22972}
22973
22974impl<'a> Iterator for WordBreakingTokenizer<'a> {
22975    /// Yields a span, the count of graphemes in the token, and whether it was
22976    /// whitespace. Note that it also breaks at word boundaries.
22977    type Item = WordBreakToken<'a>;
22978
22979    fn next(&mut self) -> Option<Self::Item> {
22980        use unicode_segmentation::UnicodeSegmentation;
22981        if self.input.is_empty() {
22982            return None;
22983        }
22984
22985        let mut iter = self.input.graphemes(true).peekable();
22986        let mut offset = 0;
22987        let mut grapheme_len = 0;
22988        if let Some(first_grapheme) = iter.next() {
22989            let is_newline = first_grapheme == "\n";
22990            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22991            offset += first_grapheme.len();
22992            grapheme_len += 1;
22993            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22994                if let Some(grapheme) = iter.peek().copied()
22995                    && should_stay_with_preceding_ideograph(grapheme)
22996                {
22997                    offset += grapheme.len();
22998                    grapheme_len += 1;
22999                }
23000            } else {
23001                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23002                let mut next_word_bound = words.peek().copied();
23003                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23004                    next_word_bound = words.next();
23005                }
23006                while let Some(grapheme) = iter.peek().copied() {
23007                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23008                        break;
23009                    };
23010                    if is_grapheme_whitespace(grapheme) != is_whitespace
23011                        || (grapheme == "\n") != is_newline
23012                    {
23013                        break;
23014                    };
23015                    offset += grapheme.len();
23016                    grapheme_len += 1;
23017                    iter.next();
23018                }
23019            }
23020            let token = &self.input[..offset];
23021            self.input = &self.input[offset..];
23022            if token == "\n" {
23023                Some(WordBreakToken::Newline)
23024            } else if is_whitespace {
23025                Some(WordBreakToken::InlineWhitespace {
23026                    token,
23027                    grapheme_len,
23028                })
23029            } else {
23030                Some(WordBreakToken::Word {
23031                    token,
23032                    grapheme_len,
23033                })
23034            }
23035        } else {
23036            None
23037        }
23038    }
23039}
23040
23041#[test]
23042fn test_word_breaking_tokenizer() {
23043    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23044        ("", &[]),
23045        ("  ", &[whitespace("  ", 2)]),
23046        ("Ʒ", &[word("Ʒ", 1)]),
23047        ("Ǽ", &[word("Ǽ", 1)]),
23048        ("", &[word("", 1)]),
23049        ("⋑⋑", &[word("⋑⋑", 2)]),
23050        (
23051            "原理,进而",
23052            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23053        ),
23054        (
23055            "hello world",
23056            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23057        ),
23058        (
23059            "hello, world",
23060            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23061        ),
23062        (
23063            "  hello world",
23064            &[
23065                whitespace("  ", 2),
23066                word("hello", 5),
23067                whitespace(" ", 1),
23068                word("world", 5),
23069            ],
23070        ),
23071        (
23072            "这是什么 \n 钢笔",
23073            &[
23074                word("", 1),
23075                word("", 1),
23076                word("", 1),
23077                word("", 1),
23078                whitespace(" ", 1),
23079                newline(),
23080                whitespace(" ", 1),
23081                word("", 1),
23082                word("", 1),
23083            ],
23084        ),
23085        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23086    ];
23087
23088    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23089        WordBreakToken::Word {
23090            token,
23091            grapheme_len,
23092        }
23093    }
23094
23095    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23096        WordBreakToken::InlineWhitespace {
23097            token,
23098            grapheme_len,
23099        }
23100    }
23101
23102    fn newline() -> WordBreakToken<'static> {
23103        WordBreakToken::Newline
23104    }
23105
23106    for (input, result) in tests {
23107        assert_eq!(
23108            WordBreakingTokenizer::new(input)
23109                .collect::<Vec<_>>()
23110                .as_slice(),
23111            *result,
23112        );
23113    }
23114}
23115
23116fn wrap_with_prefix(
23117    first_line_prefix: String,
23118    subsequent_lines_prefix: String,
23119    unwrapped_text: String,
23120    wrap_column: usize,
23121    tab_size: NonZeroU32,
23122    preserve_existing_whitespace: bool,
23123) -> String {
23124    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23125    let subsequent_lines_prefix_len =
23126        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23127    let mut wrapped_text = String::new();
23128    let mut current_line = first_line_prefix;
23129    let mut is_first_line = true;
23130
23131    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23132    let mut current_line_len = first_line_prefix_len;
23133    let mut in_whitespace = false;
23134    for token in tokenizer {
23135        let have_preceding_whitespace = in_whitespace;
23136        match token {
23137            WordBreakToken::Word {
23138                token,
23139                grapheme_len,
23140            } => {
23141                in_whitespace = false;
23142                let current_prefix_len = if is_first_line {
23143                    first_line_prefix_len
23144                } else {
23145                    subsequent_lines_prefix_len
23146                };
23147                if current_line_len + grapheme_len > wrap_column
23148                    && current_line_len != current_prefix_len
23149                {
23150                    wrapped_text.push_str(current_line.trim_end());
23151                    wrapped_text.push('\n');
23152                    is_first_line = false;
23153                    current_line = subsequent_lines_prefix.clone();
23154                    current_line_len = subsequent_lines_prefix_len;
23155                }
23156                current_line.push_str(token);
23157                current_line_len += grapheme_len;
23158            }
23159            WordBreakToken::InlineWhitespace {
23160                mut token,
23161                mut grapheme_len,
23162            } => {
23163                in_whitespace = true;
23164                if have_preceding_whitespace && !preserve_existing_whitespace {
23165                    continue;
23166                }
23167                if !preserve_existing_whitespace {
23168                    // Keep a single whitespace grapheme as-is
23169                    if let Some(first) =
23170                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23171                    {
23172                        token = first;
23173                    } else {
23174                        token = " ";
23175                    }
23176                    grapheme_len = 1;
23177                }
23178                let current_prefix_len = if is_first_line {
23179                    first_line_prefix_len
23180                } else {
23181                    subsequent_lines_prefix_len
23182                };
23183                if current_line_len + grapheme_len > wrap_column {
23184                    wrapped_text.push_str(current_line.trim_end());
23185                    wrapped_text.push('\n');
23186                    is_first_line = false;
23187                    current_line = subsequent_lines_prefix.clone();
23188                    current_line_len = subsequent_lines_prefix_len;
23189                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23190                    current_line.push_str(token);
23191                    current_line_len += grapheme_len;
23192                }
23193            }
23194            WordBreakToken::Newline => {
23195                in_whitespace = true;
23196                let current_prefix_len = if is_first_line {
23197                    first_line_prefix_len
23198                } else {
23199                    subsequent_lines_prefix_len
23200                };
23201                if preserve_existing_whitespace {
23202                    wrapped_text.push_str(current_line.trim_end());
23203                    wrapped_text.push('\n');
23204                    is_first_line = false;
23205                    current_line = subsequent_lines_prefix.clone();
23206                    current_line_len = subsequent_lines_prefix_len;
23207                } else if have_preceding_whitespace {
23208                    continue;
23209                } else if current_line_len + 1 > wrap_column
23210                    && current_line_len != current_prefix_len
23211                {
23212                    wrapped_text.push_str(current_line.trim_end());
23213                    wrapped_text.push('\n');
23214                    is_first_line = false;
23215                    current_line = subsequent_lines_prefix.clone();
23216                    current_line_len = subsequent_lines_prefix_len;
23217                } else if current_line_len != current_prefix_len {
23218                    current_line.push(' ');
23219                    current_line_len += 1;
23220                }
23221            }
23222        }
23223    }
23224
23225    if !current_line.is_empty() {
23226        wrapped_text.push_str(&current_line);
23227    }
23228    wrapped_text
23229}
23230
23231#[test]
23232fn test_wrap_with_prefix() {
23233    assert_eq!(
23234        wrap_with_prefix(
23235            "# ".to_string(),
23236            "# ".to_string(),
23237            "abcdefg".to_string(),
23238            4,
23239            NonZeroU32::new(4).unwrap(),
23240            false,
23241        ),
23242        "# abcdefg"
23243    );
23244    assert_eq!(
23245        wrap_with_prefix(
23246            "".to_string(),
23247            "".to_string(),
23248            "\thello world".to_string(),
23249            8,
23250            NonZeroU32::new(4).unwrap(),
23251            false,
23252        ),
23253        "hello\nworld"
23254    );
23255    assert_eq!(
23256        wrap_with_prefix(
23257            "// ".to_string(),
23258            "// ".to_string(),
23259            "xx \nyy zz aa bb cc".to_string(),
23260            12,
23261            NonZeroU32::new(4).unwrap(),
23262            false,
23263        ),
23264        "// xx yy zz\n// aa bb cc"
23265    );
23266    assert_eq!(
23267        wrap_with_prefix(
23268            String::new(),
23269            String::new(),
23270            "这是什么 \n 钢笔".to_string(),
23271            3,
23272            NonZeroU32::new(4).unwrap(),
23273            false,
23274        ),
23275        "这是什\n么 钢\n"
23276    );
23277    assert_eq!(
23278        wrap_with_prefix(
23279            String::new(),
23280            String::new(),
23281            format!("foo{}bar", '\u{2009}'), // thin space
23282            80,
23283            NonZeroU32::new(4).unwrap(),
23284            false,
23285        ),
23286        format!("foo{}bar", '\u{2009}')
23287    );
23288}
23289
23290pub trait CollaborationHub {
23291    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23292    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23293    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23294}
23295
23296impl CollaborationHub for Entity<Project> {
23297    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23298        self.read(cx).collaborators()
23299    }
23300
23301    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23302        self.read(cx).user_store().read(cx).participant_indices()
23303    }
23304
23305    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23306        let this = self.read(cx);
23307        let user_ids = this.collaborators().values().map(|c| c.user_id);
23308        this.user_store().read(cx).participant_names(user_ids, cx)
23309    }
23310}
23311
23312pub trait SemanticsProvider {
23313    fn hover(
23314        &self,
23315        buffer: &Entity<Buffer>,
23316        position: text::Anchor,
23317        cx: &mut App,
23318    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23319
23320    fn inline_values(
23321        &self,
23322        buffer_handle: Entity<Buffer>,
23323        range: Range<text::Anchor>,
23324        cx: &mut App,
23325    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23326
23327    fn applicable_inlay_chunks(
23328        &self,
23329        buffer: &Entity<Buffer>,
23330        ranges: &[Range<text::Anchor>],
23331        cx: &mut App,
23332    ) -> Vec<Range<BufferRow>>;
23333
23334    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23335
23336    fn inlay_hints(
23337        &self,
23338        invalidate: InvalidationStrategy,
23339        buffer: Entity<Buffer>,
23340        ranges: Vec<Range<text::Anchor>>,
23341        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23342        cx: &mut App,
23343    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23344
23345    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23346
23347    fn document_highlights(
23348        &self,
23349        buffer: &Entity<Buffer>,
23350        position: text::Anchor,
23351        cx: &mut App,
23352    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23353
23354    fn definitions(
23355        &self,
23356        buffer: &Entity<Buffer>,
23357        position: text::Anchor,
23358        kind: GotoDefinitionKind,
23359        cx: &mut App,
23360    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23361
23362    fn range_for_rename(
23363        &self,
23364        buffer: &Entity<Buffer>,
23365        position: text::Anchor,
23366        cx: &mut App,
23367    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23368
23369    fn perform_rename(
23370        &self,
23371        buffer: &Entity<Buffer>,
23372        position: text::Anchor,
23373        new_name: String,
23374        cx: &mut App,
23375    ) -> Option<Task<Result<ProjectTransaction>>>;
23376}
23377
23378pub trait CompletionProvider {
23379    fn completions(
23380        &self,
23381        excerpt_id: ExcerptId,
23382        buffer: &Entity<Buffer>,
23383        buffer_position: text::Anchor,
23384        trigger: CompletionContext,
23385        window: &mut Window,
23386        cx: &mut Context<Editor>,
23387    ) -> Task<Result<Vec<CompletionResponse>>>;
23388
23389    fn resolve_completions(
23390        &self,
23391        _buffer: Entity<Buffer>,
23392        _completion_indices: Vec<usize>,
23393        _completions: Rc<RefCell<Box<[Completion]>>>,
23394        _cx: &mut Context<Editor>,
23395    ) -> Task<Result<bool>> {
23396        Task::ready(Ok(false))
23397    }
23398
23399    fn apply_additional_edits_for_completion(
23400        &self,
23401        _buffer: Entity<Buffer>,
23402        _completions: Rc<RefCell<Box<[Completion]>>>,
23403        _completion_index: usize,
23404        _push_to_history: bool,
23405        _cx: &mut Context<Editor>,
23406    ) -> Task<Result<Option<language::Transaction>>> {
23407        Task::ready(Ok(None))
23408    }
23409
23410    fn is_completion_trigger(
23411        &self,
23412        buffer: &Entity<Buffer>,
23413        position: language::Anchor,
23414        text: &str,
23415        trigger_in_words: bool,
23416        menu_is_open: bool,
23417        cx: &mut Context<Editor>,
23418    ) -> bool;
23419
23420    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23421
23422    fn sort_completions(&self) -> bool {
23423        true
23424    }
23425
23426    fn filter_completions(&self) -> bool {
23427        true
23428    }
23429
23430    fn show_snippets(&self) -> bool {
23431        false
23432    }
23433}
23434
23435pub trait CodeActionProvider {
23436    fn id(&self) -> Arc<str>;
23437
23438    fn code_actions(
23439        &self,
23440        buffer: &Entity<Buffer>,
23441        range: Range<text::Anchor>,
23442        window: &mut Window,
23443        cx: &mut App,
23444    ) -> Task<Result<Vec<CodeAction>>>;
23445
23446    fn apply_code_action(
23447        &self,
23448        buffer_handle: Entity<Buffer>,
23449        action: CodeAction,
23450        excerpt_id: ExcerptId,
23451        push_to_history: bool,
23452        window: &mut Window,
23453        cx: &mut App,
23454    ) -> Task<Result<ProjectTransaction>>;
23455}
23456
23457impl CodeActionProvider for Entity<Project> {
23458    fn id(&self) -> Arc<str> {
23459        "project".into()
23460    }
23461
23462    fn code_actions(
23463        &self,
23464        buffer: &Entity<Buffer>,
23465        range: Range<text::Anchor>,
23466        _window: &mut Window,
23467        cx: &mut App,
23468    ) -> Task<Result<Vec<CodeAction>>> {
23469        self.update(cx, |project, cx| {
23470            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23471            let code_actions = project.code_actions(buffer, range, None, cx);
23472            cx.background_spawn(async move {
23473                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23474                Ok(code_lens_actions
23475                    .context("code lens fetch")?
23476                    .into_iter()
23477                    .flatten()
23478                    .chain(
23479                        code_actions
23480                            .context("code action fetch")?
23481                            .into_iter()
23482                            .flatten(),
23483                    )
23484                    .collect())
23485            })
23486        })
23487    }
23488
23489    fn apply_code_action(
23490        &self,
23491        buffer_handle: Entity<Buffer>,
23492        action: CodeAction,
23493        _excerpt_id: ExcerptId,
23494        push_to_history: bool,
23495        _window: &mut Window,
23496        cx: &mut App,
23497    ) -> Task<Result<ProjectTransaction>> {
23498        self.update(cx, |project, cx| {
23499            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23500        })
23501    }
23502}
23503
23504fn snippet_completions(
23505    project: &Project,
23506    buffer: &Entity<Buffer>,
23507    buffer_anchor: text::Anchor,
23508    classifier: CharClassifier,
23509    cx: &mut App,
23510) -> Task<Result<CompletionResponse>> {
23511    let languages = buffer.read(cx).languages_at(buffer_anchor);
23512    let snippet_store = project.snippets().read(cx);
23513
23514    let scopes: Vec<_> = languages
23515        .iter()
23516        .filter_map(|language| {
23517            let language_name = language.lsp_id();
23518            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23519
23520            if snippets.is_empty() {
23521                None
23522            } else {
23523                Some((language.default_scope(), snippets))
23524            }
23525        })
23526        .collect();
23527
23528    if scopes.is_empty() {
23529        return Task::ready(Ok(CompletionResponse {
23530            completions: vec![],
23531            display_options: CompletionDisplayOptions::default(),
23532            is_incomplete: false,
23533        }));
23534    }
23535
23536    let snapshot = buffer.read(cx).text_snapshot();
23537    let executor = cx.background_executor().clone();
23538
23539    cx.background_spawn(async move {
23540        let is_word_char = |c| classifier.is_word(c);
23541
23542        let mut is_incomplete = false;
23543        let mut completions: Vec<Completion> = Vec::new();
23544
23545        const MAX_PREFIX_LEN: usize = 128;
23546        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23547        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23548        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23549
23550        let max_buffer_window: String = snapshot
23551            .text_for_range(window_start..buffer_offset)
23552            .collect();
23553
23554        if max_buffer_window.is_empty() {
23555            return Ok(CompletionResponse {
23556                completions: vec![],
23557                display_options: CompletionDisplayOptions::default(),
23558                is_incomplete: true,
23559            });
23560        }
23561
23562        for (_scope, snippets) in scopes.into_iter() {
23563            // Sort snippets by word count to match longer snippet prefixes first.
23564            let mut sorted_snippet_candidates = snippets
23565                .iter()
23566                .enumerate()
23567                .flat_map(|(snippet_ix, snippet)| {
23568                    snippet
23569                        .prefix
23570                        .iter()
23571                        .enumerate()
23572                        .map(move |(prefix_ix, prefix)| {
23573                            let word_count =
23574                                snippet_candidate_suffixes(prefix, is_word_char).count();
23575                            ((snippet_ix, prefix_ix), prefix, word_count)
23576                        })
23577                })
23578                .collect_vec();
23579            sorted_snippet_candidates
23580                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23581
23582            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23583
23584            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23585                .take(
23586                    sorted_snippet_candidates
23587                        .first()
23588                        .map(|(_, _, word_count)| *word_count)
23589                        .unwrap_or_default(),
23590                )
23591                .collect_vec();
23592
23593            const MAX_RESULTS: usize = 100;
23594            // Each match also remembers how many characters from the buffer it consumed
23595            let mut matches: Vec<(StringMatch, usize)> = vec![];
23596
23597            let mut snippet_list_cutoff_index = 0;
23598            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23599                let word_count = buffer_index + 1;
23600                // Increase `snippet_list_cutoff_index` until we have all of the
23601                // snippets with sufficiently many words.
23602                while sorted_snippet_candidates
23603                    .get(snippet_list_cutoff_index)
23604                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23605                        *snippet_word_count >= word_count
23606                    })
23607                {
23608                    snippet_list_cutoff_index += 1;
23609                }
23610
23611                // Take only the candidates with at least `word_count` many words
23612                let snippet_candidates_at_word_len =
23613                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23614
23615                let candidates = snippet_candidates_at_word_len
23616                    .iter()
23617                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23618                    .enumerate() // index in `sorted_snippet_candidates`
23619                    // First char must match
23620                    .filter(|(_ix, prefix)| {
23621                        itertools::equal(
23622                            prefix
23623                                .chars()
23624                                .next()
23625                                .into_iter()
23626                                .flat_map(|c| c.to_lowercase()),
23627                            buffer_window
23628                                .chars()
23629                                .next()
23630                                .into_iter()
23631                                .flat_map(|c| c.to_lowercase()),
23632                        )
23633                    })
23634                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23635                    .collect::<Vec<StringMatchCandidate>>();
23636
23637                matches.extend(
23638                    fuzzy::match_strings(
23639                        &candidates,
23640                        &buffer_window,
23641                        buffer_window.chars().any(|c| c.is_uppercase()),
23642                        true,
23643                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23644                        &Default::default(),
23645                        executor.clone(),
23646                    )
23647                    .await
23648                    .into_iter()
23649                    .map(|string_match| (string_match, buffer_window.len())),
23650                );
23651
23652                if matches.len() >= MAX_RESULTS {
23653                    break;
23654                }
23655            }
23656
23657            let to_lsp = |point: &text::Anchor| {
23658                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23659                point_to_lsp(end)
23660            };
23661            let lsp_end = to_lsp(&buffer_anchor);
23662
23663            if matches.len() >= MAX_RESULTS {
23664                is_incomplete = true;
23665            }
23666
23667            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23668                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23669                    sorted_snippet_candidates[string_match.candidate_id];
23670                let snippet = &snippets[snippet_index];
23671                let start = buffer_offset - buffer_window_len;
23672                let start = snapshot.anchor_before(start);
23673                let range = start..buffer_anchor;
23674                let lsp_start = to_lsp(&start);
23675                let lsp_range = lsp::Range {
23676                    start: lsp_start,
23677                    end: lsp_end,
23678                };
23679                Completion {
23680                    replace_range: range,
23681                    new_text: snippet.body.clone(),
23682                    source: CompletionSource::Lsp {
23683                        insert_range: None,
23684                        server_id: LanguageServerId(usize::MAX),
23685                        resolved: true,
23686                        lsp_completion: Box::new(lsp::CompletionItem {
23687                            label: snippet.prefix.first().unwrap().clone(),
23688                            kind: Some(CompletionItemKind::SNIPPET),
23689                            label_details: snippet.description.as_ref().map(|description| {
23690                                lsp::CompletionItemLabelDetails {
23691                                    detail: Some(description.clone()),
23692                                    description: None,
23693                                }
23694                            }),
23695                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23696                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23697                                lsp::InsertReplaceEdit {
23698                                    new_text: snippet.body.clone(),
23699                                    insert: lsp_range,
23700                                    replace: lsp_range,
23701                                },
23702                            )),
23703                            filter_text: Some(snippet.body.clone()),
23704                            sort_text: Some(char::MAX.to_string()),
23705                            ..lsp::CompletionItem::default()
23706                        }),
23707                        lsp_defaults: None,
23708                    },
23709                    label: CodeLabel {
23710                        text: matching_prefix.clone(),
23711                        runs: Vec::new(),
23712                        filter_range: 0..matching_prefix.len(),
23713                    },
23714                    icon_path: None,
23715                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23716                        single_line: snippet.name.clone().into(),
23717                        plain_text: snippet
23718                            .description
23719                            .clone()
23720                            .map(|description| description.into()),
23721                    }),
23722                    insert_text_mode: None,
23723                    confirm: None,
23724                    match_start: Some(start),
23725                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23726                }
23727            }));
23728        }
23729
23730        Ok(CompletionResponse {
23731            completions,
23732            display_options: CompletionDisplayOptions::default(),
23733            is_incomplete,
23734        })
23735    })
23736}
23737
23738impl CompletionProvider for Entity<Project> {
23739    fn completions(
23740        &self,
23741        _excerpt_id: ExcerptId,
23742        buffer: &Entity<Buffer>,
23743        buffer_position: text::Anchor,
23744        options: CompletionContext,
23745        _window: &mut Window,
23746        cx: &mut Context<Editor>,
23747    ) -> Task<Result<Vec<CompletionResponse>>> {
23748        self.update(cx, |project, cx| {
23749            let task = project.completions(buffer, buffer_position, options, cx);
23750            cx.background_spawn(task)
23751        })
23752    }
23753
23754    fn resolve_completions(
23755        &self,
23756        buffer: Entity<Buffer>,
23757        completion_indices: Vec<usize>,
23758        completions: Rc<RefCell<Box<[Completion]>>>,
23759        cx: &mut Context<Editor>,
23760    ) -> Task<Result<bool>> {
23761        self.update(cx, |project, cx| {
23762            project.lsp_store().update(cx, |lsp_store, cx| {
23763                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23764            })
23765        })
23766    }
23767
23768    fn apply_additional_edits_for_completion(
23769        &self,
23770        buffer: Entity<Buffer>,
23771        completions: Rc<RefCell<Box<[Completion]>>>,
23772        completion_index: usize,
23773        push_to_history: bool,
23774        cx: &mut Context<Editor>,
23775    ) -> Task<Result<Option<language::Transaction>>> {
23776        self.update(cx, |project, cx| {
23777            project.lsp_store().update(cx, |lsp_store, cx| {
23778                lsp_store.apply_additional_edits_for_completion(
23779                    buffer,
23780                    completions,
23781                    completion_index,
23782                    push_to_history,
23783                    cx,
23784                )
23785            })
23786        })
23787    }
23788
23789    fn is_completion_trigger(
23790        &self,
23791        buffer: &Entity<Buffer>,
23792        position: language::Anchor,
23793        text: &str,
23794        trigger_in_words: bool,
23795        menu_is_open: bool,
23796        cx: &mut Context<Editor>,
23797    ) -> bool {
23798        let mut chars = text.chars();
23799        let char = if let Some(char) = chars.next() {
23800            char
23801        } else {
23802            return false;
23803        };
23804        if chars.next().is_some() {
23805            return false;
23806        }
23807
23808        let buffer = buffer.read(cx);
23809        let snapshot = buffer.snapshot();
23810        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23811            return false;
23812        }
23813        let classifier = snapshot
23814            .char_classifier_at(position)
23815            .scope_context(Some(CharScopeContext::Completion));
23816        if trigger_in_words && classifier.is_word(char) {
23817            return true;
23818        }
23819
23820        buffer.completion_triggers().contains(text)
23821    }
23822
23823    fn show_snippets(&self) -> bool {
23824        true
23825    }
23826}
23827
23828impl SemanticsProvider for Entity<Project> {
23829    fn hover(
23830        &self,
23831        buffer: &Entity<Buffer>,
23832        position: text::Anchor,
23833        cx: &mut App,
23834    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23835        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23836    }
23837
23838    fn document_highlights(
23839        &self,
23840        buffer: &Entity<Buffer>,
23841        position: text::Anchor,
23842        cx: &mut App,
23843    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23844        Some(self.update(cx, |project, cx| {
23845            project.document_highlights(buffer, position, cx)
23846        }))
23847    }
23848
23849    fn definitions(
23850        &self,
23851        buffer: &Entity<Buffer>,
23852        position: text::Anchor,
23853        kind: GotoDefinitionKind,
23854        cx: &mut App,
23855    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23856        Some(self.update(cx, |project, cx| match kind {
23857            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23858            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23859            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23860            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23861        }))
23862    }
23863
23864    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23865        self.update(cx, |project, cx| {
23866            if project
23867                .active_debug_session(cx)
23868                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23869            {
23870                return true;
23871            }
23872
23873            buffer.update(cx, |buffer, cx| {
23874                project.any_language_server_supports_inlay_hints(buffer, cx)
23875            })
23876        })
23877    }
23878
23879    fn inline_values(
23880        &self,
23881        buffer_handle: Entity<Buffer>,
23882        range: Range<text::Anchor>,
23883        cx: &mut App,
23884    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23885        self.update(cx, |project, cx| {
23886            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23887
23888            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23889        })
23890    }
23891
23892    fn applicable_inlay_chunks(
23893        &self,
23894        buffer: &Entity<Buffer>,
23895        ranges: &[Range<text::Anchor>],
23896        cx: &mut App,
23897    ) -> Vec<Range<BufferRow>> {
23898        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23899            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23900        })
23901    }
23902
23903    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23904        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23905            lsp_store.invalidate_inlay_hints(for_buffers)
23906        });
23907    }
23908
23909    fn inlay_hints(
23910        &self,
23911        invalidate: InvalidationStrategy,
23912        buffer: Entity<Buffer>,
23913        ranges: Vec<Range<text::Anchor>>,
23914        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23915        cx: &mut App,
23916    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23917        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23918            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23919        }))
23920    }
23921
23922    fn range_for_rename(
23923        &self,
23924        buffer: &Entity<Buffer>,
23925        position: text::Anchor,
23926        cx: &mut App,
23927    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23928        Some(self.update(cx, |project, cx| {
23929            let buffer = buffer.clone();
23930            let task = project.prepare_rename(buffer.clone(), position, cx);
23931            cx.spawn(async move |_, cx| {
23932                Ok(match task.await? {
23933                    PrepareRenameResponse::Success(range) => Some(range),
23934                    PrepareRenameResponse::InvalidPosition => None,
23935                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23936                        // Fallback on using TreeSitter info to determine identifier range
23937                        buffer.read_with(cx, |buffer, _| {
23938                            let snapshot = buffer.snapshot();
23939                            let (range, kind) = snapshot.surrounding_word(position, None);
23940                            if kind != Some(CharKind::Word) {
23941                                return None;
23942                            }
23943                            Some(
23944                                snapshot.anchor_before(range.start)
23945                                    ..snapshot.anchor_after(range.end),
23946                            )
23947                        })?
23948                    }
23949                })
23950            })
23951        }))
23952    }
23953
23954    fn perform_rename(
23955        &self,
23956        buffer: &Entity<Buffer>,
23957        position: text::Anchor,
23958        new_name: String,
23959        cx: &mut App,
23960    ) -> Option<Task<Result<ProjectTransaction>>> {
23961        Some(self.update(cx, |project, cx| {
23962            project.perform_rename(buffer.clone(), position, new_name, cx)
23963        }))
23964    }
23965}
23966
23967fn consume_contiguous_rows(
23968    contiguous_row_selections: &mut Vec<Selection<Point>>,
23969    selection: &Selection<Point>,
23970    display_map: &DisplaySnapshot,
23971    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23972) -> (MultiBufferRow, MultiBufferRow) {
23973    contiguous_row_selections.push(selection.clone());
23974    let start_row = starting_row(selection, display_map);
23975    let mut end_row = ending_row(selection, display_map);
23976
23977    while let Some(next_selection) = selections.peek() {
23978        if next_selection.start.row <= end_row.0 {
23979            end_row = ending_row(next_selection, display_map);
23980            contiguous_row_selections.push(selections.next().unwrap().clone());
23981        } else {
23982            break;
23983        }
23984    }
23985    (start_row, end_row)
23986}
23987
23988fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23989    if selection.start.column > 0 {
23990        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23991    } else {
23992        MultiBufferRow(selection.start.row)
23993    }
23994}
23995
23996fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23997    if next_selection.end.column > 0 || next_selection.is_empty() {
23998        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23999    } else {
24000        MultiBufferRow(next_selection.end.row)
24001    }
24002}
24003
24004impl EditorSnapshot {
24005    pub fn remote_selections_in_range<'a>(
24006        &'a self,
24007        range: &'a Range<Anchor>,
24008        collaboration_hub: &dyn CollaborationHub,
24009        cx: &'a App,
24010    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24011        let participant_names = collaboration_hub.user_names(cx);
24012        let participant_indices = collaboration_hub.user_participant_indices(cx);
24013        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24014        let collaborators_by_replica_id = collaborators_by_peer_id
24015            .values()
24016            .map(|collaborator| (collaborator.replica_id, collaborator))
24017            .collect::<HashMap<_, _>>();
24018        self.buffer_snapshot()
24019            .selections_in_range(range, false)
24020            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24021                if replica_id == ReplicaId::AGENT {
24022                    Some(RemoteSelection {
24023                        replica_id,
24024                        selection,
24025                        cursor_shape,
24026                        line_mode,
24027                        collaborator_id: CollaboratorId::Agent,
24028                        user_name: Some("Agent".into()),
24029                        color: cx.theme().players().agent(),
24030                    })
24031                } else {
24032                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24033                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24034                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24035                    Some(RemoteSelection {
24036                        replica_id,
24037                        selection,
24038                        cursor_shape,
24039                        line_mode,
24040                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24041                        user_name,
24042                        color: if let Some(index) = participant_index {
24043                            cx.theme().players().color_for_participant(index.0)
24044                        } else {
24045                            cx.theme().players().absent()
24046                        },
24047                    })
24048                }
24049            })
24050    }
24051
24052    pub fn hunks_for_ranges(
24053        &self,
24054        ranges: impl IntoIterator<Item = Range<Point>>,
24055    ) -> Vec<MultiBufferDiffHunk> {
24056        let mut hunks = Vec::new();
24057        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24058            HashMap::default();
24059        for query_range in ranges {
24060            let query_rows =
24061                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24062            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24063                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24064            ) {
24065                // Include deleted hunks that are adjacent to the query range, because
24066                // otherwise they would be missed.
24067                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24068                if hunk.status().is_deleted() {
24069                    intersects_range |= hunk.row_range.start == query_rows.end;
24070                    intersects_range |= hunk.row_range.end == query_rows.start;
24071                }
24072                if intersects_range {
24073                    if !processed_buffer_rows
24074                        .entry(hunk.buffer_id)
24075                        .or_default()
24076                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24077                    {
24078                        continue;
24079                    }
24080                    hunks.push(hunk);
24081                }
24082            }
24083        }
24084
24085        hunks
24086    }
24087
24088    fn display_diff_hunks_for_rows<'a>(
24089        &'a self,
24090        display_rows: Range<DisplayRow>,
24091        folded_buffers: &'a HashSet<BufferId>,
24092    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24093        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24094        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24095
24096        self.buffer_snapshot()
24097            .diff_hunks_in_range(buffer_start..buffer_end)
24098            .filter_map(|hunk| {
24099                if folded_buffers.contains(&hunk.buffer_id) {
24100                    return None;
24101                }
24102
24103                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24104                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24105
24106                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24107                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24108
24109                let display_hunk = if hunk_display_start.column() != 0 {
24110                    DisplayDiffHunk::Folded {
24111                        display_row: hunk_display_start.row(),
24112                    }
24113                } else {
24114                    let mut end_row = hunk_display_end.row();
24115                    if hunk_display_end.column() > 0 {
24116                        end_row.0 += 1;
24117                    }
24118                    let is_created_file = hunk.is_created_file();
24119                    DisplayDiffHunk::Unfolded {
24120                        status: hunk.status(),
24121                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24122                            ..hunk.diff_base_byte_range.end.0,
24123                        display_row_range: hunk_display_start.row()..end_row,
24124                        multi_buffer_range: Anchor::range_in_buffer(
24125                            hunk.excerpt_id,
24126                            hunk.buffer_range,
24127                        ),
24128                        is_created_file,
24129                    }
24130                };
24131
24132                Some(display_hunk)
24133            })
24134    }
24135
24136    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24137        self.display_snapshot
24138            .buffer_snapshot()
24139            .language_at(position)
24140    }
24141
24142    pub fn is_focused(&self) -> bool {
24143        self.is_focused
24144    }
24145
24146    pub fn placeholder_text(&self) -> Option<String> {
24147        self.placeholder_display_snapshot
24148            .as_ref()
24149            .map(|display_map| display_map.text())
24150    }
24151
24152    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24153        self.scroll_anchor.scroll_position(&self.display_snapshot)
24154    }
24155
24156    fn gutter_dimensions(
24157        &self,
24158        font_id: FontId,
24159        font_size: Pixels,
24160        max_line_number_width: Pixels,
24161        cx: &App,
24162    ) -> Option<GutterDimensions> {
24163        if !self.show_gutter {
24164            return None;
24165        }
24166
24167        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24168        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24169
24170        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24171            matches!(
24172                ProjectSettings::get_global(cx).git.git_gutter,
24173                GitGutterSetting::TrackedFiles
24174            )
24175        });
24176        let gutter_settings = EditorSettings::get_global(cx).gutter;
24177        let show_line_numbers = self
24178            .show_line_numbers
24179            .unwrap_or(gutter_settings.line_numbers);
24180        let line_gutter_width = if show_line_numbers {
24181            // Avoid flicker-like gutter resizes when the line number gains another digit by
24182            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24183            let min_width_for_number_on_gutter =
24184                ch_advance * gutter_settings.min_line_number_digits as f32;
24185            max_line_number_width.max(min_width_for_number_on_gutter)
24186        } else {
24187            0.0.into()
24188        };
24189
24190        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24191        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24192
24193        let git_blame_entries_width =
24194            self.git_blame_gutter_max_author_length
24195                .map(|max_author_length| {
24196                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24197                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24198
24199                    /// The number of characters to dedicate to gaps and margins.
24200                    const SPACING_WIDTH: usize = 4;
24201
24202                    let max_char_count = max_author_length.min(renderer.max_author_length())
24203                        + ::git::SHORT_SHA_LENGTH
24204                        + MAX_RELATIVE_TIMESTAMP.len()
24205                        + SPACING_WIDTH;
24206
24207                    ch_advance * max_char_count
24208                });
24209
24210        let is_singleton = self.buffer_snapshot().is_singleton();
24211
24212        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24213        left_padding += if !is_singleton {
24214            ch_width * 4.0
24215        } else if show_runnables || show_breakpoints {
24216            ch_width * 3.0
24217        } else if show_git_gutter && show_line_numbers {
24218            ch_width * 2.0
24219        } else if show_git_gutter || show_line_numbers {
24220            ch_width
24221        } else {
24222            px(0.)
24223        };
24224
24225        let shows_folds = is_singleton && gutter_settings.folds;
24226
24227        let right_padding = if shows_folds && show_line_numbers {
24228            ch_width * 4.0
24229        } else if shows_folds || (!is_singleton && show_line_numbers) {
24230            ch_width * 3.0
24231        } else if show_line_numbers {
24232            ch_width
24233        } else {
24234            px(0.)
24235        };
24236
24237        Some(GutterDimensions {
24238            left_padding,
24239            right_padding,
24240            width: line_gutter_width + left_padding + right_padding,
24241            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24242            git_blame_entries_width,
24243        })
24244    }
24245
24246    pub fn render_crease_toggle(
24247        &self,
24248        buffer_row: MultiBufferRow,
24249        row_contains_cursor: bool,
24250        editor: Entity<Editor>,
24251        window: &mut Window,
24252        cx: &mut App,
24253    ) -> Option<AnyElement> {
24254        let folded = self.is_line_folded(buffer_row);
24255        let mut is_foldable = false;
24256
24257        if let Some(crease) = self
24258            .crease_snapshot
24259            .query_row(buffer_row, self.buffer_snapshot())
24260        {
24261            is_foldable = true;
24262            match crease {
24263                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24264                    if let Some(render_toggle) = render_toggle {
24265                        let toggle_callback =
24266                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24267                                if folded {
24268                                    editor.update(cx, |editor, cx| {
24269                                        editor.fold_at(buffer_row, window, cx)
24270                                    });
24271                                } else {
24272                                    editor.update(cx, |editor, cx| {
24273                                        editor.unfold_at(buffer_row, window, cx)
24274                                    });
24275                                }
24276                            });
24277                        return Some((render_toggle)(
24278                            buffer_row,
24279                            folded,
24280                            toggle_callback,
24281                            window,
24282                            cx,
24283                        ));
24284                    }
24285                }
24286            }
24287        }
24288
24289        is_foldable |= self.starts_indent(buffer_row);
24290
24291        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24292            Some(
24293                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24294                    .toggle_state(folded)
24295                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24296                        if folded {
24297                            this.unfold_at(buffer_row, window, cx);
24298                        } else {
24299                            this.fold_at(buffer_row, window, cx);
24300                        }
24301                    }))
24302                    .into_any_element(),
24303            )
24304        } else {
24305            None
24306        }
24307    }
24308
24309    pub fn render_crease_trailer(
24310        &self,
24311        buffer_row: MultiBufferRow,
24312        window: &mut Window,
24313        cx: &mut App,
24314    ) -> Option<AnyElement> {
24315        let folded = self.is_line_folded(buffer_row);
24316        if let Crease::Inline { render_trailer, .. } = self
24317            .crease_snapshot
24318            .query_row(buffer_row, self.buffer_snapshot())?
24319        {
24320            let render_trailer = render_trailer.as_ref()?;
24321            Some(render_trailer(buffer_row, folded, window, cx))
24322        } else {
24323            None
24324        }
24325    }
24326}
24327
24328impl Deref for EditorSnapshot {
24329    type Target = DisplaySnapshot;
24330
24331    fn deref(&self) -> &Self::Target {
24332        &self.display_snapshot
24333    }
24334}
24335
24336#[derive(Clone, Debug, PartialEq, Eq)]
24337pub enum EditorEvent {
24338    InputIgnored {
24339        text: Arc<str>,
24340    },
24341    InputHandled {
24342        utf16_range_to_replace: Option<Range<isize>>,
24343        text: Arc<str>,
24344    },
24345    ExcerptsAdded {
24346        buffer: Entity<Buffer>,
24347        predecessor: ExcerptId,
24348        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24349    },
24350    ExcerptsRemoved {
24351        ids: Vec<ExcerptId>,
24352        removed_buffer_ids: Vec<BufferId>,
24353    },
24354    BufferFoldToggled {
24355        ids: Vec<ExcerptId>,
24356        folded: bool,
24357    },
24358    ExcerptsEdited {
24359        ids: Vec<ExcerptId>,
24360    },
24361    ExcerptsExpanded {
24362        ids: Vec<ExcerptId>,
24363    },
24364    BufferEdited,
24365    Edited {
24366        transaction_id: clock::Lamport,
24367    },
24368    Reparsed(BufferId),
24369    Focused,
24370    FocusedIn,
24371    Blurred,
24372    DirtyChanged,
24373    Saved,
24374    TitleChanged,
24375    SelectionsChanged {
24376        local: bool,
24377    },
24378    ScrollPositionChanged {
24379        local: bool,
24380        autoscroll: bool,
24381    },
24382    TransactionUndone {
24383        transaction_id: clock::Lamport,
24384    },
24385    TransactionBegun {
24386        transaction_id: clock::Lamport,
24387    },
24388    CursorShapeChanged,
24389    BreadcrumbsChanged,
24390    PushedToNavHistory {
24391        anchor: Anchor,
24392        is_deactivate: bool,
24393    },
24394}
24395
24396impl EventEmitter<EditorEvent> for Editor {}
24397
24398impl Focusable for Editor {
24399    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24400        self.focus_handle.clone()
24401    }
24402}
24403
24404impl Render for Editor {
24405    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24406        let settings = ThemeSettings::get_global(cx);
24407
24408        let mut text_style = match self.mode {
24409            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24410                color: cx.theme().colors().editor_foreground,
24411                font_family: settings.ui_font.family.clone(),
24412                font_features: settings.ui_font.features.clone(),
24413                font_fallbacks: settings.ui_font.fallbacks.clone(),
24414                font_size: rems(0.875).into(),
24415                font_weight: settings.ui_font.weight,
24416                line_height: relative(settings.buffer_line_height.value()),
24417                ..Default::default()
24418            },
24419            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24420                color: cx.theme().colors().editor_foreground,
24421                font_family: settings.buffer_font.family.clone(),
24422                font_features: settings.buffer_font.features.clone(),
24423                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24424                font_size: settings.buffer_font_size(cx).into(),
24425                font_weight: settings.buffer_font.weight,
24426                line_height: relative(settings.buffer_line_height.value()),
24427                ..Default::default()
24428            },
24429        };
24430        if let Some(text_style_refinement) = &self.text_style_refinement {
24431            text_style.refine(text_style_refinement)
24432        }
24433
24434        let background = match self.mode {
24435            EditorMode::SingleLine => cx.theme().system().transparent,
24436            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24437            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24438            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24439        };
24440
24441        EditorElement::new(
24442            &cx.entity(),
24443            EditorStyle {
24444                background,
24445                border: cx.theme().colors().border,
24446                local_player: cx.theme().players().local(),
24447                text: text_style,
24448                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24449                syntax: cx.theme().syntax().clone(),
24450                status: cx.theme().status().clone(),
24451                inlay_hints_style: make_inlay_hints_style(cx),
24452                edit_prediction_styles: make_suggestion_styles(cx),
24453                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24454                show_underlines: self.diagnostics_enabled(),
24455            },
24456        )
24457    }
24458}
24459
24460impl EntityInputHandler for Editor {
24461    fn text_for_range(
24462        &mut self,
24463        range_utf16: Range<usize>,
24464        adjusted_range: &mut Option<Range<usize>>,
24465        _: &mut Window,
24466        cx: &mut Context<Self>,
24467    ) -> Option<String> {
24468        let snapshot = self.buffer.read(cx).read(cx);
24469        let start = snapshot.clip_offset_utf16(
24470            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24471            Bias::Left,
24472        );
24473        let end = snapshot.clip_offset_utf16(
24474            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24475            Bias::Right,
24476        );
24477        if (start.0.0..end.0.0) != range_utf16 {
24478            adjusted_range.replace(start.0.0..end.0.0);
24479        }
24480        Some(snapshot.text_for_range(start..end).collect())
24481    }
24482
24483    fn selected_text_range(
24484        &mut self,
24485        ignore_disabled_input: bool,
24486        _: &mut Window,
24487        cx: &mut Context<Self>,
24488    ) -> Option<UTF16Selection> {
24489        // Prevent the IME menu from appearing when holding down an alphabetic key
24490        // while input is disabled.
24491        if !ignore_disabled_input && !self.input_enabled {
24492            return None;
24493        }
24494
24495        let selection = self
24496            .selections
24497            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24498        let range = selection.range();
24499
24500        Some(UTF16Selection {
24501            range: range.start.0.0..range.end.0.0,
24502            reversed: selection.reversed,
24503        })
24504    }
24505
24506    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24507        let snapshot = self.buffer.read(cx).read(cx);
24508        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24509        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24510    }
24511
24512    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24513        self.clear_highlights::<InputComposition>(cx);
24514        self.ime_transaction.take();
24515    }
24516
24517    fn replace_text_in_range(
24518        &mut self,
24519        range_utf16: Option<Range<usize>>,
24520        text: &str,
24521        window: &mut Window,
24522        cx: &mut Context<Self>,
24523    ) {
24524        if !self.input_enabled {
24525            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24526            return;
24527        }
24528
24529        self.transact(window, cx, |this, window, cx| {
24530            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24531                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24532                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24533                Some(this.selection_replacement_ranges(range_utf16, cx))
24534            } else {
24535                this.marked_text_ranges(cx)
24536            };
24537
24538            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24539                let newest_selection_id = this.selections.newest_anchor().id;
24540                this.selections
24541                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24542                    .iter()
24543                    .zip(ranges_to_replace.iter())
24544                    .find_map(|(selection, range)| {
24545                        if selection.id == newest_selection_id {
24546                            Some(
24547                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24548                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24549                            )
24550                        } else {
24551                            None
24552                        }
24553                    })
24554            });
24555
24556            cx.emit(EditorEvent::InputHandled {
24557                utf16_range_to_replace: range_to_replace,
24558                text: text.into(),
24559            });
24560
24561            if let Some(new_selected_ranges) = new_selected_ranges {
24562                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24563                    selections.select_ranges(new_selected_ranges)
24564                });
24565                this.backspace(&Default::default(), window, cx);
24566            }
24567
24568            this.handle_input(text, window, cx);
24569        });
24570
24571        if let Some(transaction) = self.ime_transaction {
24572            self.buffer.update(cx, |buffer, cx| {
24573                buffer.group_until_transaction(transaction, cx);
24574            });
24575        }
24576
24577        self.unmark_text(window, cx);
24578    }
24579
24580    fn replace_and_mark_text_in_range(
24581        &mut self,
24582        range_utf16: Option<Range<usize>>,
24583        text: &str,
24584        new_selected_range_utf16: Option<Range<usize>>,
24585        window: &mut Window,
24586        cx: &mut Context<Self>,
24587    ) {
24588        if !self.input_enabled {
24589            return;
24590        }
24591
24592        let transaction = self.transact(window, cx, |this, window, cx| {
24593            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24594                let snapshot = this.buffer.read(cx).read(cx);
24595                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24596                    for marked_range in &mut marked_ranges {
24597                        marked_range.end = marked_range.start + relative_range_utf16.end;
24598                        marked_range.start += relative_range_utf16.start;
24599                        marked_range.start =
24600                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24601                        marked_range.end =
24602                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24603                    }
24604                }
24605                Some(marked_ranges)
24606            } else if let Some(range_utf16) = range_utf16 {
24607                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24608                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24609                Some(this.selection_replacement_ranges(range_utf16, cx))
24610            } else {
24611                None
24612            };
24613
24614            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24615                let newest_selection_id = this.selections.newest_anchor().id;
24616                this.selections
24617                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24618                    .iter()
24619                    .zip(ranges_to_replace.iter())
24620                    .find_map(|(selection, range)| {
24621                        if selection.id == newest_selection_id {
24622                            Some(
24623                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24624                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24625                            )
24626                        } else {
24627                            None
24628                        }
24629                    })
24630            });
24631
24632            cx.emit(EditorEvent::InputHandled {
24633                utf16_range_to_replace: range_to_replace,
24634                text: text.into(),
24635            });
24636
24637            if let Some(ranges) = ranges_to_replace {
24638                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24639                    s.select_ranges(ranges)
24640                });
24641            }
24642
24643            let marked_ranges = {
24644                let snapshot = this.buffer.read(cx).read(cx);
24645                this.selections
24646                    .disjoint_anchors_arc()
24647                    .iter()
24648                    .map(|selection| {
24649                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24650                    })
24651                    .collect::<Vec<_>>()
24652            };
24653
24654            if text.is_empty() {
24655                this.unmark_text(window, cx);
24656            } else {
24657                this.highlight_text::<InputComposition>(
24658                    marked_ranges.clone(),
24659                    HighlightStyle {
24660                        underline: Some(UnderlineStyle {
24661                            thickness: px(1.),
24662                            color: None,
24663                            wavy: false,
24664                        }),
24665                        ..Default::default()
24666                    },
24667                    cx,
24668                );
24669            }
24670
24671            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24672            let use_autoclose = this.use_autoclose;
24673            let use_auto_surround = this.use_auto_surround;
24674            this.set_use_autoclose(false);
24675            this.set_use_auto_surround(false);
24676            this.handle_input(text, window, cx);
24677            this.set_use_autoclose(use_autoclose);
24678            this.set_use_auto_surround(use_auto_surround);
24679
24680            if let Some(new_selected_range) = new_selected_range_utf16 {
24681                let snapshot = this.buffer.read(cx).read(cx);
24682                let new_selected_ranges = marked_ranges
24683                    .into_iter()
24684                    .map(|marked_range| {
24685                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24686                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24687                            insertion_start.0 + new_selected_range.start,
24688                        ));
24689                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24690                            insertion_start.0 + new_selected_range.end,
24691                        ));
24692                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24693                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24694                    })
24695                    .collect::<Vec<_>>();
24696
24697                drop(snapshot);
24698                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24699                    selections.select_ranges(new_selected_ranges)
24700                });
24701            }
24702        });
24703
24704        self.ime_transaction = self.ime_transaction.or(transaction);
24705        if let Some(transaction) = self.ime_transaction {
24706            self.buffer.update(cx, |buffer, cx| {
24707                buffer.group_until_transaction(transaction, cx);
24708            });
24709        }
24710
24711        if self.text_highlights::<InputComposition>(cx).is_none() {
24712            self.ime_transaction.take();
24713        }
24714    }
24715
24716    fn bounds_for_range(
24717        &mut self,
24718        range_utf16: Range<usize>,
24719        element_bounds: gpui::Bounds<Pixels>,
24720        window: &mut Window,
24721        cx: &mut Context<Self>,
24722    ) -> Option<gpui::Bounds<Pixels>> {
24723        let text_layout_details = self.text_layout_details(window);
24724        let CharacterDimensions {
24725            em_width,
24726            em_advance,
24727            line_height,
24728        } = self.character_dimensions(window);
24729
24730        let snapshot = self.snapshot(window, cx);
24731        let scroll_position = snapshot.scroll_position();
24732        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24733
24734        let start =
24735            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24736        let x = Pixels::from(
24737            ScrollOffset::from(
24738                snapshot.x_for_display_point(start, &text_layout_details)
24739                    + self.gutter_dimensions.full_width(),
24740            ) - scroll_left,
24741        );
24742        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24743
24744        Some(Bounds {
24745            origin: element_bounds.origin + point(x, y),
24746            size: size(em_width, line_height),
24747        })
24748    }
24749
24750    fn character_index_for_point(
24751        &mut self,
24752        point: gpui::Point<Pixels>,
24753        _window: &mut Window,
24754        _cx: &mut Context<Self>,
24755    ) -> Option<usize> {
24756        let position_map = self.last_position_map.as_ref()?;
24757        if !position_map.text_hitbox.contains(&point) {
24758            return None;
24759        }
24760        let display_point = position_map.point_for_position(point).previous_valid;
24761        let anchor = position_map
24762            .snapshot
24763            .display_point_to_anchor(display_point, Bias::Left);
24764        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24765        Some(utf16_offset.0.0)
24766    }
24767
24768    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24769        self.input_enabled
24770    }
24771}
24772
24773trait SelectionExt {
24774    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24775    fn spanned_rows(
24776        &self,
24777        include_end_if_at_line_start: bool,
24778        map: &DisplaySnapshot,
24779    ) -> Range<MultiBufferRow>;
24780}
24781
24782impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24783    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24784        let start = self
24785            .start
24786            .to_point(map.buffer_snapshot())
24787            .to_display_point(map);
24788        let end = self
24789            .end
24790            .to_point(map.buffer_snapshot())
24791            .to_display_point(map);
24792        if self.reversed {
24793            end..start
24794        } else {
24795            start..end
24796        }
24797    }
24798
24799    fn spanned_rows(
24800        &self,
24801        include_end_if_at_line_start: bool,
24802        map: &DisplaySnapshot,
24803    ) -> Range<MultiBufferRow> {
24804        let start = self.start.to_point(map.buffer_snapshot());
24805        let mut end = self.end.to_point(map.buffer_snapshot());
24806        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24807            end.row -= 1;
24808        }
24809
24810        let buffer_start = map.prev_line_boundary(start).0;
24811        let buffer_end = map.next_line_boundary(end).0;
24812        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24813    }
24814}
24815
24816impl<T: InvalidationRegion> InvalidationStack<T> {
24817    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24818    where
24819        S: Clone + ToOffset,
24820    {
24821        while let Some(region) = self.last() {
24822            let all_selections_inside_invalidation_ranges =
24823                if selections.len() == region.ranges().len() {
24824                    selections
24825                        .iter()
24826                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24827                        .all(|(selection, invalidation_range)| {
24828                            let head = selection.head().to_offset(buffer);
24829                            invalidation_range.start <= head && invalidation_range.end >= head
24830                        })
24831                } else {
24832                    false
24833                };
24834
24835            if all_selections_inside_invalidation_ranges {
24836                break;
24837            } else {
24838                self.pop();
24839            }
24840        }
24841    }
24842}
24843
24844impl<T> Default for InvalidationStack<T> {
24845    fn default() -> Self {
24846        Self(Default::default())
24847    }
24848}
24849
24850impl<T> Deref for InvalidationStack<T> {
24851    type Target = Vec<T>;
24852
24853    fn deref(&self) -> &Self::Target {
24854        &self.0
24855    }
24856}
24857
24858impl<T> DerefMut for InvalidationStack<T> {
24859    fn deref_mut(&mut self) -> &mut Self::Target {
24860        &mut self.0
24861    }
24862}
24863
24864impl InvalidationRegion for SnippetState {
24865    fn ranges(&self) -> &[Range<Anchor>] {
24866        &self.ranges[self.active_index]
24867    }
24868}
24869
24870fn edit_prediction_edit_text(
24871    current_snapshot: &BufferSnapshot,
24872    edits: &[(Range<Anchor>, impl AsRef<str>)],
24873    edit_preview: &EditPreview,
24874    include_deletions: bool,
24875    cx: &App,
24876) -> HighlightedText {
24877    let edits = edits
24878        .iter()
24879        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24880        .collect::<Vec<_>>();
24881
24882    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24883}
24884
24885fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24886    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24887    // Just show the raw edit text with basic styling
24888    let mut text = String::new();
24889    let mut highlights = Vec::new();
24890
24891    let insertion_highlight_style = HighlightStyle {
24892        color: Some(cx.theme().colors().text),
24893        ..Default::default()
24894    };
24895
24896    for (_, edit_text) in edits {
24897        let start_offset = text.len();
24898        text.push_str(edit_text);
24899        let end_offset = text.len();
24900
24901        if start_offset < end_offset {
24902            highlights.push((start_offset..end_offset, insertion_highlight_style));
24903        }
24904    }
24905
24906    HighlightedText {
24907        text: text.into(),
24908        highlights,
24909    }
24910}
24911
24912pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24913    match severity {
24914        lsp::DiagnosticSeverity::ERROR => colors.error,
24915        lsp::DiagnosticSeverity::WARNING => colors.warning,
24916        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24917        lsp::DiagnosticSeverity::HINT => colors.info,
24918        _ => colors.ignored,
24919    }
24920}
24921
24922pub fn styled_runs_for_code_label<'a>(
24923    label: &'a CodeLabel,
24924    syntax_theme: &'a theme::SyntaxTheme,
24925) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24926    let fade_out = HighlightStyle {
24927        fade_out: Some(0.35),
24928        ..Default::default()
24929    };
24930
24931    let mut prev_end = label.filter_range.end;
24932    label
24933        .runs
24934        .iter()
24935        .enumerate()
24936        .flat_map(move |(ix, (range, highlight_id))| {
24937            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24938                style
24939            } else {
24940                return Default::default();
24941            };
24942            let muted_style = style.highlight(fade_out);
24943
24944            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24945            if range.start >= label.filter_range.end {
24946                if range.start > prev_end {
24947                    runs.push((prev_end..range.start, fade_out));
24948                }
24949                runs.push((range.clone(), muted_style));
24950            } else if range.end <= label.filter_range.end {
24951                runs.push((range.clone(), style));
24952            } else {
24953                runs.push((range.start..label.filter_range.end, style));
24954                runs.push((label.filter_range.end..range.end, muted_style));
24955            }
24956            prev_end = cmp::max(prev_end, range.end);
24957
24958            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24959                runs.push((prev_end..label.text.len(), fade_out));
24960            }
24961
24962            runs
24963        })
24964}
24965
24966pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24967    let mut prev_index = 0;
24968    let mut prev_codepoint: Option<char> = None;
24969    text.char_indices()
24970        .chain([(text.len(), '\0')])
24971        .filter_map(move |(index, codepoint)| {
24972            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24973            let is_boundary = index == text.len()
24974                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24975                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24976            if is_boundary {
24977                let chunk = &text[prev_index..index];
24978                prev_index = index;
24979                Some(chunk)
24980            } else {
24981                None
24982            }
24983        })
24984}
24985
24986/// Given a string of text immediately before the cursor, iterates over possible
24987/// strings a snippet could match to. More precisely: returns an iterator over
24988/// suffixes of `text` created by splitting at word boundaries (before & after
24989/// every non-word character).
24990///
24991/// Shorter suffixes are returned first.
24992pub(crate) fn snippet_candidate_suffixes(
24993    text: &str,
24994    is_word_char: impl Fn(char) -> bool,
24995) -> impl std::iter::Iterator<Item = &str> {
24996    let mut prev_index = text.len();
24997    let mut prev_codepoint = None;
24998    text.char_indices()
24999        .rev()
25000        .chain([(0, '\0')])
25001        .filter_map(move |(index, codepoint)| {
25002            let prev_index = std::mem::replace(&mut prev_index, index);
25003            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25004            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25005                None
25006            } else {
25007                let chunk = &text[prev_index..]; // go to end of string
25008                Some(chunk)
25009            }
25010        })
25011}
25012
25013pub trait RangeToAnchorExt: Sized {
25014    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25015
25016    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25017        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25018        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25019    }
25020}
25021
25022impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25023    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25024        let start_offset = self.start.to_offset(snapshot);
25025        let end_offset = self.end.to_offset(snapshot);
25026        if start_offset == end_offset {
25027            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25028        } else {
25029            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25030        }
25031    }
25032}
25033
25034pub trait RowExt {
25035    fn as_f64(&self) -> f64;
25036
25037    fn next_row(&self) -> Self;
25038
25039    fn previous_row(&self) -> Self;
25040
25041    fn minus(&self, other: Self) -> u32;
25042}
25043
25044impl RowExt for DisplayRow {
25045    fn as_f64(&self) -> f64 {
25046        self.0 as _
25047    }
25048
25049    fn next_row(&self) -> Self {
25050        Self(self.0 + 1)
25051    }
25052
25053    fn previous_row(&self) -> Self {
25054        Self(self.0.saturating_sub(1))
25055    }
25056
25057    fn minus(&self, other: Self) -> u32 {
25058        self.0 - other.0
25059    }
25060}
25061
25062impl RowExt for MultiBufferRow {
25063    fn as_f64(&self) -> f64 {
25064        self.0 as _
25065    }
25066
25067    fn next_row(&self) -> Self {
25068        Self(self.0 + 1)
25069    }
25070
25071    fn previous_row(&self) -> Self {
25072        Self(self.0.saturating_sub(1))
25073    }
25074
25075    fn minus(&self, other: Self) -> u32 {
25076        self.0 - other.0
25077    }
25078}
25079
25080trait RowRangeExt {
25081    type Row;
25082
25083    fn len(&self) -> usize;
25084
25085    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25086}
25087
25088impl RowRangeExt for Range<MultiBufferRow> {
25089    type Row = MultiBufferRow;
25090
25091    fn len(&self) -> usize {
25092        (self.end.0 - self.start.0) as usize
25093    }
25094
25095    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25096        (self.start.0..self.end.0).map(MultiBufferRow)
25097    }
25098}
25099
25100impl RowRangeExt for Range<DisplayRow> {
25101    type Row = DisplayRow;
25102
25103    fn len(&self) -> usize {
25104        (self.end.0 - self.start.0) as usize
25105    }
25106
25107    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25108        (self.start.0..self.end.0).map(DisplayRow)
25109    }
25110}
25111
25112/// If select range has more than one line, we
25113/// just point the cursor to range.start.
25114fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25115    if range.start.row == range.end.row {
25116        range
25117    } else {
25118        range.start..range.start
25119    }
25120}
25121pub struct KillRing(ClipboardItem);
25122impl Global for KillRing {}
25123
25124const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25125
25126enum BreakpointPromptEditAction {
25127    Log,
25128    Condition,
25129    HitCondition,
25130}
25131
25132struct BreakpointPromptEditor {
25133    pub(crate) prompt: Entity<Editor>,
25134    editor: WeakEntity<Editor>,
25135    breakpoint_anchor: Anchor,
25136    breakpoint: Breakpoint,
25137    edit_action: BreakpointPromptEditAction,
25138    block_ids: HashSet<CustomBlockId>,
25139    editor_margins: Arc<Mutex<EditorMargins>>,
25140    _subscriptions: Vec<Subscription>,
25141}
25142
25143impl BreakpointPromptEditor {
25144    const MAX_LINES: u8 = 4;
25145
25146    fn new(
25147        editor: WeakEntity<Editor>,
25148        breakpoint_anchor: Anchor,
25149        breakpoint: Breakpoint,
25150        edit_action: BreakpointPromptEditAction,
25151        window: &mut Window,
25152        cx: &mut Context<Self>,
25153    ) -> Self {
25154        let base_text = match edit_action {
25155            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25156            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25157            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25158        }
25159        .map(|msg| msg.to_string())
25160        .unwrap_or_default();
25161
25162        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25163        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25164
25165        let prompt = cx.new(|cx| {
25166            let mut prompt = Editor::new(
25167                EditorMode::AutoHeight {
25168                    min_lines: 1,
25169                    max_lines: Some(Self::MAX_LINES as usize),
25170                },
25171                buffer,
25172                None,
25173                window,
25174                cx,
25175            );
25176            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25177            prompt.set_show_cursor_when_unfocused(false, cx);
25178            prompt.set_placeholder_text(
25179                match edit_action {
25180                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25181                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25182                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25183                },
25184                window,
25185                cx,
25186            );
25187
25188            prompt
25189        });
25190
25191        Self {
25192            prompt,
25193            editor,
25194            breakpoint_anchor,
25195            breakpoint,
25196            edit_action,
25197            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25198            block_ids: Default::default(),
25199            _subscriptions: vec![],
25200        }
25201    }
25202
25203    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25204        self.block_ids.extend(block_ids)
25205    }
25206
25207    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25208        if let Some(editor) = self.editor.upgrade() {
25209            let message = self
25210                .prompt
25211                .read(cx)
25212                .buffer
25213                .read(cx)
25214                .as_singleton()
25215                .expect("A multi buffer in breakpoint prompt isn't possible")
25216                .read(cx)
25217                .as_rope()
25218                .to_string();
25219
25220            editor.update(cx, |editor, cx| {
25221                editor.edit_breakpoint_at_anchor(
25222                    self.breakpoint_anchor,
25223                    self.breakpoint.clone(),
25224                    match self.edit_action {
25225                        BreakpointPromptEditAction::Log => {
25226                            BreakpointEditAction::EditLogMessage(message.into())
25227                        }
25228                        BreakpointPromptEditAction::Condition => {
25229                            BreakpointEditAction::EditCondition(message.into())
25230                        }
25231                        BreakpointPromptEditAction::HitCondition => {
25232                            BreakpointEditAction::EditHitCondition(message.into())
25233                        }
25234                    },
25235                    cx,
25236                );
25237
25238                editor.remove_blocks(self.block_ids.clone(), None, cx);
25239                cx.focus_self(window);
25240            });
25241        }
25242    }
25243
25244    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25245        self.editor
25246            .update(cx, |editor, cx| {
25247                editor.remove_blocks(self.block_ids.clone(), None, cx);
25248                window.focus(&editor.focus_handle);
25249            })
25250            .log_err();
25251    }
25252
25253    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25254        let settings = ThemeSettings::get_global(cx);
25255        let text_style = TextStyle {
25256            color: if self.prompt.read(cx).read_only(cx) {
25257                cx.theme().colors().text_disabled
25258            } else {
25259                cx.theme().colors().text
25260            },
25261            font_family: settings.buffer_font.family.clone(),
25262            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25263            font_size: settings.buffer_font_size(cx).into(),
25264            font_weight: settings.buffer_font.weight,
25265            line_height: relative(settings.buffer_line_height.value()),
25266            ..Default::default()
25267        };
25268        EditorElement::new(
25269            &self.prompt,
25270            EditorStyle {
25271                background: cx.theme().colors().editor_background,
25272                local_player: cx.theme().players().local(),
25273                text: text_style,
25274                ..Default::default()
25275            },
25276        )
25277    }
25278}
25279
25280impl Render for BreakpointPromptEditor {
25281    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25282        let editor_margins = *self.editor_margins.lock();
25283        let gutter_dimensions = editor_margins.gutter;
25284        h_flex()
25285            .key_context("Editor")
25286            .bg(cx.theme().colors().editor_background)
25287            .border_y_1()
25288            .border_color(cx.theme().status().info_border)
25289            .size_full()
25290            .py(window.line_height() / 2.5)
25291            .on_action(cx.listener(Self::confirm))
25292            .on_action(cx.listener(Self::cancel))
25293            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25294            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25295    }
25296}
25297
25298impl Focusable for BreakpointPromptEditor {
25299    fn focus_handle(&self, cx: &App) -> FocusHandle {
25300        self.prompt.focus_handle(cx)
25301    }
25302}
25303
25304fn all_edits_insertions_or_deletions(
25305    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25306    snapshot: &MultiBufferSnapshot,
25307) -> bool {
25308    let mut all_insertions = true;
25309    let mut all_deletions = true;
25310
25311    for (range, new_text) in edits.iter() {
25312        let range_is_empty = range.to_offset(snapshot).is_empty();
25313        let text_is_empty = new_text.is_empty();
25314
25315        if range_is_empty != text_is_empty {
25316            if range_is_empty {
25317                all_deletions = false;
25318            } else {
25319                all_insertions = false;
25320            }
25321        } else {
25322            return false;
25323        }
25324
25325        if !all_insertions && !all_deletions {
25326            return false;
25327        }
25328    }
25329    all_insertions || all_deletions
25330}
25331
25332struct MissingEditPredictionKeybindingTooltip;
25333
25334impl Render for MissingEditPredictionKeybindingTooltip {
25335    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25336        ui::tooltip_container(cx, |container, cx| {
25337            container
25338                .flex_shrink_0()
25339                .max_w_80()
25340                .min_h(rems_from_px(124.))
25341                .justify_between()
25342                .child(
25343                    v_flex()
25344                        .flex_1()
25345                        .text_ui_sm(cx)
25346                        .child(Label::new("Conflict with Accept Keybinding"))
25347                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25348                )
25349                .child(
25350                    h_flex()
25351                        .pb_1()
25352                        .gap_1()
25353                        .items_end()
25354                        .w_full()
25355                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25356                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25357                        }))
25358                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25359                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25360                        })),
25361                )
25362        })
25363    }
25364}
25365
25366#[derive(Debug, Clone, Copy, PartialEq)]
25367pub struct LineHighlight {
25368    pub background: Background,
25369    pub border: Option<gpui::Hsla>,
25370    pub include_gutter: bool,
25371    pub type_id: Option<TypeId>,
25372}
25373
25374struct LineManipulationResult {
25375    pub new_text: String,
25376    pub line_count_before: usize,
25377    pub line_count_after: usize,
25378}
25379
25380fn render_diff_hunk_controls(
25381    row: u32,
25382    status: &DiffHunkStatus,
25383    hunk_range: Range<Anchor>,
25384    is_created_file: bool,
25385    line_height: Pixels,
25386    editor: &Entity<Editor>,
25387    _window: &mut Window,
25388    cx: &mut App,
25389) -> AnyElement {
25390    h_flex()
25391        .h(line_height)
25392        .mr_1()
25393        .gap_1()
25394        .px_0p5()
25395        .pb_1()
25396        .border_x_1()
25397        .border_b_1()
25398        .border_color(cx.theme().colors().border_variant)
25399        .rounded_b_lg()
25400        .bg(cx.theme().colors().editor_background)
25401        .gap_1()
25402        .block_mouse_except_scroll()
25403        .shadow_md()
25404        .child(if status.has_secondary_hunk() {
25405            Button::new(("stage", row as u64), "Stage")
25406                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25407                .tooltip({
25408                    let focus_handle = editor.focus_handle(cx);
25409                    move |_window, cx| {
25410                        Tooltip::for_action_in(
25411                            "Stage Hunk",
25412                            &::git::ToggleStaged,
25413                            &focus_handle,
25414                            cx,
25415                        )
25416                    }
25417                })
25418                .on_click({
25419                    let editor = editor.clone();
25420                    move |_event, _window, cx| {
25421                        editor.update(cx, |editor, cx| {
25422                            editor.stage_or_unstage_diff_hunks(
25423                                true,
25424                                vec![hunk_range.start..hunk_range.start],
25425                                cx,
25426                            );
25427                        });
25428                    }
25429                })
25430        } else {
25431            Button::new(("unstage", row as u64), "Unstage")
25432                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25433                .tooltip({
25434                    let focus_handle = editor.focus_handle(cx);
25435                    move |_window, cx| {
25436                        Tooltip::for_action_in(
25437                            "Unstage Hunk",
25438                            &::git::ToggleStaged,
25439                            &focus_handle,
25440                            cx,
25441                        )
25442                    }
25443                })
25444                .on_click({
25445                    let editor = editor.clone();
25446                    move |_event, _window, cx| {
25447                        editor.update(cx, |editor, cx| {
25448                            editor.stage_or_unstage_diff_hunks(
25449                                false,
25450                                vec![hunk_range.start..hunk_range.start],
25451                                cx,
25452                            );
25453                        });
25454                    }
25455                })
25456        })
25457        .child(
25458            Button::new(("restore", row as u64), "Restore")
25459                .tooltip({
25460                    let focus_handle = editor.focus_handle(cx);
25461                    move |_window, cx| {
25462                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25463                    }
25464                })
25465                .on_click({
25466                    let editor = editor.clone();
25467                    move |_event, window, cx| {
25468                        editor.update(cx, |editor, cx| {
25469                            let snapshot = editor.snapshot(window, cx);
25470                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25471                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25472                        });
25473                    }
25474                })
25475                .disabled(is_created_file),
25476        )
25477        .when(
25478            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25479            |el| {
25480                el.child(
25481                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25482                        .shape(IconButtonShape::Square)
25483                        .icon_size(IconSize::Small)
25484                        // .disabled(!has_multiple_hunks)
25485                        .tooltip({
25486                            let focus_handle = editor.focus_handle(cx);
25487                            move |_window, cx| {
25488                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25489                            }
25490                        })
25491                        .on_click({
25492                            let editor = editor.clone();
25493                            move |_event, window, cx| {
25494                                editor.update(cx, |editor, cx| {
25495                                    let snapshot = editor.snapshot(window, cx);
25496                                    let position =
25497                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25498                                    editor.go_to_hunk_before_or_after_position(
25499                                        &snapshot,
25500                                        position,
25501                                        Direction::Next,
25502                                        window,
25503                                        cx,
25504                                    );
25505                                    editor.expand_selected_diff_hunks(cx);
25506                                });
25507                            }
25508                        }),
25509                )
25510                .child(
25511                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25512                        .shape(IconButtonShape::Square)
25513                        .icon_size(IconSize::Small)
25514                        // .disabled(!has_multiple_hunks)
25515                        .tooltip({
25516                            let focus_handle = editor.focus_handle(cx);
25517                            move |_window, cx| {
25518                                Tooltip::for_action_in(
25519                                    "Previous Hunk",
25520                                    &GoToPreviousHunk,
25521                                    &focus_handle,
25522                                    cx,
25523                                )
25524                            }
25525                        })
25526                        .on_click({
25527                            let editor = editor.clone();
25528                            move |_event, window, cx| {
25529                                editor.update(cx, |editor, cx| {
25530                                    let snapshot = editor.snapshot(window, cx);
25531                                    let point =
25532                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25533                                    editor.go_to_hunk_before_or_after_position(
25534                                        &snapshot,
25535                                        point,
25536                                        Direction::Prev,
25537                                        window,
25538                                        cx,
25539                                    );
25540                                    editor.expand_selected_diff_hunks(cx);
25541                                });
25542                            }
25543                        }),
25544                )
25545            },
25546        )
25547        .into_any_element()
25548}
25549
25550pub fn multibuffer_context_lines(cx: &App) -> u32 {
25551    EditorSettings::try_get(cx)
25552        .map(|settings| settings.excerpt_context_lines)
25553        .unwrap_or(2)
25554        .min(32)
25555}