editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   69    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   70    ToPoint,
   71};
   72pub use text::Bias;
   73
   74use ::git::{
   75    Restore,
   76    blame::{BlameEntry, ParsedCommitMessage},
   77    status::FileStatus,
   78};
   79use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   80use anyhow::{Context as _, Result, anyhow};
   81use blink_manager::BlinkManager;
   82use buffer_diff::DiffHunkStatus;
   83use client::{Collaborator, ParticipantIndex, parse_zed_link};
   84use clock::ReplicaId;
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   90use convert_case::{Case, Casing};
   91use dap::TelemetrySpawnLocation;
   92use display_map::*;
   93use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  109    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle,
  110    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  111    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  112};
  113use hover_links::{HoverLink, HoveredLinkState, find_file};
  114use hover_popover::{HoverState, hide_hover};
  115use indent_guides::ActiveIndentGuidesState;
  116use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  117use itertools::{Either, Itertools};
  118use language::{
  119    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  120    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  121    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  122    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  123    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  124    language_settings::{
  125        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  126        all_language_settings, language_settings,
  127    },
  128    point_from_lsp, point_to_lsp, text_diff_with_options,
  129};
  130use linked_editing_ranges::refresh_linked_ranges;
  131use lsp::{
  132    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  133    LanguageServerId,
  134};
  135use lsp_colors::LspColorData;
  136use markdown::Markdown;
  137use mouse_context_menu::MouseContextMenu;
  138use movement::TextLayoutDetails;
  139use multi_buffer::{
  140    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  141};
  142use parking_lot::Mutex;
  143use persistence::DB;
  144use project::{
  145    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  146    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  147    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  148    ProjectPath, ProjectTransaction, TaskSourceKind,
  149    debugger::{
  150        breakpoint_store::{
  151            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  152            BreakpointStore, BreakpointStoreEvent,
  153        },
  154        session::{Session, SessionEvent},
  155    },
  156    git_store::GitStoreEvent,
  157    lsp_store::{
  158        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  159        OpenLspBufferHandle,
  160    },
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  167use serde::{Deserialize, Serialize};
  168use settings::{
  169    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  170    update_settings_file,
  171};
  172use smallvec::{SmallVec, smallvec};
  173use snippet::Snippet;
  174use std::{
  175    any::{Any, TypeId},
  176    borrow::Cow,
  177    cell::{OnceCell, RefCell},
  178    cmp::{self, Ordering, Reverse},
  179    collections::hash_map,
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    inlays::{
  214        InlineValueCache,
  215        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  216    },
  217    scroll::{ScrollOffset, ScrollPixelOffset},
  218    selections_collection::resolve_selections_wrapping_blocks,
  219    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  220};
  221
  222pub const FILE_HEADER_HEIGHT: u32 = 2;
  223pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  224const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  225const MAX_LINE_LEN: usize = 1024;
  226const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  227const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  228pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  229#[doc(hidden)]
  230pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  231pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  232
  233pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  236pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  237
  238pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  239pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  240pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  241
  242pub type RenderDiffHunkControlsFn = Arc<
  243    dyn Fn(
  244        u32,
  245        &DiffHunkStatus,
  246        Range<Anchor>,
  247        bool,
  248        Pixels,
  249        &Entity<Editor>,
  250        &mut Window,
  251        &mut App,
  252    ) -> AnyElement,
  253>;
  254
  255enum ReportEditorEvent {
  256    Saved { auto_saved: bool },
  257    EditorOpened,
  258    Closed,
  259}
  260
  261impl ReportEditorEvent {
  262    pub fn event_type(&self) -> &'static str {
  263        match self {
  264            Self::Saved { .. } => "Editor Saved",
  265            Self::EditorOpened => "Editor Opened",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271pub enum ActiveDebugLine {}
  272pub enum DebugStackFrameLine {}
  273enum DocumentHighlightRead {}
  274enum DocumentHighlightWrite {}
  275enum InputComposition {}
  276pub enum PendingInput {}
  277enum SelectedTextHighlight {}
  278
  279pub enum ConflictsOuter {}
  280pub enum ConflictsOurs {}
  281pub enum ConflictsTheirs {}
  282pub enum ConflictsOursMarker {}
  283pub enum ConflictsTheirsMarker {}
  284
  285#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  286pub enum Navigated {
  287    Yes,
  288    No,
  289}
  290
  291impl Navigated {
  292    pub fn from_bool(yes: bool) -> Navigated {
  293        if yes { Navigated::Yes } else { Navigated::No }
  294    }
  295}
  296
  297#[derive(Debug, Clone, PartialEq, Eq)]
  298enum DisplayDiffHunk {
  299    Folded {
  300        display_row: DisplayRow,
  301    },
  302    Unfolded {
  303        is_created_file: bool,
  304        diff_base_byte_range: Range<usize>,
  305        display_row_range: Range<DisplayRow>,
  306        multi_buffer_range: Range<Anchor>,
  307        status: DiffHunkStatus,
  308    },
  309}
  310
  311pub enum HideMouseCursorOrigin {
  312    TypingAction,
  313    MovementAction,
  314}
  315
  316pub fn init(cx: &mut App) {
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        language_registry: Option<Arc<LanguageRegistry>>,
  378        cx: &mut App,
  379    ) -> Vec<BlockProperties<Anchor>>;
  380
  381    fn render_hover(
  382        &self,
  383        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  384        range: Range<Point>,
  385        buffer_id: BufferId,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Option<Entity<markdown::Markdown>>;
  389
  390    fn open_link(
  391        &self,
  392        editor: &mut Editor,
  393        link: SharedString,
  394        window: &mut Window,
  395        cx: &mut Context<Editor>,
  396    );
  397}
  398
  399pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  400
  401impl GlobalDiagnosticRenderer {
  402    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  403        cx.try_global::<Self>().map(|g| g.0.clone())
  404    }
  405}
  406
  407impl gpui::Global for GlobalDiagnosticRenderer {}
  408pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  409    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  410}
  411
  412pub struct SearchWithinRange;
  413
  414trait InvalidationRegion {
  415    fn ranges(&self) -> &[Range<Anchor>];
  416}
  417
  418#[derive(Clone, Debug, PartialEq)]
  419pub enum SelectPhase {
  420    Begin {
  421        position: DisplayPoint,
  422        add: bool,
  423        click_count: usize,
  424    },
  425    BeginColumnar {
  426        position: DisplayPoint,
  427        reset: bool,
  428        mode: ColumnarMode,
  429        goal_column: u32,
  430    },
  431    Extend {
  432        position: DisplayPoint,
  433        click_count: usize,
  434    },
  435    Update {
  436        position: DisplayPoint,
  437        goal_column: u32,
  438        scroll_delta: gpui::Point<f32>,
  439    },
  440    End,
  441}
  442
  443#[derive(Clone, Debug, PartialEq)]
  444pub enum ColumnarMode {
  445    FromMouse,
  446    FromSelection,
  447}
  448
  449#[derive(Clone, Debug)]
  450pub enum SelectMode {
  451    Character,
  452    Word(Range<Anchor>),
  453    Line(Range<Anchor>),
  454    All,
  455}
  456
  457#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  458pub enum SizingBehavior {
  459    /// The editor will layout itself using `size_full` and will include the vertical
  460    /// scroll margin as requested by user settings.
  461    #[default]
  462    Default,
  463    /// The editor will layout itself using `size_full`, but will not have any
  464    /// vertical overscroll.
  465    ExcludeOverscrollMargin,
  466    /// The editor will request a vertical size according to its content and will be
  467    /// layouted without a vertical scroll margin.
  468    SizeByContent,
  469}
  470
  471#[derive(Clone, PartialEq, Eq, Debug)]
  472pub enum EditorMode {
  473    SingleLine,
  474    AutoHeight {
  475        min_lines: usize,
  476        max_lines: Option<usize>,
  477    },
  478    Full {
  479        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  480        scale_ui_elements_with_buffer_font_size: bool,
  481        /// When set to `true`, the editor will render a background for the active line.
  482        show_active_line_background: bool,
  483        /// Determines the sizing behavior for this editor
  484        sizing_behavior: SizingBehavior,
  485    },
  486    Minimap {
  487        parent: WeakEntity<Editor>,
  488    },
  489}
  490
  491impl EditorMode {
  492    pub fn full() -> Self {
  493        Self::Full {
  494            scale_ui_elements_with_buffer_font_size: true,
  495            show_active_line_background: true,
  496            sizing_behavior: SizingBehavior::Default,
  497        }
  498    }
  499
  500    #[inline]
  501    pub fn is_full(&self) -> bool {
  502        matches!(self, Self::Full { .. })
  503    }
  504
  505    #[inline]
  506    pub fn is_single_line(&self) -> bool {
  507        matches!(self, Self::SingleLine { .. })
  508    }
  509
  510    #[inline]
  511    fn is_minimap(&self) -> bool {
  512        matches!(self, Self::Minimap { .. })
  513    }
  514}
  515
  516#[derive(Copy, Clone, Debug)]
  517pub enum SoftWrap {
  518    /// Prefer not to wrap at all.
  519    ///
  520    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  521    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  522    GitDiff,
  523    /// Prefer a single line generally, unless an overly long line is encountered.
  524    None,
  525    /// Soft wrap lines that exceed the editor width.
  526    EditorWidth,
  527    /// Soft wrap lines at the preferred line length.
  528    Column(u32),
  529    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  530    Bounded(u32),
  531}
  532
  533#[derive(Clone)]
  534pub struct EditorStyle {
  535    pub background: Hsla,
  536    pub border: Hsla,
  537    pub local_player: PlayerColor,
  538    pub text: TextStyle,
  539    pub scrollbar_width: Pixels,
  540    pub syntax: Arc<SyntaxTheme>,
  541    pub status: StatusColors,
  542    pub inlay_hints_style: HighlightStyle,
  543    pub edit_prediction_styles: EditPredictionStyles,
  544    pub unnecessary_code_fade: f32,
  545    pub show_underlines: bool,
  546}
  547
  548impl Default for EditorStyle {
  549    fn default() -> Self {
  550        Self {
  551            background: Hsla::default(),
  552            border: Hsla::default(),
  553            local_player: PlayerColor::default(),
  554            text: TextStyle::default(),
  555            scrollbar_width: Pixels::default(),
  556            syntax: Default::default(),
  557            // HACK: Status colors don't have a real default.
  558            // We should look into removing the status colors from the editor
  559            // style and retrieve them directly from the theme.
  560            status: StatusColors::dark(),
  561            inlay_hints_style: HighlightStyle::default(),
  562            edit_prediction_styles: EditPredictionStyles {
  563                insertion: HighlightStyle::default(),
  564                whitespace: HighlightStyle::default(),
  565            },
  566            unnecessary_code_fade: Default::default(),
  567            show_underlines: true,
  568        }
  569    }
  570}
  571
  572pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  573    let show_background = language_settings::language_settings(None, None, cx)
  574        .inlay_hints
  575        .show_background;
  576
  577    let mut style = cx.theme().syntax().get("hint");
  578
  579    if style.color.is_none() {
  580        style.color = Some(cx.theme().status().hint);
  581    }
  582
  583    if !show_background {
  584        style.background_color = None;
  585        return style;
  586    }
  587
  588    if style.background_color.is_none() {
  589        style.background_color = Some(cx.theme().status().hint_background);
  590    }
  591
  592    style
  593}
  594
  595pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  596    EditPredictionStyles {
  597        insertion: HighlightStyle {
  598            color: Some(cx.theme().status().predictive),
  599            ..HighlightStyle::default()
  600        },
  601        whitespace: HighlightStyle {
  602            background_color: Some(cx.theme().status().created_background),
  603            ..HighlightStyle::default()
  604        },
  605    }
  606}
  607
  608type CompletionId = usize;
  609
  610pub(crate) enum EditDisplayMode {
  611    TabAccept,
  612    DiffPopover,
  613    Inline,
  614}
  615
  616enum EditPrediction {
  617    Edit {
  618        edits: Vec<(Range<Anchor>, Arc<str>)>,
  619        edit_preview: Option<EditPreview>,
  620        display_mode: EditDisplayMode,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in the active editor
  624    MoveWithin {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628    /// Move to a specific location in a different editor (not the active one)
  629    MoveOutside {
  630        target: language::Anchor,
  631        snapshot: BufferSnapshot,
  632    },
  633}
  634
  635struct EditPredictionState {
  636    inlay_ids: Vec<InlayId>,
  637    completion: EditPrediction,
  638    completion_id: Option<SharedString>,
  639    invalidation_range: Option<Range<Anchor>>,
  640}
  641
  642enum EditPredictionSettings {
  643    Disabled,
  644    Enabled {
  645        show_in_menu: bool,
  646        preview_requires_modifier: bool,
  647    },
  648}
  649
  650enum EditPredictionHighlight {}
  651
  652#[derive(Debug, Clone)]
  653struct InlineDiagnostic {
  654    message: SharedString,
  655    group_id: usize,
  656    is_primary: bool,
  657    start: Point,
  658    severity: lsp::DiagnosticSeverity,
  659}
  660
  661pub enum MenuEditPredictionsPolicy {
  662    Never,
  663    ByProvider,
  664}
  665
  666pub enum EditPredictionPreview {
  667    /// Modifier is not pressed
  668    Inactive { released_too_fast: bool },
  669    /// Modifier pressed
  670    Active {
  671        since: Instant,
  672        previous_scroll_position: Option<ScrollAnchor>,
  673    },
  674}
  675
  676impl EditPredictionPreview {
  677    pub fn released_too_fast(&self) -> bool {
  678        match self {
  679            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  680            EditPredictionPreview::Active { .. } => false,
  681        }
  682    }
  683
  684    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  685        if let EditPredictionPreview::Active {
  686            previous_scroll_position,
  687            ..
  688        } = self
  689        {
  690            *previous_scroll_position = scroll_position;
  691        }
  692    }
  693}
  694
  695pub struct ContextMenuOptions {
  696    pub min_entries_visible: usize,
  697    pub max_entries_visible: usize,
  698    pub placement: Option<ContextMenuPlacement>,
  699}
  700
  701#[derive(Debug, Clone, PartialEq, Eq)]
  702pub enum ContextMenuPlacement {
  703    Above,
  704    Below,
  705}
  706
  707#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  708struct EditorActionId(usize);
  709
  710impl EditorActionId {
  711    pub fn post_inc(&mut self) -> Self {
  712        let answer = self.0;
  713
  714        *self = Self(answer + 1);
  715
  716        Self(answer)
  717    }
  718}
  719
  720// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  721// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  722
  723type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  724type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  725
  726#[derive(Default)]
  727struct ScrollbarMarkerState {
  728    scrollbar_size: Size<Pixels>,
  729    dirty: bool,
  730    markers: Arc<[PaintQuad]>,
  731    pending_refresh: Option<Task<Result<()>>>,
  732}
  733
  734impl ScrollbarMarkerState {
  735    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  736        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  737    }
  738}
  739
  740#[derive(Clone, Copy, PartialEq, Eq)]
  741pub enum MinimapVisibility {
  742    Disabled,
  743    Enabled {
  744        /// The configuration currently present in the users settings.
  745        setting_configuration: bool,
  746        /// Whether to override the currently set visibility from the users setting.
  747        toggle_override: bool,
  748    },
  749}
  750
  751impl MinimapVisibility {
  752    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  753        if mode.is_full() {
  754            Self::Enabled {
  755                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  756                toggle_override: false,
  757            }
  758        } else {
  759            Self::Disabled
  760        }
  761    }
  762
  763    fn hidden(&self) -> Self {
  764        match *self {
  765            Self::Enabled {
  766                setting_configuration,
  767                ..
  768            } => Self::Enabled {
  769                setting_configuration,
  770                toggle_override: setting_configuration,
  771            },
  772            Self::Disabled => Self::Disabled,
  773        }
  774    }
  775
  776    fn disabled(&self) -> bool {
  777        matches!(*self, Self::Disabled)
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  815pub enum BufferSerialization {
  816    All,
  817    NonDirtyBuffers,
  818}
  819
  820impl BufferSerialization {
  821    fn new(restore_unsaved_buffers: bool) -> Self {
  822        if restore_unsaved_buffers {
  823            Self::All
  824        } else {
  825            Self::NonDirtyBuffers
  826        }
  827    }
  828}
  829
  830#[derive(Clone, Debug)]
  831struct RunnableTasks {
  832    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  833    offset: multi_buffer::Anchor,
  834    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  835    column: u32,
  836    // Values of all named captures, including those starting with '_'
  837    extra_variables: HashMap<String, String>,
  838    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  839    context_range: Range<BufferOffset>,
  840}
  841
  842impl RunnableTasks {
  843    fn resolve<'a>(
  844        &'a self,
  845        cx: &'a task::TaskContext,
  846    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  847        self.templates.iter().filter_map(|(kind, template)| {
  848            template
  849                .resolve_task(&kind.to_id_base(), cx)
  850                .map(|task| (kind.clone(), task))
  851        })
  852    }
  853}
  854
  855#[derive(Clone)]
  856pub struct ResolvedTasks {
  857    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  858    position: Anchor,
  859}
  860
  861/// Addons allow storing per-editor state in other crates (e.g. Vim)
  862pub trait Addon: 'static {
  863    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  864
  865    fn render_buffer_header_controls(
  866        &self,
  867        _: &ExcerptInfo,
  868        _: &Window,
  869        _: &App,
  870    ) -> Option<AnyElement> {
  871        None
  872    }
  873
  874    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    pub collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    next_inlay_id: usize,
 1126    next_color_inlay_id: usize,
 1127    _subscriptions: Vec<Subscription>,
 1128    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1129    gutter_dimensions: GutterDimensions,
 1130    style: Option<EditorStyle>,
 1131    text_style_refinement: Option<TextStyleRefinement>,
 1132    next_editor_action_id: EditorActionId,
 1133    editor_actions: Rc<
 1134        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1135    >,
 1136    use_autoclose: bool,
 1137    use_auto_surround: bool,
 1138    auto_replace_emoji_shortcode: bool,
 1139    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1140    show_git_blame_gutter: bool,
 1141    show_git_blame_inline: bool,
 1142    show_git_blame_inline_delay_task: Option<Task<()>>,
 1143    git_blame_inline_enabled: bool,
 1144    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1145    buffer_serialization: Option<BufferSerialization>,
 1146    show_selection_menu: Option<bool>,
 1147    blame: Option<Entity<GitBlame>>,
 1148    blame_subscription: Option<Subscription>,
 1149    custom_context_menu: Option<
 1150        Box<
 1151            dyn 'static
 1152                + Fn(
 1153                    &mut Self,
 1154                    DisplayPoint,
 1155                    &mut Window,
 1156                    &mut Context<Self>,
 1157                ) -> Option<Entity<ui::ContextMenu>>,
 1158        >,
 1159    >,
 1160    last_bounds: Option<Bounds<Pixels>>,
 1161    last_position_map: Option<Rc<PositionMap>>,
 1162    expect_bounds_change: Option<Bounds<Pixels>>,
 1163    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1164    tasks_update_task: Option<Task<()>>,
 1165    breakpoint_store: Option<Entity<BreakpointStore>>,
 1166    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1167    hovered_diff_hunk_row: Option<DisplayRow>,
 1168    pull_diagnostics_task: Task<()>,
 1169    in_project_search: bool,
 1170    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1171    breadcrumb_header: Option<String>,
 1172    focused_block: Option<FocusedBlock>,
 1173    next_scroll_position: NextScrollCursorCenterTopBottom,
 1174    addons: HashMap<TypeId, Box<dyn Addon>>,
 1175    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1176    load_diff_task: Option<Shared<Task<()>>>,
 1177    /// Whether we are temporarily displaying a diff other than git's
 1178    temporary_diff_override: bool,
 1179    selection_mark_mode: bool,
 1180    toggle_fold_multiple_buffers: Task<()>,
 1181    _scroll_cursor_center_top_bottom_task: Task<()>,
 1182    serialize_selections: Task<()>,
 1183    serialize_folds: Task<()>,
 1184    mouse_cursor_hidden: bool,
 1185    minimap: Option<Entity<Self>>,
 1186    hide_mouse_mode: HideMouseMode,
 1187    pub change_list: ChangeList,
 1188    inline_value_cache: InlineValueCache,
 1189
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    inlay_hints: Option<LspInlayHintData>,
 1195    folding_newlines: Task<()>,
 1196    select_next_is_case_sensitive: Option<bool>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1199    accent_overrides: Vec<SharedString>,
 1200    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1201}
 1202
 1203fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1204    if debounce_ms > 0 {
 1205        Some(Duration::from_millis(debounce_ms))
 1206    } else {
 1207        None
 1208    }
 1209}
 1210
 1211#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1212enum NextScrollCursorCenterTopBottom {
 1213    #[default]
 1214    Center,
 1215    Top,
 1216    Bottom,
 1217}
 1218
 1219impl NextScrollCursorCenterTopBottom {
 1220    fn next(&self) -> Self {
 1221        match self {
 1222            Self::Center => Self::Top,
 1223            Self::Top => Self::Bottom,
 1224            Self::Bottom => Self::Center,
 1225        }
 1226    }
 1227}
 1228
 1229#[derive(Clone)]
 1230pub struct EditorSnapshot {
 1231    pub mode: EditorMode,
 1232    show_gutter: bool,
 1233    show_line_numbers: Option<bool>,
 1234    show_git_diff_gutter: Option<bool>,
 1235    show_code_actions: Option<bool>,
 1236    show_runnables: Option<bool>,
 1237    show_breakpoints: Option<bool>,
 1238    git_blame_gutter_max_author_length: Option<usize>,
 1239    pub display_snapshot: DisplaySnapshot,
 1240    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1241    is_focused: bool,
 1242    scroll_anchor: ScrollAnchor,
 1243    ongoing_scroll: OngoingScroll,
 1244    current_line_highlight: CurrentLineHighlight,
 1245    gutter_hovered: bool,
 1246}
 1247
 1248#[derive(Default, Debug, Clone, Copy)]
 1249pub struct GutterDimensions {
 1250    pub left_padding: Pixels,
 1251    pub right_padding: Pixels,
 1252    pub width: Pixels,
 1253    pub margin: Pixels,
 1254    pub git_blame_entries_width: Option<Pixels>,
 1255}
 1256
 1257impl GutterDimensions {
 1258    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1259        Self {
 1260            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1261            ..Default::default()
 1262        }
 1263    }
 1264
 1265    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1266        -cx.text_system().descent(font_id, font_size)
 1267    }
 1268    /// The full width of the space taken up by the gutter.
 1269    pub fn full_width(&self) -> Pixels {
 1270        self.margin + self.width
 1271    }
 1272
 1273    /// The width of the space reserved for the fold indicators,
 1274    /// use alongside 'justify_end' and `gutter_width` to
 1275    /// right align content with the line numbers
 1276    pub fn fold_area_width(&self) -> Pixels {
 1277        self.margin + self.right_padding
 1278    }
 1279}
 1280
 1281struct CharacterDimensions {
 1282    em_width: Pixels,
 1283    em_advance: Pixels,
 1284    line_height: Pixels,
 1285}
 1286
 1287#[derive(Debug)]
 1288pub struct RemoteSelection {
 1289    pub replica_id: ReplicaId,
 1290    pub selection: Selection<Anchor>,
 1291    pub cursor_shape: CursorShape,
 1292    pub collaborator_id: CollaboratorId,
 1293    pub line_mode: bool,
 1294    pub user_name: Option<SharedString>,
 1295    pub color: PlayerColor,
 1296}
 1297
 1298#[derive(Clone, Debug)]
 1299struct SelectionHistoryEntry {
 1300    selections: Arc<[Selection<Anchor>]>,
 1301    select_next_state: Option<SelectNextState>,
 1302    select_prev_state: Option<SelectNextState>,
 1303    add_selections_state: Option<AddSelectionsState>,
 1304}
 1305
 1306#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1307enum SelectionHistoryMode {
 1308    #[default]
 1309    Normal,
 1310    Undoing,
 1311    Redoing,
 1312    Skipping,
 1313}
 1314
 1315#[derive(Clone, PartialEq, Eq, Hash)]
 1316struct HoveredCursor {
 1317    replica_id: ReplicaId,
 1318    selection_id: usize,
 1319}
 1320
 1321#[derive(Debug)]
 1322/// SelectionEffects controls the side-effects of updating the selection.
 1323///
 1324/// The default behaviour does "what you mostly want":
 1325/// - it pushes to the nav history if the cursor moved by >10 lines
 1326/// - it re-triggers completion requests
 1327/// - it scrolls to fit
 1328///
 1329/// You might want to modify these behaviours. For example when doing a "jump"
 1330/// like go to definition, we always want to add to nav history; but when scrolling
 1331/// in vim mode we never do.
 1332///
 1333/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1334/// move.
 1335#[derive(Clone)]
 1336pub struct SelectionEffects {
 1337    nav_history: Option<bool>,
 1338    completions: bool,
 1339    scroll: Option<Autoscroll>,
 1340}
 1341
 1342impl Default for SelectionEffects {
 1343    fn default() -> Self {
 1344        Self {
 1345            nav_history: None,
 1346            completions: true,
 1347            scroll: Some(Autoscroll::fit()),
 1348        }
 1349    }
 1350}
 1351impl SelectionEffects {
 1352    pub fn scroll(scroll: Autoscroll) -> Self {
 1353        Self {
 1354            scroll: Some(scroll),
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn no_scroll() -> Self {
 1360        Self {
 1361            scroll: None,
 1362            ..Default::default()
 1363        }
 1364    }
 1365
 1366    pub fn completions(self, completions: bool) -> Self {
 1367        Self {
 1368            completions,
 1369            ..self
 1370        }
 1371    }
 1372
 1373    pub fn nav_history(self, nav_history: bool) -> Self {
 1374        Self {
 1375            nav_history: Some(nav_history),
 1376            ..self
 1377        }
 1378    }
 1379}
 1380
 1381struct DeferredSelectionEffectsState {
 1382    changed: bool,
 1383    effects: SelectionEffects,
 1384    old_cursor_position: Anchor,
 1385    history_entry: SelectionHistoryEntry,
 1386}
 1387
 1388#[derive(Default)]
 1389struct SelectionHistory {
 1390    #[allow(clippy::type_complexity)]
 1391    selections_by_transaction:
 1392        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1393    mode: SelectionHistoryMode,
 1394    undo_stack: VecDeque<SelectionHistoryEntry>,
 1395    redo_stack: VecDeque<SelectionHistoryEntry>,
 1396}
 1397
 1398impl SelectionHistory {
 1399    #[track_caller]
 1400    fn insert_transaction(
 1401        &mut self,
 1402        transaction_id: TransactionId,
 1403        selections: Arc<[Selection<Anchor>]>,
 1404    ) {
 1405        if selections.is_empty() {
 1406            log::error!(
 1407                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1408                std::panic::Location::caller()
 1409            );
 1410            return;
 1411        }
 1412        self.selections_by_transaction
 1413            .insert(transaction_id, (selections, None));
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction(
 1418        &self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get(&transaction_id)
 1422    }
 1423
 1424    #[allow(clippy::type_complexity)]
 1425    fn transaction_mut(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1429        self.selections_by_transaction.get_mut(&transaction_id)
 1430    }
 1431
 1432    fn push(&mut self, entry: SelectionHistoryEntry) {
 1433        if !entry.selections.is_empty() {
 1434            match self.mode {
 1435                SelectionHistoryMode::Normal => {
 1436                    self.push_undo(entry);
 1437                    self.redo_stack.clear();
 1438                }
 1439                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1440                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1441                SelectionHistoryMode::Skipping => {}
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .undo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.undo_stack.push_back(entry);
 1453            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.undo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458
 1459    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1460        if self
 1461            .redo_stack
 1462            .back()
 1463            .is_none_or(|e| e.selections != entry.selections)
 1464        {
 1465            self.redo_stack.push_back(entry);
 1466            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1467                self.redo_stack.pop_front();
 1468            }
 1469        }
 1470    }
 1471}
 1472
 1473#[derive(Clone, Copy)]
 1474pub struct RowHighlightOptions {
 1475    pub autoscroll: bool,
 1476    pub include_gutter: bool,
 1477}
 1478
 1479impl Default for RowHighlightOptions {
 1480    fn default() -> Self {
 1481        Self {
 1482            autoscroll: Default::default(),
 1483            include_gutter: true,
 1484        }
 1485    }
 1486}
 1487
 1488struct RowHighlight {
 1489    index: usize,
 1490    range: Range<Anchor>,
 1491    color: Hsla,
 1492    options: RowHighlightOptions,
 1493    type_id: TypeId,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsState {
 1498    groups: Vec<AddSelectionsGroup>,
 1499}
 1500
 1501#[derive(Clone, Debug)]
 1502struct AddSelectionsGroup {
 1503    above: bool,
 1504    stack: Vec<usize>,
 1505}
 1506
 1507#[derive(Clone)]
 1508struct SelectNextState {
 1509    query: AhoCorasick,
 1510    wordwise: bool,
 1511    done: bool,
 1512}
 1513
 1514impl std::fmt::Debug for SelectNextState {
 1515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1516        f.debug_struct(std::any::type_name::<Self>())
 1517            .field("wordwise", &self.wordwise)
 1518            .field("done", &self.done)
 1519            .finish()
 1520    }
 1521}
 1522
 1523#[derive(Debug)]
 1524struct AutocloseRegion {
 1525    selection_id: usize,
 1526    range: Range<Anchor>,
 1527    pair: BracketPair,
 1528}
 1529
 1530#[derive(Debug)]
 1531struct SnippetState {
 1532    ranges: Vec<Vec<Range<Anchor>>>,
 1533    active_index: usize,
 1534    choices: Vec<Option<Vec<String>>>,
 1535}
 1536
 1537#[doc(hidden)]
 1538pub struct RenameState {
 1539    pub range: Range<Anchor>,
 1540    pub old_name: Arc<str>,
 1541    pub editor: Entity<Editor>,
 1542    block_id: CustomBlockId,
 1543}
 1544
 1545struct InvalidationStack<T>(Vec<T>);
 1546
 1547struct RegisteredEditPredictionProvider {
 1548    provider: Arc<dyn EditPredictionProviderHandle>,
 1549    _subscription: Subscription,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553pub struct ActiveDiagnosticGroup {
 1554    pub active_range: Range<Anchor>,
 1555    pub active_message: String,
 1556    pub group_id: usize,
 1557    pub blocks: HashSet<CustomBlockId>,
 1558}
 1559
 1560#[derive(Debug, PartialEq, Eq)]
 1561
 1562pub(crate) enum ActiveDiagnostic {
 1563    None,
 1564    All,
 1565    Group(ActiveDiagnosticGroup),
 1566}
 1567
 1568#[derive(Serialize, Deserialize, Clone, Debug)]
 1569pub struct ClipboardSelection {
 1570    /// The number of bytes in this selection.
 1571    pub len: usize,
 1572    /// Whether this was a full-line selection.
 1573    pub is_entire_line: bool,
 1574    /// The indentation of the first line when this content was originally copied.
 1575    pub first_line_indent: u32,
 1576}
 1577
 1578// selections, scroll behavior, was newest selection reversed
 1579type SelectSyntaxNodeHistoryState = (
 1580    Box<[Selection<MultiBufferOffset>]>,
 1581    SelectSyntaxNodeScrollBehavior,
 1582    bool,
 1583);
 1584
 1585#[derive(Default)]
 1586struct SelectSyntaxNodeHistory {
 1587    stack: Vec<SelectSyntaxNodeHistoryState>,
 1588    // disable temporarily to allow changing selections without losing the stack
 1589    pub disable_clearing: bool,
 1590}
 1591
 1592impl SelectSyntaxNodeHistory {
 1593    pub fn try_clear(&mut self) {
 1594        if !self.disable_clearing {
 1595            self.stack.clear();
 1596        }
 1597    }
 1598
 1599    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1600        self.stack.push(selection);
 1601    }
 1602
 1603    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1604        self.stack.pop()
 1605    }
 1606}
 1607
 1608enum SelectSyntaxNodeScrollBehavior {
 1609    CursorTop,
 1610    FitSelection,
 1611    CursorBottom,
 1612}
 1613
 1614#[derive(Debug)]
 1615pub(crate) struct NavigationData {
 1616    cursor_anchor: Anchor,
 1617    cursor_position: Point,
 1618    scroll_anchor: ScrollAnchor,
 1619    scroll_top_row: u32,
 1620}
 1621
 1622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1623pub enum GotoDefinitionKind {
 1624    Symbol,
 1625    Declaration,
 1626    Type,
 1627    Implementation,
 1628}
 1629
 1630pub enum FormatTarget {
 1631    Buffers(HashSet<Entity<Buffer>>),
 1632    Ranges(Vec<Range<MultiBufferPoint>>),
 1633}
 1634
 1635pub(crate) struct FocusedBlock {
 1636    id: BlockId,
 1637    focus_handle: WeakFocusHandle,
 1638}
 1639
 1640#[derive(Clone)]
 1641enum JumpData {
 1642    MultiBufferRow {
 1643        row: MultiBufferRow,
 1644        line_offset_from_top: u32,
 1645    },
 1646    MultiBufferPoint {
 1647        excerpt_id: ExcerptId,
 1648        position: Point,
 1649        anchor: text::Anchor,
 1650        line_offset_from_top: u32,
 1651    },
 1652}
 1653
 1654pub enum MultibufferSelectionMode {
 1655    First,
 1656    All,
 1657}
 1658
 1659#[derive(Clone, Copy, Debug, Default)]
 1660pub struct RewrapOptions {
 1661    pub override_language_settings: bool,
 1662    pub preserve_existing_whitespace: bool,
 1663}
 1664
 1665impl Editor {
 1666    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1667        let buffer = cx.new(|cx| Buffer::local("", cx));
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1670    }
 1671
 1672    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1673        let buffer = cx.new(|cx| Buffer::local("", cx));
 1674        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1675        Self::new(EditorMode::full(), buffer, None, window, cx)
 1676    }
 1677
 1678    pub fn auto_height(
 1679        min_lines: usize,
 1680        max_lines: usize,
 1681        window: &mut Window,
 1682        cx: &mut Context<Self>,
 1683    ) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(
 1687            EditorMode::AutoHeight {
 1688                min_lines,
 1689                max_lines: Some(max_lines),
 1690            },
 1691            buffer,
 1692            None,
 1693            window,
 1694            cx,
 1695        )
 1696    }
 1697
 1698    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1699    /// The editor grows as tall as needed to fit its content.
 1700    pub fn auto_height_unbounded(
 1701        min_lines: usize,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        let buffer = cx.new(|cx| Buffer::local("", cx));
 1706        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1707        Self::new(
 1708            EditorMode::AutoHeight {
 1709                min_lines,
 1710                max_lines: None,
 1711            },
 1712            buffer,
 1713            None,
 1714            window,
 1715            cx,
 1716        )
 1717    }
 1718
 1719    pub fn for_buffer(
 1720        buffer: Entity<Buffer>,
 1721        project: Option<Entity<Project>>,
 1722        window: &mut Window,
 1723        cx: &mut Context<Self>,
 1724    ) -> Self {
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn for_multibuffer(
 1730        buffer: Entity<MultiBuffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        Self::new(EditorMode::full(), buffer, project, window, cx)
 1736    }
 1737
 1738    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let mut clone = Self::new(
 1740            self.mode.clone(),
 1741            self.buffer.clone(),
 1742            self.project.clone(),
 1743            window,
 1744            cx,
 1745        );
 1746        self.display_map.update(cx, |display_map, cx| {
 1747            let snapshot = display_map.snapshot(cx);
 1748            clone.display_map.update(cx, |display_map, cx| {
 1749                display_map.set_state(&snapshot, cx);
 1750            });
 1751        });
 1752        clone.folds_did_change(cx);
 1753        clone.selections.clone_state(&self.selections);
 1754        clone.scroll_manager.clone_state(&self.scroll_manager);
 1755        clone.searchable = self.searchable;
 1756        clone.read_only = self.read_only;
 1757        clone
 1758    }
 1759
 1760    pub fn new(
 1761        mode: EditorMode,
 1762        buffer: Entity<MultiBuffer>,
 1763        project: Option<Entity<Project>>,
 1764        window: &mut Window,
 1765        cx: &mut Context<Self>,
 1766    ) -> Self {
 1767        Editor::new_internal(mode, buffer, project, None, window, cx)
 1768    }
 1769
 1770    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1771        let multi_buffer = self.buffer().read(cx);
 1772        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1773        let multi_buffer_visible_start = self
 1774            .scroll_manager
 1775            .anchor()
 1776            .anchor
 1777            .to_point(&multi_buffer_snapshot);
 1778        let max_row = multi_buffer_snapshot.max_point().row;
 1779
 1780        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1781        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1782
 1783        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1784            let outline_items = buffer
 1785                .outline_items_containing(
 1786                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1787                    true,
 1788                    self.style().map(|style| style.syntax.as_ref()),
 1789                )
 1790                .into_iter()
 1791                .map(|outline_item| OutlineItem {
 1792                    depth: outline_item.depth,
 1793                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1794                    source_range_for_text: Anchor::range_in_buffer(
 1795                        *excerpt_id,
 1796                        outline_item.source_range_for_text,
 1797                    ),
 1798                    text: outline_item.text,
 1799                    highlight_ranges: outline_item.highlight_ranges,
 1800                    name_ranges: outline_item.name_ranges,
 1801                    body_range: outline_item
 1802                        .body_range
 1803                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1804                    annotation_range: outline_item
 1805                        .annotation_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1807                });
 1808            return Some(outline_items.collect());
 1809        }
 1810
 1811        None
 1812    }
 1813
 1814    fn new_internal(
 1815        mode: EditorMode,
 1816        multi_buffer: Entity<MultiBuffer>,
 1817        project: Option<Entity<Project>>,
 1818        display_map: Option<Entity<DisplayMap>>,
 1819        window: &mut Window,
 1820        cx: &mut Context<Self>,
 1821    ) -> Self {
 1822        debug_assert!(
 1823            display_map.is_none() || mode.is_minimap(),
 1824            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1825        );
 1826
 1827        let full_mode = mode.is_full();
 1828        let is_minimap = mode.is_minimap();
 1829        let diagnostics_max_severity = if full_mode {
 1830            EditorSettings::get_global(cx)
 1831                .diagnostics_max_severity
 1832                .unwrap_or(DiagnosticSeverity::Hint)
 1833        } else {
 1834            DiagnosticSeverity::Off
 1835        };
 1836        let style = window.text_style();
 1837        let font_size = style.font_size.to_pixels(window.rem_size());
 1838        let editor = cx.entity().downgrade();
 1839        let fold_placeholder = FoldPlaceholder {
 1840            constrain_width: false,
 1841            render: Arc::new(move |fold_id, fold_range, cx| {
 1842                let editor = editor.clone();
 1843                div()
 1844                    .id(fold_id)
 1845                    .bg(cx.theme().colors().ghost_element_background)
 1846                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1847                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1848                    .rounded_xs()
 1849                    .size_full()
 1850                    .cursor_pointer()
 1851                    .child("")
 1852                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1853                    .on_click(move |_, _window, cx| {
 1854                        editor
 1855                            .update(cx, |editor, cx| {
 1856                                editor.unfold_ranges(
 1857                                    &[fold_range.start..fold_range.end],
 1858                                    true,
 1859                                    false,
 1860                                    cx,
 1861                                );
 1862                                cx.stop_propagation();
 1863                            })
 1864                            .ok();
 1865                    })
 1866                    .into_any()
 1867            }),
 1868            merge_adjacent: true,
 1869            ..FoldPlaceholder::default()
 1870        };
 1871        let display_map = display_map.unwrap_or_else(|| {
 1872            cx.new(|cx| {
 1873                DisplayMap::new(
 1874                    multi_buffer.clone(),
 1875                    style.font(),
 1876                    font_size,
 1877                    None,
 1878                    FILE_HEADER_HEIGHT,
 1879                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1880                    fold_placeholder,
 1881                    diagnostics_max_severity,
 1882                    cx,
 1883                )
 1884            })
 1885        });
 1886
 1887        let selections = SelectionsCollection::new();
 1888
 1889        let blink_manager = cx.new(|cx| {
 1890            let mut blink_manager = BlinkManager::new(
 1891                CURSOR_BLINK_INTERVAL,
 1892                |cx| EditorSettings::get_global(cx).cursor_blink,
 1893                cx,
 1894            );
 1895            if is_minimap {
 1896                blink_manager.disable(cx);
 1897            }
 1898            blink_manager
 1899        });
 1900
 1901        let soft_wrap_mode_override =
 1902            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1903
 1904        let mut project_subscriptions = Vec::new();
 1905        if full_mode && let Some(project) = project.as_ref() {
 1906            project_subscriptions.push(cx.subscribe_in(
 1907                project,
 1908                window,
 1909                |editor, _, event, window, cx| match event {
 1910                    project::Event::RefreshCodeLens => {
 1911                        // we always query lens with actions, without storing them, always refreshing them
 1912                    }
 1913                    project::Event::RefreshInlayHints {
 1914                        server_id,
 1915                        request_id,
 1916                    } => {
 1917                        editor.refresh_inlay_hints(
 1918                            InlayHintRefreshReason::RefreshRequested {
 1919                                server_id: *server_id,
 1920                                request_id: *request_id,
 1921                            },
 1922                            cx,
 1923                        );
 1924                    }
 1925                    project::Event::LanguageServerRemoved(..) => {
 1926                        if editor.tasks_update_task.is_none() {
 1927                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1928                        }
 1929                        editor.registered_buffers.clear();
 1930                        editor.register_visible_buffers(cx);
 1931                    }
 1932                    project::Event::LanguageServerAdded(..) => {
 1933                        if editor.tasks_update_task.is_none() {
 1934                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1935                        }
 1936                    }
 1937                    project::Event::SnippetEdit(id, snippet_edits) => {
 1938                        // todo(lw): Non singletons
 1939                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1940                            let snapshot = buffer.read(cx).snapshot();
 1941                            let focus_handle = editor.focus_handle(cx);
 1942                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1943                                for (range, snippet) in snippet_edits {
 1944                                    let buffer_range =
 1945                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1946                                    editor
 1947                                        .insert_snippet(
 1948                                            &[MultiBufferOffset(buffer_range.start)
 1949                                                ..MultiBufferOffset(buffer_range.end)],
 1950                                            snippet.clone(),
 1951                                            window,
 1952                                            cx,
 1953                                        )
 1954                                        .ok();
 1955                                }
 1956                            }
 1957                        }
 1958                    }
 1959                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1960                        let buffer_id = *buffer_id;
 1961                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1962                            editor.register_buffer(buffer_id, cx);
 1963                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1964                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1965                            refresh_linked_ranges(editor, window, cx);
 1966                            editor.refresh_code_actions(window, cx);
 1967                            editor.refresh_document_highlights(cx);
 1968                        }
 1969                    }
 1970
 1971                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1972                        let Some(workspace) = editor.workspace() else {
 1973                            return;
 1974                        };
 1975                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1976                        else {
 1977                            return;
 1978                        };
 1979
 1980                        if active_editor.entity_id() == cx.entity_id() {
 1981                            let entity_id = cx.entity_id();
 1982                            workspace.update(cx, |this, cx| {
 1983                                this.panes_mut()
 1984                                    .iter_mut()
 1985                                    .filter(|pane| pane.entity_id() != entity_id)
 1986                                    .for_each(|p| {
 1987                                        p.update(cx, |pane, _| {
 1988                                            pane.nav_history_mut().rename_item(
 1989                                                entity_id,
 1990                                                project_path.clone(),
 1991                                                abs_path.clone().into(),
 1992                                            );
 1993                                        })
 1994                                    });
 1995                            });
 1996                            let edited_buffers_already_open = {
 1997                                let other_editors: Vec<Entity<Editor>> = workspace
 1998                                    .read(cx)
 1999                                    .panes()
 2000                                    .iter()
 2001                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2002                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2003                                    .collect();
 2004
 2005                                transaction.0.keys().all(|buffer| {
 2006                                    other_editors.iter().any(|editor| {
 2007                                        let multi_buffer = editor.read(cx).buffer();
 2008                                        multi_buffer.read(cx).is_singleton()
 2009                                            && multi_buffer.read(cx).as_singleton().map_or(
 2010                                                false,
 2011                                                |singleton| {
 2012                                                    singleton.entity_id() == buffer.entity_id()
 2013                                                },
 2014                                            )
 2015                                    })
 2016                                })
 2017                            };
 2018                            if !edited_buffers_already_open {
 2019                                let workspace = workspace.downgrade();
 2020                                let transaction = transaction.clone();
 2021                                cx.defer_in(window, move |_, window, cx| {
 2022                                    cx.spawn_in(window, async move |editor, cx| {
 2023                                        Self::open_project_transaction(
 2024                                            &editor,
 2025                                            workspace,
 2026                                            transaction,
 2027                                            "Rename".to_string(),
 2028                                            cx,
 2029                                        )
 2030                                        .await
 2031                                        .ok()
 2032                                    })
 2033                                    .detach();
 2034                                });
 2035                            }
 2036                        }
 2037                    }
 2038
 2039                    _ => {}
 2040                },
 2041            ));
 2042            if let Some(task_inventory) = project
 2043                .read(cx)
 2044                .task_store()
 2045                .read(cx)
 2046                .task_inventory()
 2047                .cloned()
 2048            {
 2049                project_subscriptions.push(cx.observe_in(
 2050                    &task_inventory,
 2051                    window,
 2052                    |editor, _, window, cx| {
 2053                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2054                    },
 2055                ));
 2056            };
 2057
 2058            project_subscriptions.push(cx.subscribe_in(
 2059                &project.read(cx).breakpoint_store(),
 2060                window,
 2061                |editor, _, event, window, cx| match event {
 2062                    BreakpointStoreEvent::ClearDebugLines => {
 2063                        editor.clear_row_highlights::<ActiveDebugLine>();
 2064                        editor.refresh_inline_values(cx);
 2065                    }
 2066                    BreakpointStoreEvent::SetDebugLine => {
 2067                        if editor.go_to_active_debug_line(window, cx) {
 2068                            cx.stop_propagation();
 2069                        }
 2070
 2071                        editor.refresh_inline_values(cx);
 2072                    }
 2073                    _ => {}
 2074                },
 2075            ));
 2076            let git_store = project.read(cx).git_store().clone();
 2077            let project = project.clone();
 2078            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2079                if let GitStoreEvent::RepositoryAdded = event {
 2080                    this.load_diff_task = Some(
 2081                        update_uncommitted_diff_for_buffer(
 2082                            cx.entity(),
 2083                            &project,
 2084                            this.buffer.read(cx).all_buffers(),
 2085                            this.buffer.clone(),
 2086                            cx,
 2087                        )
 2088                        .shared(),
 2089                    );
 2090                }
 2091            }));
 2092        }
 2093
 2094        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2095
 2096        let inlay_hint_settings =
 2097            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2098        let focus_handle = cx.focus_handle();
 2099        if !is_minimap {
 2100            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2101                .detach();
 2102            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2103                .detach();
 2104            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2105                .detach();
 2106            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2107                .detach();
 2108            cx.observe_pending_input(window, Self::observe_pending_input)
 2109                .detach();
 2110        }
 2111
 2112        let show_indent_guides =
 2113            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2114                Some(false)
 2115            } else {
 2116                None
 2117            };
 2118
 2119        let breakpoint_store = match (&mode, project.as_ref()) {
 2120            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2121            _ => None,
 2122        };
 2123
 2124        let mut code_action_providers = Vec::new();
 2125        let mut load_uncommitted_diff = None;
 2126        if let Some(project) = project.clone() {
 2127            load_uncommitted_diff = Some(
 2128                update_uncommitted_diff_for_buffer(
 2129                    cx.entity(),
 2130                    &project,
 2131                    multi_buffer.read(cx).all_buffers(),
 2132                    multi_buffer.clone(),
 2133                    cx,
 2134                )
 2135                .shared(),
 2136            );
 2137            code_action_providers.push(Rc::new(project) as Rc<_>);
 2138        }
 2139
 2140        let mut editor = Self {
 2141            focus_handle,
 2142            show_cursor_when_unfocused: false,
 2143            last_focused_descendant: None,
 2144            buffer: multi_buffer.clone(),
 2145            display_map: display_map.clone(),
 2146            placeholder_display_map: None,
 2147            selections,
 2148            scroll_manager: ScrollManager::new(cx),
 2149            columnar_selection_state: None,
 2150            add_selections_state: None,
 2151            select_next_state: None,
 2152            select_prev_state: None,
 2153            selection_history: SelectionHistory::default(),
 2154            defer_selection_effects: false,
 2155            deferred_selection_effects_state: None,
 2156            autoclose_regions: Vec::new(),
 2157            snippet_stack: InvalidationStack::default(),
 2158            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2159            ime_transaction: None,
 2160            active_diagnostics: ActiveDiagnostic::None,
 2161            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2162            inline_diagnostics_update: Task::ready(()),
 2163            inline_diagnostics: Vec::new(),
 2164            soft_wrap_mode_override,
 2165            diagnostics_max_severity,
 2166            hard_wrap: None,
 2167            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2168            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2169            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2170            project,
 2171            blink_manager: blink_manager.clone(),
 2172            show_local_selections: true,
 2173            show_scrollbars: ScrollbarAxes {
 2174                horizontal: full_mode,
 2175                vertical: full_mode,
 2176            },
 2177            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2178            offset_content: !matches!(mode, EditorMode::SingleLine),
 2179            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2180            show_gutter: full_mode,
 2181            show_line_numbers: (!full_mode).then_some(false),
 2182            use_relative_line_numbers: None,
 2183            disable_expand_excerpt_buttons: !full_mode,
 2184            show_git_diff_gutter: None,
 2185            show_code_actions: None,
 2186            show_runnables: None,
 2187            show_breakpoints: None,
 2188            show_wrap_guides: None,
 2189            show_indent_guides,
 2190            highlight_order: 0,
 2191            highlighted_rows: HashMap::default(),
 2192            background_highlights: HashMap::default(),
 2193            gutter_highlights: HashMap::default(),
 2194            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2195            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2196            nav_history: None,
 2197            context_menu: RefCell::new(None),
 2198            context_menu_options: None,
 2199            mouse_context_menu: None,
 2200            completion_tasks: Vec::new(),
 2201            inline_blame_popover: None,
 2202            inline_blame_popover_show_task: None,
 2203            signature_help_state: SignatureHelpState::default(),
 2204            auto_signature_help: None,
 2205            find_all_references_task_sources: Vec::new(),
 2206            next_completion_id: 0,
 2207            next_inlay_id: 0,
 2208            code_action_providers,
 2209            available_code_actions: None,
 2210            code_actions_task: None,
 2211            quick_selection_highlight_task: None,
 2212            debounced_selection_highlight_task: None,
 2213            document_highlights_task: None,
 2214            linked_editing_range_task: None,
 2215            pending_rename: None,
 2216            searchable: !is_minimap,
 2217            cursor_shape: EditorSettings::get_global(cx)
 2218                .cursor_shape
 2219                .unwrap_or_default(),
 2220            current_line_highlight: None,
 2221            autoindent_mode: Some(AutoindentMode::EachLine),
 2222            collapse_matches: false,
 2223            workspace: None,
 2224            input_enabled: !is_minimap,
 2225            use_modal_editing: full_mode,
 2226            read_only: is_minimap,
 2227            use_autoclose: true,
 2228            use_auto_surround: true,
 2229            auto_replace_emoji_shortcode: false,
 2230            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2231            leader_id: None,
 2232            remote_id: None,
 2233            hover_state: HoverState::default(),
 2234            pending_mouse_down: None,
 2235            hovered_link_state: None,
 2236            edit_prediction_provider: None,
 2237            active_edit_prediction: None,
 2238            stale_edit_prediction_in_menu: None,
 2239            edit_prediction_preview: EditPredictionPreview::Inactive {
 2240                released_too_fast: false,
 2241            },
 2242            inline_diagnostics_enabled: full_mode,
 2243            diagnostics_enabled: full_mode,
 2244            word_completions_enabled: full_mode,
 2245            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2246            gutter_hovered: false,
 2247            pixel_position_of_newest_cursor: None,
 2248            last_bounds: None,
 2249            last_position_map: None,
 2250            expect_bounds_change: None,
 2251            gutter_dimensions: GutterDimensions::default(),
 2252            style: None,
 2253            show_cursor_names: false,
 2254            hovered_cursors: HashMap::default(),
 2255            next_editor_action_id: EditorActionId::default(),
 2256            editor_actions: Rc::default(),
 2257            edit_predictions_hidden_for_vim_mode: false,
 2258            show_edit_predictions_override: None,
 2259            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2260            edit_prediction_settings: EditPredictionSettings::Disabled,
 2261            edit_prediction_indent_conflict: false,
 2262            edit_prediction_requires_modifier_in_indent_conflict: true,
 2263            custom_context_menu: None,
 2264            show_git_blame_gutter: false,
 2265            show_git_blame_inline: false,
 2266            show_selection_menu: None,
 2267            show_git_blame_inline_delay_task: None,
 2268            git_blame_inline_enabled: full_mode
 2269                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2270            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2271            buffer_serialization: is_minimap.not().then(|| {
 2272                BufferSerialization::new(
 2273                    ProjectSettings::get_global(cx)
 2274                        .session
 2275                        .restore_unsaved_buffers,
 2276                )
 2277            }),
 2278            blame: None,
 2279            blame_subscription: None,
 2280            tasks: BTreeMap::default(),
 2281
 2282            breakpoint_store,
 2283            gutter_breakpoint_indicator: (None, None),
 2284            hovered_diff_hunk_row: None,
 2285            _subscriptions: (!is_minimap)
 2286                .then(|| {
 2287                    vec![
 2288                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2289                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2290                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2291                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2292                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2293                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2294                        cx.observe_window_activation(window, |editor, window, cx| {
 2295                            let active = window.is_window_active();
 2296                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2297                                if active {
 2298                                    blink_manager.enable(cx);
 2299                                } else {
 2300                                    blink_manager.disable(cx);
 2301                                }
 2302                            });
 2303                            if active {
 2304                                editor.show_mouse_cursor(cx);
 2305                            }
 2306                        }),
 2307                    ]
 2308                })
 2309                .unwrap_or_default(),
 2310            tasks_update_task: None,
 2311            pull_diagnostics_task: Task::ready(()),
 2312            colors: None,
 2313            refresh_colors_task: Task::ready(()),
 2314            inlay_hints: None,
 2315            next_color_inlay_id: 0,
 2316            post_scroll_update: Task::ready(()),
 2317            linked_edit_ranges: Default::default(),
 2318            in_project_search: false,
 2319            previous_search_ranges: None,
 2320            breadcrumb_header: None,
 2321            focused_block: None,
 2322            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2323            addons: HashMap::default(),
 2324            registered_buffers: HashMap::default(),
 2325            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2326            selection_mark_mode: false,
 2327            toggle_fold_multiple_buffers: Task::ready(()),
 2328            serialize_selections: Task::ready(()),
 2329            serialize_folds: Task::ready(()),
 2330            text_style_refinement: None,
 2331            load_diff_task: load_uncommitted_diff,
 2332            temporary_diff_override: false,
 2333            mouse_cursor_hidden: false,
 2334            minimap: None,
 2335            hide_mouse_mode: EditorSettings::get_global(cx)
 2336                .hide_mouse
 2337                .unwrap_or_default(),
 2338            change_list: ChangeList::new(),
 2339            mode,
 2340            selection_drag_state: SelectionDragState::None,
 2341            folding_newlines: Task::ready(()),
 2342            lookup_key: None,
 2343            select_next_is_case_sensitive: None,
 2344            applicable_language_settings: HashMap::default(),
 2345            accent_overrides: Vec::new(),
 2346            fetched_tree_sitter_chunks: HashMap::default(),
 2347        };
 2348
 2349        if is_minimap {
 2350            return editor;
 2351        }
 2352
 2353        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2354        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2355
 2356        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2357            editor
 2358                ._subscriptions
 2359                .push(cx.observe(breakpoints, |_, _, cx| {
 2360                    cx.notify();
 2361                }));
 2362        }
 2363        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2364        editor._subscriptions.extend(project_subscriptions);
 2365
 2366        editor._subscriptions.push(cx.subscribe_in(
 2367            &cx.entity(),
 2368            window,
 2369            |editor, _, e: &EditorEvent, window, cx| match e {
 2370                EditorEvent::ScrollPositionChanged { local, .. } => {
 2371                    if *local {
 2372                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2373                        editor.inline_blame_popover.take();
 2374                        let new_anchor = editor.scroll_manager.anchor();
 2375                        let snapshot = editor.snapshot(window, cx);
 2376                        editor.update_restoration_data(cx, move |data| {
 2377                            data.scroll_position = (
 2378                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2379                                new_anchor.offset,
 2380                            );
 2381                        });
 2382
 2383                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2384                            cx.background_executor()
 2385                                .timer(Duration::from_millis(50))
 2386                                .await;
 2387                            editor
 2388                                .update_in(cx, |editor, window, cx| {
 2389                                    editor.register_visible_buffers(cx);
 2390                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2391                                    editor.refresh_inlay_hints(
 2392                                        InlayHintRefreshReason::NewLinesShown,
 2393                                        cx,
 2394                                    );
 2395                                    editor.colorize_brackets(false, cx);
 2396                                })
 2397                                .ok();
 2398                        });
 2399                    }
 2400                }
 2401                EditorEvent::Edited { .. } => {
 2402                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2403                        .map(|vim_mode| vim_mode.0)
 2404                        .unwrap_or(false);
 2405                    if !vim_mode {
 2406                        let display_map = editor.display_snapshot(cx);
 2407                        let selections = editor.selections.all_adjusted_display(&display_map);
 2408                        let pop_state = editor
 2409                            .change_list
 2410                            .last()
 2411                            .map(|previous| {
 2412                                previous.len() == selections.len()
 2413                                    && previous.iter().enumerate().all(|(ix, p)| {
 2414                                        p.to_display_point(&display_map).row()
 2415                                            == selections[ix].head().row()
 2416                                    })
 2417                            })
 2418                            .unwrap_or(false);
 2419                        let new_positions = selections
 2420                            .into_iter()
 2421                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2422                            .collect();
 2423                        editor
 2424                            .change_list
 2425                            .push_to_change_list(pop_state, new_positions);
 2426                    }
 2427                }
 2428                _ => (),
 2429            },
 2430        ));
 2431
 2432        if let Some(dap_store) = editor
 2433            .project
 2434            .as_ref()
 2435            .map(|project| project.read(cx).dap_store())
 2436        {
 2437            let weak_editor = cx.weak_entity();
 2438
 2439            editor
 2440                ._subscriptions
 2441                .push(
 2442                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2443                        let session_entity = cx.entity();
 2444                        weak_editor
 2445                            .update(cx, |editor, cx| {
 2446                                editor._subscriptions.push(
 2447                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2448                                );
 2449                            })
 2450                            .ok();
 2451                    }),
 2452                );
 2453
 2454            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2455                editor
 2456                    ._subscriptions
 2457                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2458            }
 2459        }
 2460
 2461        // skip adding the initial selection to selection history
 2462        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2463        editor.end_selection(window, cx);
 2464        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2465
 2466        editor.scroll_manager.show_scrollbars(window, cx);
 2467        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2468
 2469        if full_mode {
 2470            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2471            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2472
 2473            if editor.git_blame_inline_enabled {
 2474                editor.start_git_blame_inline(false, window, cx);
 2475            }
 2476
 2477            editor.go_to_active_debug_line(window, cx);
 2478
 2479            editor.minimap =
 2480                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2481            editor.colors = Some(LspColorData::new(cx));
 2482            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2483
 2484            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2485                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2486            }
 2487            editor.update_lsp_data(None, window, cx);
 2488            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2489        }
 2490
 2491        editor
 2492    }
 2493
 2494    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2495        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2496    }
 2497
 2498    pub fn deploy_mouse_context_menu(
 2499        &mut self,
 2500        position: gpui::Point<Pixels>,
 2501        context_menu: Entity<ContextMenu>,
 2502        window: &mut Window,
 2503        cx: &mut Context<Self>,
 2504    ) {
 2505        self.mouse_context_menu = Some(MouseContextMenu::new(
 2506            self,
 2507            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2508            context_menu,
 2509            window,
 2510            cx,
 2511        ));
 2512    }
 2513
 2514    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2515        self.mouse_context_menu
 2516            .as_ref()
 2517            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2518    }
 2519
 2520    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2521        if self
 2522            .selections
 2523            .pending_anchor()
 2524            .is_some_and(|pending_selection| {
 2525                let snapshot = self.buffer().read(cx).snapshot(cx);
 2526                pending_selection.range().includes(range, &snapshot)
 2527            })
 2528        {
 2529            return true;
 2530        }
 2531
 2532        self.selections
 2533            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2534            .into_iter()
 2535            .any(|selection| {
 2536                // This is needed to cover a corner case, if we just check for an existing
 2537                // selection in the fold range, having a cursor at the start of the fold
 2538                // marks it as selected. Non-empty selections don't cause this.
 2539                let length = selection.end - selection.start;
 2540                length > 0
 2541            })
 2542    }
 2543
 2544    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2545        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2546    }
 2547
 2548    fn key_context_internal(
 2549        &self,
 2550        has_active_edit_prediction: bool,
 2551        window: &mut Window,
 2552        cx: &mut App,
 2553    ) -> KeyContext {
 2554        let mut key_context = KeyContext::new_with_defaults();
 2555        key_context.add("Editor");
 2556        let mode = match self.mode {
 2557            EditorMode::SingleLine => "single_line",
 2558            EditorMode::AutoHeight { .. } => "auto_height",
 2559            EditorMode::Minimap { .. } => "minimap",
 2560            EditorMode::Full { .. } => "full",
 2561        };
 2562
 2563        if EditorSettings::jupyter_enabled(cx) {
 2564            key_context.add("jupyter");
 2565        }
 2566
 2567        key_context.set("mode", mode);
 2568        if self.pending_rename.is_some() {
 2569            key_context.add("renaming");
 2570        }
 2571
 2572        if let Some(snippet_stack) = self.snippet_stack.last() {
 2573            key_context.add("in_snippet");
 2574
 2575            if snippet_stack.active_index > 0 {
 2576                key_context.add("has_previous_tabstop");
 2577            }
 2578
 2579            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2580                key_context.add("has_next_tabstop");
 2581            }
 2582        }
 2583
 2584        match self.context_menu.borrow().as_ref() {
 2585            Some(CodeContextMenu::Completions(menu)) => {
 2586                if menu.visible() {
 2587                    key_context.add("menu");
 2588                    key_context.add("showing_completions");
 2589                }
 2590            }
 2591            Some(CodeContextMenu::CodeActions(menu)) => {
 2592                if menu.visible() {
 2593                    key_context.add("menu");
 2594                    key_context.add("showing_code_actions")
 2595                }
 2596            }
 2597            None => {}
 2598        }
 2599
 2600        if self.signature_help_state.has_multiple_signatures() {
 2601            key_context.add("showing_signature_help");
 2602        }
 2603
 2604        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2605        if !self.focus_handle(cx).contains_focused(window, cx)
 2606            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2607        {
 2608            for addon in self.addons.values() {
 2609                addon.extend_key_context(&mut key_context, cx)
 2610            }
 2611        }
 2612
 2613        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2614            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2615                Some(
 2616                    file.full_path(cx)
 2617                        .extension()?
 2618                        .to_string_lossy()
 2619                        .into_owned(),
 2620                )
 2621            }) {
 2622                key_context.set("extension", extension);
 2623            }
 2624        } else {
 2625            key_context.add("multibuffer");
 2626        }
 2627
 2628        if has_active_edit_prediction {
 2629            if self.edit_prediction_in_conflict() {
 2630                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2631            } else {
 2632                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2633                key_context.add("copilot_suggestion");
 2634            }
 2635        }
 2636
 2637        if self.selection_mark_mode {
 2638            key_context.add("selection_mode");
 2639        }
 2640
 2641        let disjoint = self.selections.disjoint_anchors();
 2642        let snapshot = self.snapshot(window, cx);
 2643        let snapshot = snapshot.buffer_snapshot();
 2644        if self.mode == EditorMode::SingleLine
 2645            && let [selection] = disjoint
 2646            && selection.start == selection.end
 2647            && selection.end.to_offset(snapshot) == snapshot.len()
 2648        {
 2649            key_context.add("end_of_input");
 2650        }
 2651
 2652        if self.has_any_expanded_diff_hunks(cx) {
 2653            key_context.add("diffs_expanded");
 2654        }
 2655
 2656        key_context
 2657    }
 2658
 2659    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2660        self.last_bounds.as_ref()
 2661    }
 2662
 2663    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2664        if self.mouse_cursor_hidden {
 2665            self.mouse_cursor_hidden = false;
 2666            cx.notify();
 2667        }
 2668    }
 2669
 2670    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2671        let hide_mouse_cursor = match origin {
 2672            HideMouseCursorOrigin::TypingAction => {
 2673                matches!(
 2674                    self.hide_mouse_mode,
 2675                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2676                )
 2677            }
 2678            HideMouseCursorOrigin::MovementAction => {
 2679                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2680            }
 2681        };
 2682        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2683            self.mouse_cursor_hidden = hide_mouse_cursor;
 2684            cx.notify();
 2685        }
 2686    }
 2687
 2688    pub fn edit_prediction_in_conflict(&self) -> bool {
 2689        if !self.show_edit_predictions_in_menu() {
 2690            return false;
 2691        }
 2692
 2693        let showing_completions = self
 2694            .context_menu
 2695            .borrow()
 2696            .as_ref()
 2697            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2698
 2699        showing_completions
 2700            || self.edit_prediction_requires_modifier()
 2701            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2702            // bindings to insert tab characters.
 2703            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2704    }
 2705
 2706    pub fn accept_edit_prediction_keybind(
 2707        &self,
 2708        accept_partial: bool,
 2709        window: &mut Window,
 2710        cx: &mut App,
 2711    ) -> AcceptEditPredictionBinding {
 2712        let key_context = self.key_context_internal(true, window, cx);
 2713        let in_conflict = self.edit_prediction_in_conflict();
 2714
 2715        let bindings = if accept_partial {
 2716            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2717        } else {
 2718            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2719        };
 2720
 2721        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2722        // just the first one.
 2723        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2724            !in_conflict
 2725                || binding
 2726                    .keystrokes()
 2727                    .first()
 2728                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2729        }))
 2730    }
 2731
 2732    pub fn new_file(
 2733        workspace: &mut Workspace,
 2734        _: &workspace::NewFile,
 2735        window: &mut Window,
 2736        cx: &mut Context<Workspace>,
 2737    ) {
 2738        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2739            "Failed to create buffer",
 2740            window,
 2741            cx,
 2742            |e, _, _| match e.error_code() {
 2743                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2744                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2745                e.error_tag("required").unwrap_or("the latest version")
 2746            )),
 2747                _ => None,
 2748            },
 2749        );
 2750    }
 2751
 2752    pub fn new_in_workspace(
 2753        workspace: &mut Workspace,
 2754        window: &mut Window,
 2755        cx: &mut Context<Workspace>,
 2756    ) -> Task<Result<Entity<Editor>>> {
 2757        let project = workspace.project().clone();
 2758        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2759
 2760        cx.spawn_in(window, async move |workspace, cx| {
 2761            let buffer = create.await?;
 2762            workspace.update_in(cx, |workspace, window, cx| {
 2763                let editor =
 2764                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2765                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2766                editor
 2767            })
 2768        })
 2769    }
 2770
 2771    fn new_file_vertical(
 2772        workspace: &mut Workspace,
 2773        _: &workspace::NewFileSplitVertical,
 2774        window: &mut Window,
 2775        cx: &mut Context<Workspace>,
 2776    ) {
 2777        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2778    }
 2779
 2780    fn new_file_horizontal(
 2781        workspace: &mut Workspace,
 2782        _: &workspace::NewFileSplitHorizontal,
 2783        window: &mut Window,
 2784        cx: &mut Context<Workspace>,
 2785    ) {
 2786        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2787    }
 2788
 2789    fn new_file_split(
 2790        workspace: &mut Workspace,
 2791        action: &workspace::NewFileSplit,
 2792        window: &mut Window,
 2793        cx: &mut Context<Workspace>,
 2794    ) {
 2795        Self::new_file_in_direction(workspace, action.0, window, cx)
 2796    }
 2797
 2798    fn new_file_in_direction(
 2799        workspace: &mut Workspace,
 2800        direction: SplitDirection,
 2801        window: &mut Window,
 2802        cx: &mut Context<Workspace>,
 2803    ) {
 2804        let project = workspace.project().clone();
 2805        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2806
 2807        cx.spawn_in(window, async move |workspace, cx| {
 2808            let buffer = create.await?;
 2809            workspace.update_in(cx, move |workspace, window, cx| {
 2810                workspace.split_item(
 2811                    direction,
 2812                    Box::new(
 2813                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2814                    ),
 2815                    window,
 2816                    cx,
 2817                )
 2818            })?;
 2819            anyhow::Ok(())
 2820        })
 2821        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2822            match e.error_code() {
 2823                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2824                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2825                e.error_tag("required").unwrap_or("the latest version")
 2826            )),
 2827                _ => None,
 2828            }
 2829        });
 2830    }
 2831
 2832    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2833        self.leader_id
 2834    }
 2835
 2836    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2837        &self.buffer
 2838    }
 2839
 2840    pub fn project(&self) -> Option<&Entity<Project>> {
 2841        self.project.as_ref()
 2842    }
 2843
 2844    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2845        self.workspace.as_ref()?.0.upgrade()
 2846    }
 2847
 2848    /// Returns the workspace serialization ID if this editor should be serialized.
 2849    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2850        self.workspace
 2851            .as_ref()
 2852            .filter(|_| self.should_serialize_buffer())
 2853            .and_then(|workspace| workspace.1)
 2854    }
 2855
 2856    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2857        self.buffer().read(cx).title(cx)
 2858    }
 2859
 2860    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2861        let git_blame_gutter_max_author_length = self
 2862            .render_git_blame_gutter(cx)
 2863            .then(|| {
 2864                if let Some(blame) = self.blame.as_ref() {
 2865                    let max_author_length =
 2866                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2867                    Some(max_author_length)
 2868                } else {
 2869                    None
 2870                }
 2871            })
 2872            .flatten();
 2873
 2874        EditorSnapshot {
 2875            mode: self.mode.clone(),
 2876            show_gutter: self.show_gutter,
 2877            show_line_numbers: self.show_line_numbers,
 2878            show_git_diff_gutter: self.show_git_diff_gutter,
 2879            show_code_actions: self.show_code_actions,
 2880            show_runnables: self.show_runnables,
 2881            show_breakpoints: self.show_breakpoints,
 2882            git_blame_gutter_max_author_length,
 2883            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2884            placeholder_display_snapshot: self
 2885                .placeholder_display_map
 2886                .as_ref()
 2887                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2888            scroll_anchor: self.scroll_manager.anchor(),
 2889            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2890            is_focused: self.focus_handle.is_focused(window),
 2891            current_line_highlight: self
 2892                .current_line_highlight
 2893                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2894            gutter_hovered: self.gutter_hovered,
 2895        }
 2896    }
 2897
 2898    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2899        self.buffer.read(cx).language_at(point, cx)
 2900    }
 2901
 2902    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2903        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2904    }
 2905
 2906    pub fn active_excerpt(
 2907        &self,
 2908        cx: &App,
 2909    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2910        self.buffer
 2911            .read(cx)
 2912            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2913    }
 2914
 2915    pub fn mode(&self) -> &EditorMode {
 2916        &self.mode
 2917    }
 2918
 2919    pub fn set_mode(&mut self, mode: EditorMode) {
 2920        self.mode = mode;
 2921    }
 2922
 2923    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2924        self.collaboration_hub.as_deref()
 2925    }
 2926
 2927    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2928        self.collaboration_hub = Some(hub);
 2929    }
 2930
 2931    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2932        self.in_project_search = in_project_search;
 2933    }
 2934
 2935    pub fn set_custom_context_menu(
 2936        &mut self,
 2937        f: impl 'static
 2938        + Fn(
 2939            &mut Self,
 2940            DisplayPoint,
 2941            &mut Window,
 2942            &mut Context<Self>,
 2943        ) -> Option<Entity<ui::ContextMenu>>,
 2944    ) {
 2945        self.custom_context_menu = Some(Box::new(f))
 2946    }
 2947
 2948    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2949        self.completion_provider = provider;
 2950    }
 2951
 2952    #[cfg(any(test, feature = "test-support"))]
 2953    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2954        self.completion_provider.clone()
 2955    }
 2956
 2957    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2958        self.semantics_provider.clone()
 2959    }
 2960
 2961    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2962        self.semantics_provider = provider;
 2963    }
 2964
 2965    pub fn set_edit_prediction_provider<T>(
 2966        &mut self,
 2967        provider: Option<Entity<T>>,
 2968        window: &mut Window,
 2969        cx: &mut Context<Self>,
 2970    ) where
 2971        T: EditPredictionProvider,
 2972    {
 2973        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2974            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2975                if this.focus_handle.is_focused(window) {
 2976                    this.update_visible_edit_prediction(window, cx);
 2977                }
 2978            }),
 2979            provider: Arc::new(provider),
 2980        });
 2981        self.update_edit_prediction_settings(cx);
 2982        self.refresh_edit_prediction(false, false, window, cx);
 2983    }
 2984
 2985    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2986        self.placeholder_display_map
 2987            .as_ref()
 2988            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2989    }
 2990
 2991    pub fn set_placeholder_text(
 2992        &mut self,
 2993        placeholder_text: &str,
 2994        window: &mut Window,
 2995        cx: &mut Context<Self>,
 2996    ) {
 2997        let multibuffer = cx
 2998            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2999
 3000        let style = window.text_style();
 3001
 3002        self.placeholder_display_map = Some(cx.new(|cx| {
 3003            DisplayMap::new(
 3004                multibuffer,
 3005                style.font(),
 3006                style.font_size.to_pixels(window.rem_size()),
 3007                None,
 3008                FILE_HEADER_HEIGHT,
 3009                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3010                Default::default(),
 3011                DiagnosticSeverity::Off,
 3012                cx,
 3013            )
 3014        }));
 3015        cx.notify();
 3016    }
 3017
 3018    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3019        self.cursor_shape = cursor_shape;
 3020
 3021        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3022        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3023
 3024        cx.notify();
 3025    }
 3026
 3027    pub fn cursor_shape(&self) -> CursorShape {
 3028        self.cursor_shape
 3029    }
 3030
 3031    pub fn set_current_line_highlight(
 3032        &mut self,
 3033        current_line_highlight: Option<CurrentLineHighlight>,
 3034    ) {
 3035        self.current_line_highlight = current_line_highlight;
 3036    }
 3037
 3038    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3039        self.collapse_matches = collapse_matches;
 3040    }
 3041
 3042    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3043        if self.collapse_matches {
 3044            return range.start..range.start;
 3045        }
 3046        range.clone()
 3047    }
 3048
 3049    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3050        self.display_map.read(cx).clip_at_line_ends
 3051    }
 3052
 3053    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3054        if self.display_map.read(cx).clip_at_line_ends != clip {
 3055            self.display_map
 3056                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3057        }
 3058    }
 3059
 3060    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3061        self.input_enabled = input_enabled;
 3062    }
 3063
 3064    pub fn set_edit_predictions_hidden_for_vim_mode(
 3065        &mut self,
 3066        hidden: bool,
 3067        window: &mut Window,
 3068        cx: &mut Context<Self>,
 3069    ) {
 3070        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3071            self.edit_predictions_hidden_for_vim_mode = hidden;
 3072            if hidden {
 3073                self.update_visible_edit_prediction(window, cx);
 3074            } else {
 3075                self.refresh_edit_prediction(true, false, window, cx);
 3076            }
 3077        }
 3078    }
 3079
 3080    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3081        self.menu_edit_predictions_policy = value;
 3082    }
 3083
 3084    pub fn set_autoindent(&mut self, autoindent: bool) {
 3085        if autoindent {
 3086            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3087        } else {
 3088            self.autoindent_mode = None;
 3089        }
 3090    }
 3091
 3092    pub fn read_only(&self, cx: &App) -> bool {
 3093        self.read_only || self.buffer.read(cx).read_only()
 3094    }
 3095
 3096    pub fn set_read_only(&mut self, read_only: bool) {
 3097        self.read_only = read_only;
 3098    }
 3099
 3100    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3101        self.use_autoclose = autoclose;
 3102    }
 3103
 3104    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3105        self.use_auto_surround = auto_surround;
 3106    }
 3107
 3108    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3109        self.auto_replace_emoji_shortcode = auto_replace;
 3110    }
 3111
 3112    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3113        self.buffer_serialization = should_serialize.then(|| {
 3114            BufferSerialization::new(
 3115                ProjectSettings::get_global(cx)
 3116                    .session
 3117                    .restore_unsaved_buffers,
 3118            )
 3119        })
 3120    }
 3121
 3122    fn should_serialize_buffer(&self) -> bool {
 3123        self.buffer_serialization.is_some()
 3124    }
 3125
 3126    pub fn toggle_edit_predictions(
 3127        &mut self,
 3128        _: &ToggleEditPrediction,
 3129        window: &mut Window,
 3130        cx: &mut Context<Self>,
 3131    ) {
 3132        if self.show_edit_predictions_override.is_some() {
 3133            self.set_show_edit_predictions(None, window, cx);
 3134        } else {
 3135            let show_edit_predictions = !self.edit_predictions_enabled();
 3136            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3137        }
 3138    }
 3139
 3140    pub fn set_show_edit_predictions(
 3141        &mut self,
 3142        show_edit_predictions: Option<bool>,
 3143        window: &mut Window,
 3144        cx: &mut Context<Self>,
 3145    ) {
 3146        self.show_edit_predictions_override = show_edit_predictions;
 3147        self.update_edit_prediction_settings(cx);
 3148
 3149        if let Some(false) = show_edit_predictions {
 3150            self.discard_edit_prediction(false, cx);
 3151        } else {
 3152            self.refresh_edit_prediction(false, true, window, cx);
 3153        }
 3154    }
 3155
 3156    fn edit_predictions_disabled_in_scope(
 3157        &self,
 3158        buffer: &Entity<Buffer>,
 3159        buffer_position: language::Anchor,
 3160        cx: &App,
 3161    ) -> bool {
 3162        let snapshot = buffer.read(cx).snapshot();
 3163        let settings = snapshot.settings_at(buffer_position, cx);
 3164
 3165        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3166            return false;
 3167        };
 3168
 3169        scope.override_name().is_some_and(|scope_name| {
 3170            settings
 3171                .edit_predictions_disabled_in
 3172                .iter()
 3173                .any(|s| s == scope_name)
 3174        })
 3175    }
 3176
 3177    pub fn set_use_modal_editing(&mut self, to: bool) {
 3178        self.use_modal_editing = to;
 3179    }
 3180
 3181    pub fn use_modal_editing(&self) -> bool {
 3182        self.use_modal_editing
 3183    }
 3184
 3185    fn selections_did_change(
 3186        &mut self,
 3187        local: bool,
 3188        old_cursor_position: &Anchor,
 3189        effects: SelectionEffects,
 3190        window: &mut Window,
 3191        cx: &mut Context<Self>,
 3192    ) {
 3193        window.invalidate_character_coordinates();
 3194
 3195        // Copy selections to primary selection buffer
 3196        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3197        if local {
 3198            let selections = self
 3199                .selections
 3200                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3201            let buffer_handle = self.buffer.read(cx).read(cx);
 3202
 3203            let mut text = String::new();
 3204            for (index, selection) in selections.iter().enumerate() {
 3205                let text_for_selection = buffer_handle
 3206                    .text_for_range(selection.start..selection.end)
 3207                    .collect::<String>();
 3208
 3209                text.push_str(&text_for_selection);
 3210                if index != selections.len() - 1 {
 3211                    text.push('\n');
 3212                }
 3213            }
 3214
 3215            if !text.is_empty() {
 3216                cx.write_to_primary(ClipboardItem::new_string(text));
 3217            }
 3218        }
 3219
 3220        let selection_anchors = self.selections.disjoint_anchors_arc();
 3221
 3222        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3223            self.buffer.update(cx, |buffer, cx| {
 3224                buffer.set_active_selections(
 3225                    &selection_anchors,
 3226                    self.selections.line_mode(),
 3227                    self.cursor_shape,
 3228                    cx,
 3229                )
 3230            });
 3231        }
 3232        let display_map = self
 3233            .display_map
 3234            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3235        let buffer = display_map.buffer_snapshot();
 3236        if self.selections.count() == 1 {
 3237            self.add_selections_state = None;
 3238        }
 3239        self.select_next_state = None;
 3240        self.select_prev_state = None;
 3241        self.select_syntax_node_history.try_clear();
 3242        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3243        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3244        self.take_rename(false, window, cx);
 3245
 3246        let newest_selection = self.selections.newest_anchor();
 3247        let new_cursor_position = newest_selection.head();
 3248        let selection_start = newest_selection.start;
 3249
 3250        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3251            self.push_to_nav_history(
 3252                *old_cursor_position,
 3253                Some(new_cursor_position.to_point(buffer)),
 3254                false,
 3255                effects.nav_history == Some(true),
 3256                cx,
 3257            );
 3258        }
 3259
 3260        if local {
 3261            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3262                self.register_buffer(buffer_id, cx);
 3263            }
 3264
 3265            let mut context_menu = self.context_menu.borrow_mut();
 3266            let completion_menu = match context_menu.as_ref() {
 3267                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3268                Some(CodeContextMenu::CodeActions(_)) => {
 3269                    *context_menu = None;
 3270                    None
 3271                }
 3272                None => None,
 3273            };
 3274            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3275            drop(context_menu);
 3276
 3277            if effects.completions
 3278                && let Some(completion_position) = completion_position
 3279            {
 3280                let start_offset = selection_start.to_offset(buffer);
 3281                let position_matches = start_offset == completion_position.to_offset(buffer);
 3282                let continue_showing = if position_matches {
 3283                    if self.snippet_stack.is_empty() {
 3284                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3285                            == Some(CharKind::Word)
 3286                    } else {
 3287                        // Snippet choices can be shown even when the cursor is in whitespace.
 3288                        // Dismissing the menu with actions like backspace is handled by
 3289                        // invalidation regions.
 3290                        true
 3291                    }
 3292                } else {
 3293                    false
 3294                };
 3295
 3296                if continue_showing {
 3297                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3298                } else {
 3299                    self.hide_context_menu(window, cx);
 3300                }
 3301            }
 3302
 3303            hide_hover(self, cx);
 3304
 3305            if old_cursor_position.to_display_point(&display_map).row()
 3306                != new_cursor_position.to_display_point(&display_map).row()
 3307            {
 3308                self.available_code_actions.take();
 3309            }
 3310            self.refresh_code_actions(window, cx);
 3311            self.refresh_document_highlights(cx);
 3312            refresh_linked_ranges(self, window, cx);
 3313
 3314            self.refresh_selected_text_highlights(false, window, cx);
 3315            self.refresh_matching_bracket_highlights(window, cx);
 3316            self.update_visible_edit_prediction(window, cx);
 3317            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3318            self.inline_blame_popover.take();
 3319            if self.git_blame_inline_enabled {
 3320                self.start_inline_blame_timer(window, cx);
 3321            }
 3322        }
 3323
 3324        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3325        cx.emit(EditorEvent::SelectionsChanged { local });
 3326
 3327        let selections = &self.selections.disjoint_anchors_arc();
 3328        if selections.len() == 1 {
 3329            cx.emit(SearchEvent::ActiveMatchChanged)
 3330        }
 3331        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3332            let inmemory_selections = selections
 3333                .iter()
 3334                .map(|s| {
 3335                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3336                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3337                })
 3338                .collect();
 3339            self.update_restoration_data(cx, |data| {
 3340                data.selections = inmemory_selections;
 3341            });
 3342
 3343            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3344                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3345            {
 3346                let snapshot = self.buffer().read(cx).snapshot(cx);
 3347                let selections = selections.clone();
 3348                let background_executor = cx.background_executor().clone();
 3349                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3350                self.serialize_selections = cx.background_spawn(async move {
 3351                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3352                    let db_selections = selections
 3353                        .iter()
 3354                        .map(|selection| {
 3355                            (
 3356                                selection.start.to_offset(&snapshot).0,
 3357                                selection.end.to_offset(&snapshot).0,
 3358                            )
 3359                        })
 3360                        .collect();
 3361
 3362                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3363                        .await
 3364                        .with_context(|| {
 3365                            format!(
 3366                                "persisting editor selections for editor {editor_id}, \
 3367                                workspace {workspace_id:?}"
 3368                            )
 3369                        })
 3370                        .log_err();
 3371                });
 3372            }
 3373        }
 3374
 3375        cx.notify();
 3376    }
 3377
 3378    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3379        use text::ToOffset as _;
 3380        use text::ToPoint as _;
 3381
 3382        if self.mode.is_minimap()
 3383            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3384        {
 3385            return;
 3386        }
 3387
 3388        if !self.buffer().read(cx).is_singleton() {
 3389            return;
 3390        }
 3391
 3392        let display_snapshot = self
 3393            .display_map
 3394            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3395        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3396            return;
 3397        };
 3398        let inmemory_folds = display_snapshot
 3399            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3400            .map(|fold| {
 3401                fold.range.start.text_anchor.to_point(&snapshot)
 3402                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3403            })
 3404            .collect();
 3405        self.update_restoration_data(cx, |data| {
 3406            data.folds = inmemory_folds;
 3407        });
 3408
 3409        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3410            return;
 3411        };
 3412        let background_executor = cx.background_executor().clone();
 3413        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3414        let db_folds = display_snapshot
 3415            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3416            .map(|fold| {
 3417                (
 3418                    fold.range.start.text_anchor.to_offset(&snapshot),
 3419                    fold.range.end.text_anchor.to_offset(&snapshot),
 3420                )
 3421            })
 3422            .collect();
 3423        self.serialize_folds = cx.background_spawn(async move {
 3424            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3425            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3426                .await
 3427                .with_context(|| {
 3428                    format!(
 3429                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3430                    )
 3431                })
 3432                .log_err();
 3433        });
 3434    }
 3435
 3436    pub fn sync_selections(
 3437        &mut self,
 3438        other: Entity<Editor>,
 3439        cx: &mut Context<Self>,
 3440    ) -> gpui::Subscription {
 3441        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3442        if !other_selections.is_empty() {
 3443            self.selections
 3444                .change_with(&self.display_snapshot(cx), |selections| {
 3445                    selections.select_anchors(other_selections);
 3446                });
 3447        }
 3448
 3449        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3450            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3451                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3452                if other_selections.is_empty() {
 3453                    return;
 3454                }
 3455                let snapshot = this.display_snapshot(cx);
 3456                this.selections.change_with(&snapshot, |selections| {
 3457                    selections.select_anchors(other_selections);
 3458                });
 3459            }
 3460        });
 3461
 3462        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3463            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3464                let these_selections = this.selections.disjoint_anchors().to_vec();
 3465                if these_selections.is_empty() {
 3466                    return;
 3467                }
 3468                other.update(cx, |other_editor, cx| {
 3469                    let snapshot = other_editor.display_snapshot(cx);
 3470                    other_editor
 3471                        .selections
 3472                        .change_with(&snapshot, |selections| {
 3473                            selections.select_anchors(these_selections);
 3474                        })
 3475                });
 3476            }
 3477        });
 3478
 3479        Subscription::join(other_subscription, this_subscription)
 3480    }
 3481
 3482    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3483        if self.buffer().read(cx).is_singleton() {
 3484            return;
 3485        }
 3486        let snapshot = self.buffer.read(cx).snapshot(cx);
 3487        let buffer_ids: HashSet<BufferId> = self
 3488            .selections
 3489            .disjoint_anchor_ranges()
 3490            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3491            .collect();
 3492        for buffer_id in buffer_ids {
 3493            self.unfold_buffer(buffer_id, cx);
 3494        }
 3495    }
 3496
 3497    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3498    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3499    /// effects of selection change occur at the end of the transaction.
 3500    pub fn change_selections<R>(
 3501        &mut self,
 3502        effects: SelectionEffects,
 3503        window: &mut Window,
 3504        cx: &mut Context<Self>,
 3505        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3506    ) -> R {
 3507        let snapshot = self.display_snapshot(cx);
 3508        if let Some(state) = &mut self.deferred_selection_effects_state {
 3509            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3510            state.effects.completions = effects.completions;
 3511            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3512            let (changed, result) = self.selections.change_with(&snapshot, change);
 3513            state.changed |= changed;
 3514            return result;
 3515        }
 3516        let mut state = DeferredSelectionEffectsState {
 3517            changed: false,
 3518            effects,
 3519            old_cursor_position: self.selections.newest_anchor().head(),
 3520            history_entry: SelectionHistoryEntry {
 3521                selections: self.selections.disjoint_anchors_arc(),
 3522                select_next_state: self.select_next_state.clone(),
 3523                select_prev_state: self.select_prev_state.clone(),
 3524                add_selections_state: self.add_selections_state.clone(),
 3525            },
 3526        };
 3527        let (changed, result) = self.selections.change_with(&snapshot, change);
 3528        state.changed = state.changed || changed;
 3529        if self.defer_selection_effects {
 3530            self.deferred_selection_effects_state = Some(state);
 3531        } else {
 3532            self.apply_selection_effects(state, window, cx);
 3533        }
 3534        result
 3535    }
 3536
 3537    /// Defers the effects of selection change, so that the effects of multiple calls to
 3538    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3539    /// to selection history and the state of popovers based on selection position aren't
 3540    /// erroneously updated.
 3541    pub fn with_selection_effects_deferred<R>(
 3542        &mut self,
 3543        window: &mut Window,
 3544        cx: &mut Context<Self>,
 3545        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3546    ) -> R {
 3547        let already_deferred = self.defer_selection_effects;
 3548        self.defer_selection_effects = true;
 3549        let result = update(self, window, cx);
 3550        if !already_deferred {
 3551            self.defer_selection_effects = false;
 3552            if let Some(state) = self.deferred_selection_effects_state.take() {
 3553                self.apply_selection_effects(state, window, cx);
 3554            }
 3555        }
 3556        result
 3557    }
 3558
 3559    fn apply_selection_effects(
 3560        &mut self,
 3561        state: DeferredSelectionEffectsState,
 3562        window: &mut Window,
 3563        cx: &mut Context<Self>,
 3564    ) {
 3565        if state.changed {
 3566            self.selection_history.push(state.history_entry);
 3567
 3568            if let Some(autoscroll) = state.effects.scroll {
 3569                self.request_autoscroll(autoscroll, cx);
 3570            }
 3571
 3572            let old_cursor_position = &state.old_cursor_position;
 3573
 3574            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3575
 3576            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3577                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3578            }
 3579        }
 3580    }
 3581
 3582    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3583    where
 3584        I: IntoIterator<Item = (Range<S>, T)>,
 3585        S: ToOffset,
 3586        T: Into<Arc<str>>,
 3587    {
 3588        if self.read_only(cx) {
 3589            return;
 3590        }
 3591
 3592        self.buffer
 3593            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3594    }
 3595
 3596    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3597    where
 3598        I: IntoIterator<Item = (Range<S>, T)>,
 3599        S: ToOffset,
 3600        T: Into<Arc<str>>,
 3601    {
 3602        if self.read_only(cx) {
 3603            return;
 3604        }
 3605
 3606        self.buffer.update(cx, |buffer, cx| {
 3607            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3608        });
 3609    }
 3610
 3611    pub fn edit_with_block_indent<I, S, T>(
 3612        &mut self,
 3613        edits: I,
 3614        original_indent_columns: Vec<Option<u32>>,
 3615        cx: &mut Context<Self>,
 3616    ) where
 3617        I: IntoIterator<Item = (Range<S>, T)>,
 3618        S: ToOffset,
 3619        T: Into<Arc<str>>,
 3620    {
 3621        if self.read_only(cx) {
 3622            return;
 3623        }
 3624
 3625        self.buffer.update(cx, |buffer, cx| {
 3626            buffer.edit(
 3627                edits,
 3628                Some(AutoindentMode::Block {
 3629                    original_indent_columns,
 3630                }),
 3631                cx,
 3632            )
 3633        });
 3634    }
 3635
 3636    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3637        self.hide_context_menu(window, cx);
 3638
 3639        match phase {
 3640            SelectPhase::Begin {
 3641                position,
 3642                add,
 3643                click_count,
 3644            } => self.begin_selection(position, add, click_count, window, cx),
 3645            SelectPhase::BeginColumnar {
 3646                position,
 3647                goal_column,
 3648                reset,
 3649                mode,
 3650            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3651            SelectPhase::Extend {
 3652                position,
 3653                click_count,
 3654            } => self.extend_selection(position, click_count, window, cx),
 3655            SelectPhase::Update {
 3656                position,
 3657                goal_column,
 3658                scroll_delta,
 3659            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3660            SelectPhase::End => self.end_selection(window, cx),
 3661        }
 3662    }
 3663
 3664    fn extend_selection(
 3665        &mut self,
 3666        position: DisplayPoint,
 3667        click_count: usize,
 3668        window: &mut Window,
 3669        cx: &mut Context<Self>,
 3670    ) {
 3671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3672        let tail = self
 3673            .selections
 3674            .newest::<MultiBufferOffset>(&display_map)
 3675            .tail();
 3676        let click_count = click_count.max(match self.selections.select_mode() {
 3677            SelectMode::Character => 1,
 3678            SelectMode::Word(_) => 2,
 3679            SelectMode::Line(_) => 3,
 3680            SelectMode::All => 4,
 3681        });
 3682        self.begin_selection(position, false, click_count, window, cx);
 3683
 3684        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3685
 3686        let current_selection = match self.selections.select_mode() {
 3687            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3688            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3689        };
 3690
 3691        let mut pending_selection = self
 3692            .selections
 3693            .pending_anchor()
 3694            .cloned()
 3695            .expect("extend_selection not called with pending selection");
 3696
 3697        if pending_selection
 3698            .start
 3699            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3700            == Ordering::Greater
 3701        {
 3702            pending_selection.start = current_selection.start;
 3703        }
 3704        if pending_selection
 3705            .end
 3706            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3707            == Ordering::Less
 3708        {
 3709            pending_selection.end = current_selection.end;
 3710            pending_selection.reversed = true;
 3711        }
 3712
 3713        let mut pending_mode = self.selections.pending_mode().unwrap();
 3714        match &mut pending_mode {
 3715            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3716            _ => {}
 3717        }
 3718
 3719        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3720            SelectionEffects::scroll(Autoscroll::fit())
 3721        } else {
 3722            SelectionEffects::no_scroll()
 3723        };
 3724
 3725        self.change_selections(effects, window, cx, |s| {
 3726            s.set_pending(pending_selection.clone(), pending_mode);
 3727            s.set_is_extending(true);
 3728        });
 3729    }
 3730
 3731    fn begin_selection(
 3732        &mut self,
 3733        position: DisplayPoint,
 3734        add: bool,
 3735        click_count: usize,
 3736        window: &mut Window,
 3737        cx: &mut Context<Self>,
 3738    ) {
 3739        if !self.focus_handle.is_focused(window) {
 3740            self.last_focused_descendant = None;
 3741            window.focus(&self.focus_handle);
 3742        }
 3743
 3744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3745        let buffer = display_map.buffer_snapshot();
 3746        let position = display_map.clip_point(position, Bias::Left);
 3747
 3748        let start;
 3749        let end;
 3750        let mode;
 3751        let mut auto_scroll;
 3752        match click_count {
 3753            1 => {
 3754                start = buffer.anchor_before(position.to_point(&display_map));
 3755                end = start;
 3756                mode = SelectMode::Character;
 3757                auto_scroll = true;
 3758            }
 3759            2 => {
 3760                let position = display_map
 3761                    .clip_point(position, Bias::Left)
 3762                    .to_offset(&display_map, Bias::Left);
 3763                let (range, _) = buffer.surrounding_word(position, None);
 3764                start = buffer.anchor_before(range.start);
 3765                end = buffer.anchor_before(range.end);
 3766                mode = SelectMode::Word(start..end);
 3767                auto_scroll = true;
 3768            }
 3769            3 => {
 3770                let position = display_map
 3771                    .clip_point(position, Bias::Left)
 3772                    .to_point(&display_map);
 3773                let line_start = display_map.prev_line_boundary(position).0;
 3774                let next_line_start = buffer.clip_point(
 3775                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3776                    Bias::Left,
 3777                );
 3778                start = buffer.anchor_before(line_start);
 3779                end = buffer.anchor_before(next_line_start);
 3780                mode = SelectMode::Line(start..end);
 3781                auto_scroll = true;
 3782            }
 3783            _ => {
 3784                start = buffer.anchor_before(MultiBufferOffset(0));
 3785                end = buffer.anchor_before(buffer.len());
 3786                mode = SelectMode::All;
 3787                auto_scroll = false;
 3788            }
 3789        }
 3790        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3791
 3792        let point_to_delete: Option<usize> = {
 3793            let selected_points: Vec<Selection<Point>> =
 3794                self.selections.disjoint_in_range(start..end, &display_map);
 3795
 3796            if !add || click_count > 1 {
 3797                None
 3798            } else if !selected_points.is_empty() {
 3799                Some(selected_points[0].id)
 3800            } else {
 3801                let clicked_point_already_selected =
 3802                    self.selections.disjoint_anchors().iter().find(|selection| {
 3803                        selection.start.to_point(buffer) == start.to_point(buffer)
 3804                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3805                    });
 3806
 3807                clicked_point_already_selected.map(|selection| selection.id)
 3808            }
 3809        };
 3810
 3811        let selections_count = self.selections.count();
 3812        let effects = if auto_scroll {
 3813            SelectionEffects::default()
 3814        } else {
 3815            SelectionEffects::no_scroll()
 3816        };
 3817
 3818        self.change_selections(effects, window, cx, |s| {
 3819            if let Some(point_to_delete) = point_to_delete {
 3820                s.delete(point_to_delete);
 3821
 3822                if selections_count == 1 {
 3823                    s.set_pending_anchor_range(start..end, mode);
 3824                }
 3825            } else {
 3826                if !add {
 3827                    s.clear_disjoint();
 3828                }
 3829
 3830                s.set_pending_anchor_range(start..end, mode);
 3831            }
 3832        });
 3833    }
 3834
 3835    fn begin_columnar_selection(
 3836        &mut self,
 3837        position: DisplayPoint,
 3838        goal_column: u32,
 3839        reset: bool,
 3840        mode: ColumnarMode,
 3841        window: &mut Window,
 3842        cx: &mut Context<Self>,
 3843    ) {
 3844        if !self.focus_handle.is_focused(window) {
 3845            self.last_focused_descendant = None;
 3846            window.focus(&self.focus_handle);
 3847        }
 3848
 3849        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3850
 3851        if reset {
 3852            let pointer_position = display_map
 3853                .buffer_snapshot()
 3854                .anchor_before(position.to_point(&display_map));
 3855
 3856            self.change_selections(
 3857                SelectionEffects::scroll(Autoscroll::newest()),
 3858                window,
 3859                cx,
 3860                |s| {
 3861                    s.clear_disjoint();
 3862                    s.set_pending_anchor_range(
 3863                        pointer_position..pointer_position,
 3864                        SelectMode::Character,
 3865                    );
 3866                },
 3867            );
 3868        };
 3869
 3870        let tail = self.selections.newest::<Point>(&display_map).tail();
 3871        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3872        self.columnar_selection_state = match mode {
 3873            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3874                selection_tail: selection_anchor,
 3875                display_point: if reset {
 3876                    if position.column() != goal_column {
 3877                        Some(DisplayPoint::new(position.row(), goal_column))
 3878                    } else {
 3879                        None
 3880                    }
 3881                } else {
 3882                    None
 3883                },
 3884            }),
 3885            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3886                selection_tail: selection_anchor,
 3887            }),
 3888        };
 3889
 3890        if !reset {
 3891            self.select_columns(position, goal_column, &display_map, window, cx);
 3892        }
 3893    }
 3894
 3895    fn update_selection(
 3896        &mut self,
 3897        position: DisplayPoint,
 3898        goal_column: u32,
 3899        scroll_delta: gpui::Point<f32>,
 3900        window: &mut Window,
 3901        cx: &mut Context<Self>,
 3902    ) {
 3903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3904
 3905        if self.columnar_selection_state.is_some() {
 3906            self.select_columns(position, goal_column, &display_map, window, cx);
 3907        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3908            let buffer = display_map.buffer_snapshot();
 3909            let head;
 3910            let tail;
 3911            let mode = self.selections.pending_mode().unwrap();
 3912            match &mode {
 3913                SelectMode::Character => {
 3914                    head = position.to_point(&display_map);
 3915                    tail = pending.tail().to_point(buffer);
 3916                }
 3917                SelectMode::Word(original_range) => {
 3918                    let offset = display_map
 3919                        .clip_point(position, Bias::Left)
 3920                        .to_offset(&display_map, Bias::Left);
 3921                    let original_range = original_range.to_offset(buffer);
 3922
 3923                    let head_offset = if buffer.is_inside_word(offset, None)
 3924                        || original_range.contains(&offset)
 3925                    {
 3926                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3927                        if word_range.start < original_range.start {
 3928                            word_range.start
 3929                        } else {
 3930                            word_range.end
 3931                        }
 3932                    } else {
 3933                        offset
 3934                    };
 3935
 3936                    head = head_offset.to_point(buffer);
 3937                    if head_offset <= original_range.start {
 3938                        tail = original_range.end.to_point(buffer);
 3939                    } else {
 3940                        tail = original_range.start.to_point(buffer);
 3941                    }
 3942                }
 3943                SelectMode::Line(original_range) => {
 3944                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3945
 3946                    let position = display_map
 3947                        .clip_point(position, Bias::Left)
 3948                        .to_point(&display_map);
 3949                    let line_start = display_map.prev_line_boundary(position).0;
 3950                    let next_line_start = buffer.clip_point(
 3951                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3952                        Bias::Left,
 3953                    );
 3954
 3955                    if line_start < original_range.start {
 3956                        head = line_start
 3957                    } else {
 3958                        head = next_line_start
 3959                    }
 3960
 3961                    if head <= original_range.start {
 3962                        tail = original_range.end;
 3963                    } else {
 3964                        tail = original_range.start;
 3965                    }
 3966                }
 3967                SelectMode::All => {
 3968                    return;
 3969                }
 3970            };
 3971
 3972            if head < tail {
 3973                pending.start = buffer.anchor_before(head);
 3974                pending.end = buffer.anchor_before(tail);
 3975                pending.reversed = true;
 3976            } else {
 3977                pending.start = buffer.anchor_before(tail);
 3978                pending.end = buffer.anchor_before(head);
 3979                pending.reversed = false;
 3980            }
 3981
 3982            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3983                s.set_pending(pending.clone(), mode);
 3984            });
 3985        } else {
 3986            log::error!("update_selection dispatched with no pending selection");
 3987            return;
 3988        }
 3989
 3990        self.apply_scroll_delta(scroll_delta, window, cx);
 3991        cx.notify();
 3992    }
 3993
 3994    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3995        self.columnar_selection_state.take();
 3996        if let Some(pending_mode) = self.selections.pending_mode() {
 3997            let selections = self
 3998                .selections
 3999                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4000            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4001                s.select(selections);
 4002                s.clear_pending();
 4003                if s.is_extending() {
 4004                    s.set_is_extending(false);
 4005                } else {
 4006                    s.set_select_mode(pending_mode);
 4007                }
 4008            });
 4009        }
 4010    }
 4011
 4012    fn select_columns(
 4013        &mut self,
 4014        head: DisplayPoint,
 4015        goal_column: u32,
 4016        display_map: &DisplaySnapshot,
 4017        window: &mut Window,
 4018        cx: &mut Context<Self>,
 4019    ) {
 4020        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4021            return;
 4022        };
 4023
 4024        let tail = match columnar_state {
 4025            ColumnarSelectionState::FromMouse {
 4026                selection_tail,
 4027                display_point,
 4028            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4029            ColumnarSelectionState::FromSelection { selection_tail } => {
 4030                selection_tail.to_display_point(display_map)
 4031            }
 4032        };
 4033
 4034        let start_row = cmp::min(tail.row(), head.row());
 4035        let end_row = cmp::max(tail.row(), head.row());
 4036        let start_column = cmp::min(tail.column(), goal_column);
 4037        let end_column = cmp::max(tail.column(), goal_column);
 4038        let reversed = start_column < tail.column();
 4039
 4040        let selection_ranges = (start_row.0..=end_row.0)
 4041            .map(DisplayRow)
 4042            .filter_map(|row| {
 4043                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4044                    || start_column <= display_map.line_len(row))
 4045                    && !display_map.is_block_line(row)
 4046                {
 4047                    let start = display_map
 4048                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4049                        .to_point(display_map);
 4050                    let end = display_map
 4051                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4052                        .to_point(display_map);
 4053                    if reversed {
 4054                        Some(end..start)
 4055                    } else {
 4056                        Some(start..end)
 4057                    }
 4058                } else {
 4059                    None
 4060                }
 4061            })
 4062            .collect::<Vec<_>>();
 4063        if selection_ranges.is_empty() {
 4064            return;
 4065        }
 4066
 4067        let ranges = match columnar_state {
 4068            ColumnarSelectionState::FromMouse { .. } => {
 4069                let mut non_empty_ranges = selection_ranges
 4070                    .iter()
 4071                    .filter(|selection_range| selection_range.start != selection_range.end)
 4072                    .peekable();
 4073                if non_empty_ranges.peek().is_some() {
 4074                    non_empty_ranges.cloned().collect()
 4075                } else {
 4076                    selection_ranges
 4077                }
 4078            }
 4079            _ => selection_ranges,
 4080        };
 4081
 4082        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4083            s.select_ranges(ranges);
 4084        });
 4085        cx.notify();
 4086    }
 4087
 4088    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4089        self.selections
 4090            .all_adjusted(snapshot)
 4091            .iter()
 4092            .any(|selection| !selection.is_empty())
 4093    }
 4094
 4095    pub fn has_pending_nonempty_selection(&self) -> bool {
 4096        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4097            Some(Selection { start, end, .. }) => start != end,
 4098            None => false,
 4099        };
 4100
 4101        pending_nonempty_selection
 4102            || (self.columnar_selection_state.is_some()
 4103                && self.selections.disjoint_anchors().len() > 1)
 4104    }
 4105
 4106    pub fn has_pending_selection(&self) -> bool {
 4107        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4108    }
 4109
 4110    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4111        self.selection_mark_mode = false;
 4112        self.selection_drag_state = SelectionDragState::None;
 4113
 4114        if self.dismiss_menus_and_popups(true, window, cx) {
 4115            cx.notify();
 4116            return;
 4117        }
 4118        if self.clear_expanded_diff_hunks(cx) {
 4119            cx.notify();
 4120            return;
 4121        }
 4122        if self.show_git_blame_gutter {
 4123            self.show_git_blame_gutter = false;
 4124            cx.notify();
 4125            return;
 4126        }
 4127
 4128        if self.mode.is_full()
 4129            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4130        {
 4131            cx.notify();
 4132            return;
 4133        }
 4134
 4135        cx.propagate();
 4136    }
 4137
 4138    pub fn dismiss_menus_and_popups(
 4139        &mut self,
 4140        is_user_requested: bool,
 4141        window: &mut Window,
 4142        cx: &mut Context<Self>,
 4143    ) -> bool {
 4144        let mut dismissed = false;
 4145
 4146        dismissed |= self.take_rename(false, window, cx).is_some();
 4147        dismissed |= self.hide_blame_popover(true, cx);
 4148        dismissed |= hide_hover(self, cx);
 4149        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4150        dismissed |= self.hide_context_menu(window, cx).is_some();
 4151        dismissed |= self.mouse_context_menu.take().is_some();
 4152        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4153        dismissed |= self.snippet_stack.pop().is_some();
 4154
 4155        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4156            self.dismiss_diagnostics(cx);
 4157            dismissed = true;
 4158        }
 4159
 4160        dismissed
 4161    }
 4162
 4163    fn linked_editing_ranges_for(
 4164        &self,
 4165        selection: Range<text::Anchor>,
 4166        cx: &App,
 4167    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4168        if self.linked_edit_ranges.is_empty() {
 4169            return None;
 4170        }
 4171        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4172            selection.end.buffer_id.and_then(|end_buffer_id| {
 4173                if selection.start.buffer_id != Some(end_buffer_id) {
 4174                    return None;
 4175                }
 4176                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4177                let snapshot = buffer.read(cx).snapshot();
 4178                self.linked_edit_ranges
 4179                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4180                    .map(|ranges| (ranges, snapshot, buffer))
 4181            })?;
 4182        use text::ToOffset as TO;
 4183        // find offset from the start of current range to current cursor position
 4184        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4185
 4186        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4187        let start_difference = start_offset - start_byte_offset;
 4188        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4189        let end_difference = end_offset - start_byte_offset;
 4190        // Current range has associated linked ranges.
 4191        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4192        for range in linked_ranges.iter() {
 4193            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4194            let end_offset = start_offset + end_difference;
 4195            let start_offset = start_offset + start_difference;
 4196            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4197                continue;
 4198            }
 4199            if self.selections.disjoint_anchor_ranges().any(|s| {
 4200                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4201                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4202                {
 4203                    return false;
 4204                }
 4205                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4206                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4207            }) {
 4208                continue;
 4209            }
 4210            let start = buffer_snapshot.anchor_after(start_offset);
 4211            let end = buffer_snapshot.anchor_after(end_offset);
 4212            linked_edits
 4213                .entry(buffer.clone())
 4214                .or_default()
 4215                .push(start..end);
 4216        }
 4217        Some(linked_edits)
 4218    }
 4219
 4220    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4221        let text: Arc<str> = text.into();
 4222
 4223        if self.read_only(cx) {
 4224            return;
 4225        }
 4226
 4227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4228
 4229        self.unfold_buffers_with_selections(cx);
 4230
 4231        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4232        let mut bracket_inserted = false;
 4233        let mut edits = Vec::new();
 4234        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4235        let mut new_selections = Vec::with_capacity(selections.len());
 4236        let mut new_autoclose_regions = Vec::new();
 4237        let snapshot = self.buffer.read(cx).read(cx);
 4238        let mut clear_linked_edit_ranges = false;
 4239
 4240        for (selection, autoclose_region) in
 4241            self.selections_with_autoclose_regions(selections, &snapshot)
 4242        {
 4243            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4244                // Determine if the inserted text matches the opening or closing
 4245                // bracket of any of this language's bracket pairs.
 4246                let mut bracket_pair = None;
 4247                let mut is_bracket_pair_start = false;
 4248                let mut is_bracket_pair_end = false;
 4249                if !text.is_empty() {
 4250                    let mut bracket_pair_matching_end = None;
 4251                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4252                    //  and they are removing the character that triggered IME popup.
 4253                    for (pair, enabled) in scope.brackets() {
 4254                        if !pair.close && !pair.surround {
 4255                            continue;
 4256                        }
 4257
 4258                        if enabled && pair.start.ends_with(text.as_ref()) {
 4259                            let prefix_len = pair.start.len() - text.len();
 4260                            let preceding_text_matches_prefix = prefix_len == 0
 4261                                || (selection.start.column >= (prefix_len as u32)
 4262                                    && snapshot.contains_str_at(
 4263                                        Point::new(
 4264                                            selection.start.row,
 4265                                            selection.start.column - (prefix_len as u32),
 4266                                        ),
 4267                                        &pair.start[..prefix_len],
 4268                                    ));
 4269                            if preceding_text_matches_prefix {
 4270                                bracket_pair = Some(pair.clone());
 4271                                is_bracket_pair_start = true;
 4272                                break;
 4273                            }
 4274                        }
 4275                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4276                        {
 4277                            // take first bracket pair matching end, but don't break in case a later bracket
 4278                            // pair matches start
 4279                            bracket_pair_matching_end = Some(pair.clone());
 4280                        }
 4281                    }
 4282                    if let Some(end) = bracket_pair_matching_end
 4283                        && bracket_pair.is_none()
 4284                    {
 4285                        bracket_pair = Some(end);
 4286                        is_bracket_pair_end = true;
 4287                    }
 4288                }
 4289
 4290                if let Some(bracket_pair) = bracket_pair {
 4291                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4292                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4293                    let auto_surround =
 4294                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4295                    if selection.is_empty() {
 4296                        if is_bracket_pair_start {
 4297                            // If the inserted text is a suffix of an opening bracket and the
 4298                            // selection is preceded by the rest of the opening bracket, then
 4299                            // insert the closing bracket.
 4300                            let following_text_allows_autoclose = snapshot
 4301                                .chars_at(selection.start)
 4302                                .next()
 4303                                .is_none_or(|c| scope.should_autoclose_before(c));
 4304
 4305                            let preceding_text_allows_autoclose = selection.start.column == 0
 4306                                || snapshot
 4307                                    .reversed_chars_at(selection.start)
 4308                                    .next()
 4309                                    .is_none_or(|c| {
 4310                                        bracket_pair.start != bracket_pair.end
 4311                                            || !snapshot
 4312                                                .char_classifier_at(selection.start)
 4313                                                .is_word(c)
 4314                                    });
 4315
 4316                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4317                                && bracket_pair.start.len() == 1
 4318                            {
 4319                                let target = bracket_pair.start.chars().next().unwrap();
 4320                                let current_line_count = snapshot
 4321                                    .reversed_chars_at(selection.start)
 4322                                    .take_while(|&c| c != '\n')
 4323                                    .filter(|&c| c == target)
 4324                                    .count();
 4325                                current_line_count % 2 == 1
 4326                            } else {
 4327                                false
 4328                            };
 4329
 4330                            if autoclose
 4331                                && bracket_pair.close
 4332                                && following_text_allows_autoclose
 4333                                && preceding_text_allows_autoclose
 4334                                && !is_closing_quote
 4335                            {
 4336                                let anchor = snapshot.anchor_before(selection.end);
 4337                                new_selections.push((selection.map(|_| anchor), text.len()));
 4338                                new_autoclose_regions.push((
 4339                                    anchor,
 4340                                    text.len(),
 4341                                    selection.id,
 4342                                    bracket_pair.clone(),
 4343                                ));
 4344                                edits.push((
 4345                                    selection.range(),
 4346                                    format!("{}{}", text, bracket_pair.end).into(),
 4347                                ));
 4348                                bracket_inserted = true;
 4349                                continue;
 4350                            }
 4351                        }
 4352
 4353                        if let Some(region) = autoclose_region {
 4354                            // If the selection is followed by an auto-inserted closing bracket,
 4355                            // then don't insert that closing bracket again; just move the selection
 4356                            // past the closing bracket.
 4357                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4358                                && text.as_ref() == region.pair.end.as_str()
 4359                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4360                            if should_skip {
 4361                                let anchor = snapshot.anchor_after(selection.end);
 4362                                new_selections
 4363                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4364                                continue;
 4365                            }
 4366                        }
 4367
 4368                        let always_treat_brackets_as_autoclosed = snapshot
 4369                            .language_settings_at(selection.start, cx)
 4370                            .always_treat_brackets_as_autoclosed;
 4371                        if always_treat_brackets_as_autoclosed
 4372                            && is_bracket_pair_end
 4373                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4374                        {
 4375                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4376                            // and the inserted text is a closing bracket and the selection is followed
 4377                            // by the closing bracket then move the selection past the closing bracket.
 4378                            let anchor = snapshot.anchor_after(selection.end);
 4379                            new_selections.push((selection.map(|_| anchor), text.len()));
 4380                            continue;
 4381                        }
 4382                    }
 4383                    // If an opening bracket is 1 character long and is typed while
 4384                    // text is selected, then surround that text with the bracket pair.
 4385                    else if auto_surround
 4386                        && bracket_pair.surround
 4387                        && is_bracket_pair_start
 4388                        && bracket_pair.start.chars().count() == 1
 4389                    {
 4390                        edits.push((selection.start..selection.start, text.clone()));
 4391                        edits.push((
 4392                            selection.end..selection.end,
 4393                            bracket_pair.end.as_str().into(),
 4394                        ));
 4395                        bracket_inserted = true;
 4396                        new_selections.push((
 4397                            Selection {
 4398                                id: selection.id,
 4399                                start: snapshot.anchor_after(selection.start),
 4400                                end: snapshot.anchor_before(selection.end),
 4401                                reversed: selection.reversed,
 4402                                goal: selection.goal,
 4403                            },
 4404                            0,
 4405                        ));
 4406                        continue;
 4407                    }
 4408                }
 4409            }
 4410
 4411            if self.auto_replace_emoji_shortcode
 4412                && selection.is_empty()
 4413                && text.as_ref().ends_with(':')
 4414                && let Some(possible_emoji_short_code) =
 4415                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4416                && !possible_emoji_short_code.is_empty()
 4417                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4418            {
 4419                let emoji_shortcode_start = Point::new(
 4420                    selection.start.row,
 4421                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4422                );
 4423
 4424                // Remove shortcode from buffer
 4425                edits.push((
 4426                    emoji_shortcode_start..selection.start,
 4427                    "".to_string().into(),
 4428                ));
 4429                new_selections.push((
 4430                    Selection {
 4431                        id: selection.id,
 4432                        start: snapshot.anchor_after(emoji_shortcode_start),
 4433                        end: snapshot.anchor_before(selection.start),
 4434                        reversed: selection.reversed,
 4435                        goal: selection.goal,
 4436                    },
 4437                    0,
 4438                ));
 4439
 4440                // Insert emoji
 4441                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4442                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4443                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4444
 4445                continue;
 4446            }
 4447
 4448            // If not handling any auto-close operation, then just replace the selected
 4449            // text with the given input and move the selection to the end of the
 4450            // newly inserted text.
 4451            let anchor = snapshot.anchor_after(selection.end);
 4452            if !self.linked_edit_ranges.is_empty() {
 4453                let start_anchor = snapshot.anchor_before(selection.start);
 4454
 4455                let is_word_char = text.chars().next().is_none_or(|char| {
 4456                    let classifier = snapshot
 4457                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4458                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4459                    classifier.is_word(char)
 4460                });
 4461
 4462                if is_word_char {
 4463                    if let Some(ranges) = self
 4464                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4465                    {
 4466                        for (buffer, edits) in ranges {
 4467                            linked_edits
 4468                                .entry(buffer.clone())
 4469                                .or_default()
 4470                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4471                        }
 4472                    }
 4473                } else {
 4474                    clear_linked_edit_ranges = true;
 4475                }
 4476            }
 4477
 4478            new_selections.push((selection.map(|_| anchor), 0));
 4479            edits.push((selection.start..selection.end, text.clone()));
 4480        }
 4481
 4482        drop(snapshot);
 4483
 4484        self.transact(window, cx, |this, window, cx| {
 4485            if clear_linked_edit_ranges {
 4486                this.linked_edit_ranges.clear();
 4487            }
 4488            let initial_buffer_versions =
 4489                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4490
 4491            this.buffer.update(cx, |buffer, cx| {
 4492                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4493            });
 4494            for (buffer, edits) in linked_edits {
 4495                buffer.update(cx, |buffer, cx| {
 4496                    let snapshot = buffer.snapshot();
 4497                    let edits = edits
 4498                        .into_iter()
 4499                        .map(|(range, text)| {
 4500                            use text::ToPoint as TP;
 4501                            let end_point = TP::to_point(&range.end, &snapshot);
 4502                            let start_point = TP::to_point(&range.start, &snapshot);
 4503                            (start_point..end_point, text)
 4504                        })
 4505                        .sorted_by_key(|(range, _)| range.start);
 4506                    buffer.edit(edits, None, cx);
 4507                })
 4508            }
 4509            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4510            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4511            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4512            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4513                new_anchor_selections,
 4514                &map,
 4515            )
 4516            .zip(new_selection_deltas)
 4517            .map(|(selection, delta)| Selection {
 4518                id: selection.id,
 4519                start: selection.start + delta,
 4520                end: selection.end + delta,
 4521                reversed: selection.reversed,
 4522                goal: SelectionGoal::None,
 4523            })
 4524            .collect::<Vec<_>>();
 4525
 4526            let mut i = 0;
 4527            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4528                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4529                let start = map.buffer_snapshot().anchor_before(position);
 4530                let end = map.buffer_snapshot().anchor_after(position);
 4531                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4532                    match existing_state
 4533                        .range
 4534                        .start
 4535                        .cmp(&start, map.buffer_snapshot())
 4536                    {
 4537                        Ordering::Less => i += 1,
 4538                        Ordering::Greater => break,
 4539                        Ordering::Equal => {
 4540                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4541                                Ordering::Less => i += 1,
 4542                                Ordering::Equal => break,
 4543                                Ordering::Greater => break,
 4544                            }
 4545                        }
 4546                    }
 4547                }
 4548                this.autoclose_regions.insert(
 4549                    i,
 4550                    AutocloseRegion {
 4551                        selection_id,
 4552                        range: start..end,
 4553                        pair,
 4554                    },
 4555                );
 4556            }
 4557
 4558            let had_active_edit_prediction = this.has_active_edit_prediction();
 4559            this.change_selections(
 4560                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4561                window,
 4562                cx,
 4563                |s| s.select(new_selections),
 4564            );
 4565
 4566            if !bracket_inserted
 4567                && let Some(on_type_format_task) =
 4568                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4569            {
 4570                on_type_format_task.detach_and_log_err(cx);
 4571            }
 4572
 4573            let editor_settings = EditorSettings::get_global(cx);
 4574            if bracket_inserted
 4575                && (editor_settings.auto_signature_help
 4576                    || editor_settings.show_signature_help_after_edits)
 4577            {
 4578                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4579            }
 4580
 4581            let trigger_in_words =
 4582                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4583            if this.hard_wrap.is_some() {
 4584                let latest: Range<Point> = this.selections.newest(&map).range();
 4585                if latest.is_empty()
 4586                    && this
 4587                        .buffer()
 4588                        .read(cx)
 4589                        .snapshot(cx)
 4590                        .line_len(MultiBufferRow(latest.start.row))
 4591                        == latest.start.column
 4592                {
 4593                    this.rewrap_impl(
 4594                        RewrapOptions {
 4595                            override_language_settings: true,
 4596                            preserve_existing_whitespace: true,
 4597                        },
 4598                        cx,
 4599                    )
 4600                }
 4601            }
 4602            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4603            refresh_linked_ranges(this, window, cx);
 4604            this.refresh_edit_prediction(true, false, window, cx);
 4605            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4606        });
 4607    }
 4608
 4609    fn find_possible_emoji_shortcode_at_position(
 4610        snapshot: &MultiBufferSnapshot,
 4611        position: Point,
 4612    ) -> Option<String> {
 4613        let mut chars = Vec::new();
 4614        let mut found_colon = false;
 4615        for char in snapshot.reversed_chars_at(position).take(100) {
 4616            // Found a possible emoji shortcode in the middle of the buffer
 4617            if found_colon {
 4618                if char.is_whitespace() {
 4619                    chars.reverse();
 4620                    return Some(chars.iter().collect());
 4621                }
 4622                // If the previous character is not a whitespace, we are in the middle of a word
 4623                // and we only want to complete the shortcode if the word is made up of other emojis
 4624                let mut containing_word = String::new();
 4625                for ch in snapshot
 4626                    .reversed_chars_at(position)
 4627                    .skip(chars.len() + 1)
 4628                    .take(100)
 4629                {
 4630                    if ch.is_whitespace() {
 4631                        break;
 4632                    }
 4633                    containing_word.push(ch);
 4634                }
 4635                let containing_word = containing_word.chars().rev().collect::<String>();
 4636                if util::word_consists_of_emojis(containing_word.as_str()) {
 4637                    chars.reverse();
 4638                    return Some(chars.iter().collect());
 4639                }
 4640            }
 4641
 4642            if char.is_whitespace() || !char.is_ascii() {
 4643                return None;
 4644            }
 4645            if char == ':' {
 4646                found_colon = true;
 4647            } else {
 4648                chars.push(char);
 4649            }
 4650        }
 4651        // Found a possible emoji shortcode at the beginning of the buffer
 4652        chars.reverse();
 4653        Some(chars.iter().collect())
 4654    }
 4655
 4656    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4658        self.transact(window, cx, |this, window, cx| {
 4659            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4660                let selections = this
 4661                    .selections
 4662                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4663                let multi_buffer = this.buffer.read(cx);
 4664                let buffer = multi_buffer.snapshot(cx);
 4665                selections
 4666                    .iter()
 4667                    .map(|selection| {
 4668                        let start_point = selection.start.to_point(&buffer);
 4669                        let mut existing_indent =
 4670                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4671                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4672                        let start = selection.start;
 4673                        let end = selection.end;
 4674                        let selection_is_empty = start == end;
 4675                        let language_scope = buffer.language_scope_at(start);
 4676                        let (
 4677                            comment_delimiter,
 4678                            doc_delimiter,
 4679                            insert_extra_newline,
 4680                            indent_on_newline,
 4681                            indent_on_extra_newline,
 4682                        ) = if let Some(language) = &language_scope {
 4683                            let mut insert_extra_newline =
 4684                                insert_extra_newline_brackets(&buffer, start..end, language)
 4685                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4686
 4687                            // Comment extension on newline is allowed only for cursor selections
 4688                            let comment_delimiter = maybe!({
 4689                                if !selection_is_empty {
 4690                                    return None;
 4691                                }
 4692
 4693                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4694                                    return None;
 4695                                }
 4696
 4697                                let delimiters = language.line_comment_prefixes();
 4698                                let max_len_of_delimiter =
 4699                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4700                                let (snapshot, range) =
 4701                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4702
 4703                                let num_of_whitespaces = snapshot
 4704                                    .chars_for_range(range.clone())
 4705                                    .take_while(|c| c.is_whitespace())
 4706                                    .count();
 4707                                let comment_candidate = snapshot
 4708                                    .chars_for_range(range.clone())
 4709                                    .skip(num_of_whitespaces)
 4710                                    .take(max_len_of_delimiter)
 4711                                    .collect::<String>();
 4712                                let (delimiter, trimmed_len) = delimiters
 4713                                    .iter()
 4714                                    .filter_map(|delimiter| {
 4715                                        let prefix = delimiter.trim_end();
 4716                                        if comment_candidate.starts_with(prefix) {
 4717                                            Some((delimiter, prefix.len()))
 4718                                        } else {
 4719                                            None
 4720                                        }
 4721                                    })
 4722                                    .max_by_key(|(_, len)| *len)?;
 4723
 4724                                if let Some(BlockCommentConfig {
 4725                                    start: block_start, ..
 4726                                }) = language.block_comment()
 4727                                {
 4728                                    let block_start_trimmed = block_start.trim_end();
 4729                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4730                                        let line_content = snapshot
 4731                                            .chars_for_range(range)
 4732                                            .skip(num_of_whitespaces)
 4733                                            .take(block_start_trimmed.len())
 4734                                            .collect::<String>();
 4735
 4736                                        if line_content.starts_with(block_start_trimmed) {
 4737                                            return None;
 4738                                        }
 4739                                    }
 4740                                }
 4741
 4742                                let cursor_is_placed_after_comment_marker =
 4743                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4744                                if cursor_is_placed_after_comment_marker {
 4745                                    Some(delimiter.clone())
 4746                                } else {
 4747                                    None
 4748                                }
 4749                            });
 4750
 4751                            let mut indent_on_newline = IndentSize::spaces(0);
 4752                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4753
 4754                            let doc_delimiter = maybe!({
 4755                                if !selection_is_empty {
 4756                                    return None;
 4757                                }
 4758
 4759                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4760                                    return None;
 4761                                }
 4762
 4763                                let BlockCommentConfig {
 4764                                    start: start_tag,
 4765                                    end: end_tag,
 4766                                    prefix: delimiter,
 4767                                    tab_size: len,
 4768                                } = language.documentation_comment()?;
 4769                                let is_within_block_comment = buffer
 4770                                    .language_scope_at(start_point)
 4771                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4772                                if !is_within_block_comment {
 4773                                    return None;
 4774                                }
 4775
 4776                                let (snapshot, range) =
 4777                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4778
 4779                                let num_of_whitespaces = snapshot
 4780                                    .chars_for_range(range.clone())
 4781                                    .take_while(|c| c.is_whitespace())
 4782                                    .count();
 4783
 4784                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4785                                let column = start_point.column;
 4786                                let cursor_is_after_start_tag = {
 4787                                    let start_tag_len = start_tag.len();
 4788                                    let start_tag_line = snapshot
 4789                                        .chars_for_range(range.clone())
 4790                                        .skip(num_of_whitespaces)
 4791                                        .take(start_tag_len)
 4792                                        .collect::<String>();
 4793                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4794                                        num_of_whitespaces + start_tag_len <= column as usize
 4795                                    } else {
 4796                                        false
 4797                                    }
 4798                                };
 4799
 4800                                let cursor_is_after_delimiter = {
 4801                                    let delimiter_trim = delimiter.trim_end();
 4802                                    let delimiter_line = snapshot
 4803                                        .chars_for_range(range.clone())
 4804                                        .skip(num_of_whitespaces)
 4805                                        .take(delimiter_trim.len())
 4806                                        .collect::<String>();
 4807                                    if delimiter_line.starts_with(delimiter_trim) {
 4808                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4809                                    } else {
 4810                                        false
 4811                                    }
 4812                                };
 4813
 4814                                let cursor_is_before_end_tag_if_exists = {
 4815                                    let mut char_position = 0u32;
 4816                                    let mut end_tag_offset = None;
 4817
 4818                                    'outer: for chunk in snapshot.text_for_range(range) {
 4819                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4820                                            let chars_before_match =
 4821                                                chunk[..byte_pos].chars().count() as u32;
 4822                                            end_tag_offset =
 4823                                                Some(char_position + chars_before_match);
 4824                                            break 'outer;
 4825                                        }
 4826                                        char_position += chunk.chars().count() as u32;
 4827                                    }
 4828
 4829                                    if let Some(end_tag_offset) = end_tag_offset {
 4830                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4831                                        if cursor_is_after_start_tag {
 4832                                            if cursor_is_before_end_tag {
 4833                                                insert_extra_newline = true;
 4834                                            }
 4835                                            let cursor_is_at_start_of_end_tag =
 4836                                                column == end_tag_offset;
 4837                                            if cursor_is_at_start_of_end_tag {
 4838                                                indent_on_extra_newline.len = *len;
 4839                                            }
 4840                                        }
 4841                                        cursor_is_before_end_tag
 4842                                    } else {
 4843                                        true
 4844                                    }
 4845                                };
 4846
 4847                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4848                                    && cursor_is_before_end_tag_if_exists
 4849                                {
 4850                                    if cursor_is_after_start_tag {
 4851                                        indent_on_newline.len = *len;
 4852                                    }
 4853                                    Some(delimiter.clone())
 4854                                } else {
 4855                                    None
 4856                                }
 4857                            });
 4858
 4859                            (
 4860                                comment_delimiter,
 4861                                doc_delimiter,
 4862                                insert_extra_newline,
 4863                                indent_on_newline,
 4864                                indent_on_extra_newline,
 4865                            )
 4866                        } else {
 4867                            (
 4868                                None,
 4869                                None,
 4870                                false,
 4871                                IndentSize::default(),
 4872                                IndentSize::default(),
 4873                            )
 4874                        };
 4875
 4876                        let prevent_auto_indent = doc_delimiter.is_some();
 4877                        let delimiter = comment_delimiter.or(doc_delimiter);
 4878
 4879                        let capacity_for_delimiter =
 4880                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4881                        let mut new_text = String::with_capacity(
 4882                            1 + capacity_for_delimiter
 4883                                + existing_indent.len as usize
 4884                                + indent_on_newline.len as usize
 4885                                + indent_on_extra_newline.len as usize,
 4886                        );
 4887                        new_text.push('\n');
 4888                        new_text.extend(existing_indent.chars());
 4889                        new_text.extend(indent_on_newline.chars());
 4890
 4891                        if let Some(delimiter) = &delimiter {
 4892                            new_text.push_str(delimiter);
 4893                        }
 4894
 4895                        if insert_extra_newline {
 4896                            new_text.push('\n');
 4897                            new_text.extend(existing_indent.chars());
 4898                            new_text.extend(indent_on_extra_newline.chars());
 4899                        }
 4900
 4901                        let anchor = buffer.anchor_after(end);
 4902                        let new_selection = selection.map(|_| anchor);
 4903                        (
 4904                            ((start..end, new_text), prevent_auto_indent),
 4905                            (insert_extra_newline, new_selection),
 4906                        )
 4907                    })
 4908                    .unzip()
 4909            };
 4910
 4911            let mut auto_indent_edits = Vec::new();
 4912            let mut edits = Vec::new();
 4913            for (edit, prevent_auto_indent) in edits_with_flags {
 4914                if prevent_auto_indent {
 4915                    edits.push(edit);
 4916                } else {
 4917                    auto_indent_edits.push(edit);
 4918                }
 4919            }
 4920            if !edits.is_empty() {
 4921                this.edit(edits, cx);
 4922            }
 4923            if !auto_indent_edits.is_empty() {
 4924                this.edit_with_autoindent(auto_indent_edits, cx);
 4925            }
 4926
 4927            let buffer = this.buffer.read(cx).snapshot(cx);
 4928            let new_selections = selection_info
 4929                .into_iter()
 4930                .map(|(extra_newline_inserted, new_selection)| {
 4931                    let mut cursor = new_selection.end.to_point(&buffer);
 4932                    if extra_newline_inserted {
 4933                        cursor.row -= 1;
 4934                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4935                    }
 4936                    new_selection.map(|_| cursor)
 4937                })
 4938                .collect();
 4939
 4940            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4941            this.refresh_edit_prediction(true, false, window, cx);
 4942        });
 4943    }
 4944
 4945    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4947
 4948        let buffer = self.buffer.read(cx);
 4949        let snapshot = buffer.snapshot(cx);
 4950
 4951        let mut edits = Vec::new();
 4952        let mut rows = Vec::new();
 4953
 4954        for (rows_inserted, selection) in self
 4955            .selections
 4956            .all_adjusted(&self.display_snapshot(cx))
 4957            .into_iter()
 4958            .enumerate()
 4959        {
 4960            let cursor = selection.head();
 4961            let row = cursor.row;
 4962
 4963            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4964
 4965            let newline = "\n".to_string();
 4966            edits.push((start_of_line..start_of_line, newline));
 4967
 4968            rows.push(row + rows_inserted as u32);
 4969        }
 4970
 4971        self.transact(window, cx, |editor, window, cx| {
 4972            editor.edit(edits, cx);
 4973
 4974            editor.change_selections(Default::default(), window, cx, |s| {
 4975                let mut index = 0;
 4976                s.move_cursors_with(|map, _, _| {
 4977                    let row = rows[index];
 4978                    index += 1;
 4979
 4980                    let point = Point::new(row, 0);
 4981                    let boundary = map.next_line_boundary(point).1;
 4982                    let clipped = map.clip_point(boundary, Bias::Left);
 4983
 4984                    (clipped, SelectionGoal::None)
 4985                });
 4986            });
 4987
 4988            let mut indent_edits = Vec::new();
 4989            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4990            for row in rows {
 4991                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4992                for (row, indent) in indents {
 4993                    if indent.len == 0 {
 4994                        continue;
 4995                    }
 4996
 4997                    let text = match indent.kind {
 4998                        IndentKind::Space => " ".repeat(indent.len as usize),
 4999                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5000                    };
 5001                    let point = Point::new(row.0, 0);
 5002                    indent_edits.push((point..point, text));
 5003                }
 5004            }
 5005            editor.edit(indent_edits, cx);
 5006        });
 5007    }
 5008
 5009    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5011
 5012        let buffer = self.buffer.read(cx);
 5013        let snapshot = buffer.snapshot(cx);
 5014
 5015        let mut edits = Vec::new();
 5016        let mut rows = Vec::new();
 5017        let mut rows_inserted = 0;
 5018
 5019        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5020            let cursor = selection.head();
 5021            let row = cursor.row;
 5022
 5023            let point = Point::new(row + 1, 0);
 5024            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5025
 5026            let newline = "\n".to_string();
 5027            edits.push((start_of_line..start_of_line, newline));
 5028
 5029            rows_inserted += 1;
 5030            rows.push(row + rows_inserted);
 5031        }
 5032
 5033        self.transact(window, cx, |editor, window, cx| {
 5034            editor.edit(edits, cx);
 5035
 5036            editor.change_selections(Default::default(), window, cx, |s| {
 5037                let mut index = 0;
 5038                s.move_cursors_with(|map, _, _| {
 5039                    let row = rows[index];
 5040                    index += 1;
 5041
 5042                    let point = Point::new(row, 0);
 5043                    let boundary = map.next_line_boundary(point).1;
 5044                    let clipped = map.clip_point(boundary, Bias::Left);
 5045
 5046                    (clipped, SelectionGoal::None)
 5047                });
 5048            });
 5049
 5050            let mut indent_edits = Vec::new();
 5051            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5052            for row in rows {
 5053                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5054                for (row, indent) in indents {
 5055                    if indent.len == 0 {
 5056                        continue;
 5057                    }
 5058
 5059                    let text = match indent.kind {
 5060                        IndentKind::Space => " ".repeat(indent.len as usize),
 5061                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5062                    };
 5063                    let point = Point::new(row.0, 0);
 5064                    indent_edits.push((point..point, text));
 5065                }
 5066            }
 5067            editor.edit(indent_edits, cx);
 5068        });
 5069    }
 5070
 5071    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5072        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5073            original_indent_columns: Vec::new(),
 5074        });
 5075        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5076    }
 5077
 5078    fn insert_with_autoindent_mode(
 5079        &mut self,
 5080        text: &str,
 5081        autoindent_mode: Option<AutoindentMode>,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        if self.read_only(cx) {
 5086            return;
 5087        }
 5088
 5089        let text: Arc<str> = text.into();
 5090        self.transact(window, cx, |this, window, cx| {
 5091            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5092            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5093                let anchors = {
 5094                    let snapshot = buffer.read(cx);
 5095                    old_selections
 5096                        .iter()
 5097                        .map(|s| {
 5098                            let anchor = snapshot.anchor_after(s.head());
 5099                            s.map(|_| anchor)
 5100                        })
 5101                        .collect::<Vec<_>>()
 5102                };
 5103                buffer.edit(
 5104                    old_selections
 5105                        .iter()
 5106                        .map(|s| (s.start..s.end, text.clone())),
 5107                    autoindent_mode,
 5108                    cx,
 5109                );
 5110                anchors
 5111            });
 5112
 5113            this.change_selections(Default::default(), window, cx, |s| {
 5114                s.select_anchors(selection_anchors);
 5115            });
 5116
 5117            cx.notify();
 5118        });
 5119    }
 5120
 5121    fn trigger_completion_on_input(
 5122        &mut self,
 5123        text: &str,
 5124        trigger_in_words: bool,
 5125        window: &mut Window,
 5126        cx: &mut Context<Self>,
 5127    ) {
 5128        let completions_source = self
 5129            .context_menu
 5130            .borrow()
 5131            .as_ref()
 5132            .and_then(|menu| match menu {
 5133                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5134                CodeContextMenu::CodeActions(_) => None,
 5135            });
 5136
 5137        match completions_source {
 5138            Some(CompletionsMenuSource::Words { .. }) => {
 5139                self.open_or_update_completions_menu(
 5140                    Some(CompletionsMenuSource::Words {
 5141                        ignore_threshold: false,
 5142                    }),
 5143                    None,
 5144                    trigger_in_words,
 5145                    window,
 5146                    cx,
 5147                );
 5148            }
 5149            _ => self.open_or_update_completions_menu(
 5150                None,
 5151                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5152                true,
 5153                window,
 5154                cx,
 5155            ),
 5156        }
 5157    }
 5158
 5159    /// If any empty selections is touching the start of its innermost containing autoclose
 5160    /// region, expand it to select the brackets.
 5161    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5162        let selections = self
 5163            .selections
 5164            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5165        let buffer = self.buffer.read(cx).read(cx);
 5166        let new_selections = self
 5167            .selections_with_autoclose_regions(selections, &buffer)
 5168            .map(|(mut selection, region)| {
 5169                if !selection.is_empty() {
 5170                    return selection;
 5171                }
 5172
 5173                if let Some(region) = region {
 5174                    let mut range = region.range.to_offset(&buffer);
 5175                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5176                        range.start -= region.pair.start.len();
 5177                        if buffer.contains_str_at(range.start, &region.pair.start)
 5178                            && buffer.contains_str_at(range.end, &region.pair.end)
 5179                        {
 5180                            range.end += region.pair.end.len();
 5181                            selection.start = range.start;
 5182                            selection.end = range.end;
 5183
 5184                            return selection;
 5185                        }
 5186                    }
 5187                }
 5188
 5189                let always_treat_brackets_as_autoclosed = buffer
 5190                    .language_settings_at(selection.start, cx)
 5191                    .always_treat_brackets_as_autoclosed;
 5192
 5193                if !always_treat_brackets_as_autoclosed {
 5194                    return selection;
 5195                }
 5196
 5197                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5198                    for (pair, enabled) in scope.brackets() {
 5199                        if !enabled || !pair.close {
 5200                            continue;
 5201                        }
 5202
 5203                        if buffer.contains_str_at(selection.start, &pair.end) {
 5204                            let pair_start_len = pair.start.len();
 5205                            if buffer.contains_str_at(
 5206                                selection.start.saturating_sub_usize(pair_start_len),
 5207                                &pair.start,
 5208                            ) {
 5209                                selection.start -= pair_start_len;
 5210                                selection.end += pair.end.len();
 5211
 5212                                return selection;
 5213                            }
 5214                        }
 5215                    }
 5216                }
 5217
 5218                selection
 5219            })
 5220            .collect();
 5221
 5222        drop(buffer);
 5223        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5224            selections.select(new_selections)
 5225        });
 5226    }
 5227
 5228    /// Iterate the given selections, and for each one, find the smallest surrounding
 5229    /// autoclose region. This uses the ordering of the selections and the autoclose
 5230    /// regions to avoid repeated comparisons.
 5231    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5232        &'a self,
 5233        selections: impl IntoIterator<Item = Selection<D>>,
 5234        buffer: &'a MultiBufferSnapshot,
 5235    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5236        let mut i = 0;
 5237        let mut regions = self.autoclose_regions.as_slice();
 5238        selections.into_iter().map(move |selection| {
 5239            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5240
 5241            let mut enclosing = None;
 5242            while let Some(pair_state) = regions.get(i) {
 5243                if pair_state.range.end.to_offset(buffer) < range.start {
 5244                    regions = &regions[i + 1..];
 5245                    i = 0;
 5246                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5247                    break;
 5248                } else {
 5249                    if pair_state.selection_id == selection.id {
 5250                        enclosing = Some(pair_state);
 5251                    }
 5252                    i += 1;
 5253                }
 5254            }
 5255
 5256            (selection, enclosing)
 5257        })
 5258    }
 5259
 5260    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5261    fn invalidate_autoclose_regions(
 5262        &mut self,
 5263        mut selections: &[Selection<Anchor>],
 5264        buffer: &MultiBufferSnapshot,
 5265    ) {
 5266        self.autoclose_regions.retain(|state| {
 5267            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5268                return false;
 5269            }
 5270
 5271            let mut i = 0;
 5272            while let Some(selection) = selections.get(i) {
 5273                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5274                    selections = &selections[1..];
 5275                    continue;
 5276                }
 5277                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5278                    break;
 5279                }
 5280                if selection.id == state.selection_id {
 5281                    return true;
 5282                } else {
 5283                    i += 1;
 5284                }
 5285            }
 5286            false
 5287        });
 5288    }
 5289
 5290    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5291        let offset = position.to_offset(buffer);
 5292        let (word_range, kind) =
 5293            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5294        if offset > word_range.start && kind == Some(CharKind::Word) {
 5295            Some(
 5296                buffer
 5297                    .text_for_range(word_range.start..offset)
 5298                    .collect::<String>(),
 5299            )
 5300        } else {
 5301            None
 5302        }
 5303    }
 5304
 5305    pub fn visible_excerpts(
 5306        &self,
 5307        cx: &mut Context<Editor>,
 5308    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5309        let Some(project) = self.project() else {
 5310            return HashMap::default();
 5311        };
 5312        let project = project.read(cx);
 5313        let multi_buffer = self.buffer().read(cx);
 5314        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5315        let multi_buffer_visible_start = self
 5316            .scroll_manager
 5317            .anchor()
 5318            .anchor
 5319            .to_point(&multi_buffer_snapshot);
 5320        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5321            multi_buffer_visible_start
 5322                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5323            Bias::Left,
 5324        );
 5325        multi_buffer_snapshot
 5326            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5327            .into_iter()
 5328            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5329            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5330                let buffer_file = project::File::from_dyn(buffer.file())?;
 5331                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5332                let worktree_entry = buffer_worktree
 5333                    .read(cx)
 5334                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5335                if worktree_entry.is_ignored {
 5336                    None
 5337                } else {
 5338                    Some((
 5339                        excerpt_id,
 5340                        (
 5341                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5342                            buffer.version().clone(),
 5343                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5344                        ),
 5345                    ))
 5346                }
 5347            })
 5348            .collect()
 5349    }
 5350
 5351    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5352        TextLayoutDetails {
 5353            text_system: window.text_system().clone(),
 5354            editor_style: self.style.clone().unwrap(),
 5355            rem_size: window.rem_size(),
 5356            scroll_anchor: self.scroll_manager.anchor(),
 5357            visible_rows: self.visible_line_count(),
 5358            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5359        }
 5360    }
 5361
 5362    fn trigger_on_type_formatting(
 5363        &self,
 5364        input: String,
 5365        window: &mut Window,
 5366        cx: &mut Context<Self>,
 5367    ) -> Option<Task<Result<()>>> {
 5368        if input.len() != 1 {
 5369            return None;
 5370        }
 5371
 5372        let project = self.project()?;
 5373        let position = self.selections.newest_anchor().head();
 5374        let (buffer, buffer_position) = self
 5375            .buffer
 5376            .read(cx)
 5377            .text_anchor_for_position(position, cx)?;
 5378
 5379        let settings = language_settings::language_settings(
 5380            buffer
 5381                .read(cx)
 5382                .language_at(buffer_position)
 5383                .map(|l| l.name()),
 5384            buffer.read(cx).file(),
 5385            cx,
 5386        );
 5387        if !settings.use_on_type_format {
 5388            return None;
 5389        }
 5390
 5391        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5392        // hence we do LSP request & edit on host side only — add formats to host's history.
 5393        let push_to_lsp_host_history = true;
 5394        // If this is not the host, append its history with new edits.
 5395        let push_to_client_history = project.read(cx).is_via_collab();
 5396
 5397        let on_type_formatting = project.update(cx, |project, cx| {
 5398            project.on_type_format(
 5399                buffer.clone(),
 5400                buffer_position,
 5401                input,
 5402                push_to_lsp_host_history,
 5403                cx,
 5404            )
 5405        });
 5406        Some(cx.spawn_in(window, async move |editor, cx| {
 5407            if let Some(transaction) = on_type_formatting.await? {
 5408                if push_to_client_history {
 5409                    buffer
 5410                        .update(cx, |buffer, _| {
 5411                            buffer.push_transaction(transaction, Instant::now());
 5412                            buffer.finalize_last_transaction();
 5413                        })
 5414                        .ok();
 5415                }
 5416                editor.update(cx, |editor, cx| {
 5417                    editor.refresh_document_highlights(cx);
 5418                })?;
 5419            }
 5420            Ok(())
 5421        }))
 5422    }
 5423
 5424    pub fn show_word_completions(
 5425        &mut self,
 5426        _: &ShowWordCompletions,
 5427        window: &mut Window,
 5428        cx: &mut Context<Self>,
 5429    ) {
 5430        self.open_or_update_completions_menu(
 5431            Some(CompletionsMenuSource::Words {
 5432                ignore_threshold: true,
 5433            }),
 5434            None,
 5435            false,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        _: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, None, false, window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<String>,
 5454        trigger_in_words: bool,
 5455        window: &mut Window,
 5456        cx: &mut Context<Self>,
 5457    ) {
 5458        if self.pending_rename.is_some() {
 5459            return;
 5460        }
 5461
 5462        let completions_source = self
 5463            .context_menu
 5464            .borrow()
 5465            .as_ref()
 5466            .and_then(|menu| match menu {
 5467                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5468                CodeContextMenu::CodeActions(_) => None,
 5469            });
 5470
 5471        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5472
 5473        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5474        // inserted and selected. To handle that case, the start of the selection is used so that
 5475        // the menu starts with all choices.
 5476        let position = self
 5477            .selections
 5478            .newest_anchor()
 5479            .start
 5480            .bias_right(&multibuffer_snapshot);
 5481        if position.diff_base_anchor.is_some() {
 5482            return;
 5483        }
 5484        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5485        let Some(buffer) = buffer_position
 5486            .text_anchor
 5487            .buffer_id
 5488            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5489        else {
 5490            return;
 5491        };
 5492        let buffer_snapshot = buffer.read(cx).snapshot();
 5493
 5494        let query: Option<Arc<String>> =
 5495            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5496                .map(|query| query.into());
 5497
 5498        drop(multibuffer_snapshot);
 5499
 5500        // Hide the current completions menu when query is empty. Without this, cached
 5501        // completions from before the trigger char may be reused (#32774).
 5502        if query.is_none() {
 5503            let menu_is_open = matches!(
 5504                self.context_menu.borrow().as_ref(),
 5505                Some(CodeContextMenu::Completions(_))
 5506            );
 5507            if menu_is_open {
 5508                self.hide_context_menu(window, cx);
 5509            }
 5510        }
 5511
 5512        let mut ignore_word_threshold = false;
 5513        let provider = match requested_source {
 5514            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5515            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5516                ignore_word_threshold = ignore_threshold;
 5517                None
 5518            }
 5519            Some(CompletionsMenuSource::SnippetChoices)
 5520            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5521                log::error!("bug: SnippetChoices requested_source is not handled");
 5522                None
 5523            }
 5524        };
 5525
 5526        let sort_completions = provider
 5527            .as_ref()
 5528            .is_some_and(|provider| provider.sort_completions());
 5529
 5530        let filter_completions = provider
 5531            .as_ref()
 5532            .is_none_or(|provider| provider.filter_completions());
 5533
 5534        let was_snippets_only = matches!(
 5535            completions_source,
 5536            Some(CompletionsMenuSource::SnippetsOnly)
 5537        );
 5538
 5539        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5540            if filter_completions {
 5541                menu.filter(
 5542                    query.clone().unwrap_or_default(),
 5543                    buffer_position.text_anchor,
 5544                    &buffer,
 5545                    provider.clone(),
 5546                    window,
 5547                    cx,
 5548                );
 5549            }
 5550            // When `is_incomplete` is false, no need to re-query completions when the current query
 5551            // is a suffix of the initial query.
 5552            let was_complete = !menu.is_incomplete;
 5553            if was_complete && !was_snippets_only {
 5554                // If the new query is a suffix of the old query (typing more characters) and
 5555                // the previous result was complete, the existing completions can be filtered.
 5556                //
 5557                // Note that snippet completions are always complete.
 5558                let query_matches = match (&menu.initial_query, &query) {
 5559                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5560                    (None, _) => true,
 5561                    _ => false,
 5562                };
 5563                if query_matches {
 5564                    let position_matches = if menu.initial_position == position {
 5565                        true
 5566                    } else {
 5567                        let snapshot = self.buffer.read(cx).read(cx);
 5568                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5569                    };
 5570                    if position_matches {
 5571                        return;
 5572                    }
 5573                }
 5574            }
 5575        };
 5576
 5577        let Anchor {
 5578            excerpt_id: buffer_excerpt_id,
 5579            text_anchor: buffer_position,
 5580            ..
 5581        } = buffer_position;
 5582
 5583        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5584            buffer_snapshot.surrounding_word(buffer_position, None)
 5585        {
 5586            let word_to_exclude = buffer_snapshot
 5587                .text_for_range(word_range.clone())
 5588                .collect::<String>();
 5589            (
 5590                buffer_snapshot.anchor_before(word_range.start)
 5591                    ..buffer_snapshot.anchor_after(buffer_position),
 5592                Some(word_to_exclude),
 5593            )
 5594        } else {
 5595            (buffer_position..buffer_position, None)
 5596        };
 5597
 5598        let language = buffer_snapshot
 5599            .language_at(buffer_position)
 5600            .map(|language| language.name());
 5601
 5602        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5603            .completions
 5604            .clone();
 5605
 5606        let show_completion_documentation = buffer_snapshot
 5607            .settings_at(buffer_position, cx)
 5608            .show_completion_documentation;
 5609
 5610        // The document can be large, so stay in reasonable bounds when searching for words,
 5611        // otherwise completion pop-up might be slow to appear.
 5612        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5613        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5614        let min_word_search = buffer_snapshot.clip_point(
 5615            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5616            Bias::Left,
 5617        );
 5618        let max_word_search = buffer_snapshot.clip_point(
 5619            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5620            Bias::Right,
 5621        );
 5622        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5623            ..buffer_snapshot.point_to_offset(max_word_search);
 5624
 5625        let skip_digits = query
 5626            .as_ref()
 5627            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5628
 5629        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5630            trigger.as_ref().is_none_or(|trigger| {
 5631                provider.is_completion_trigger(
 5632                    &buffer,
 5633                    position.text_anchor,
 5634                    trigger,
 5635                    trigger_in_words,
 5636                    completions_source.is_some(),
 5637                    cx,
 5638                )
 5639            })
 5640        });
 5641
 5642        let provider_responses = if let Some(provider) = &provider
 5643            && load_provider_completions
 5644        {
 5645            let trigger_character =
 5646                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5647            let completion_context = CompletionContext {
 5648                trigger_kind: match &trigger_character {
 5649                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5650                    None => CompletionTriggerKind::INVOKED,
 5651                },
 5652                trigger_character,
 5653            };
 5654
 5655            provider.completions(
 5656                buffer_excerpt_id,
 5657                &buffer,
 5658                buffer_position,
 5659                completion_context,
 5660                window,
 5661                cx,
 5662            )
 5663        } else {
 5664            Task::ready(Ok(Vec::new()))
 5665        };
 5666
 5667        let load_word_completions = if !self.word_completions_enabled {
 5668            false
 5669        } else if requested_source
 5670            == Some(CompletionsMenuSource::Words {
 5671                ignore_threshold: true,
 5672            })
 5673        {
 5674            true
 5675        } else {
 5676            load_provider_completions
 5677                && completion_settings.words != WordsCompletionMode::Disabled
 5678                && (ignore_word_threshold || {
 5679                    let words_min_length = completion_settings.words_min_length;
 5680                    // check whether word has at least `words_min_length` characters
 5681                    let query_chars = query.iter().flat_map(|q| q.chars());
 5682                    query_chars.take(words_min_length).count() == words_min_length
 5683                })
 5684        };
 5685
 5686        let mut words = if load_word_completions {
 5687            cx.background_spawn({
 5688                let buffer_snapshot = buffer_snapshot.clone();
 5689                async move {
 5690                    buffer_snapshot.words_in_range(WordsQuery {
 5691                        fuzzy_contents: None,
 5692                        range: word_search_range,
 5693                        skip_digits,
 5694                    })
 5695                }
 5696            })
 5697        } else {
 5698            Task::ready(BTreeMap::default())
 5699        };
 5700
 5701        let snippets = if let Some(provider) = &provider
 5702            && provider.show_snippets()
 5703            && let Some(project) = self.project()
 5704        {
 5705            let char_classifier = buffer_snapshot
 5706                .char_classifier_at(buffer_position)
 5707                .scope_context(Some(CharScopeContext::Completion));
 5708            project.update(cx, |project, cx| {
 5709                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5710            })
 5711        } else {
 5712            Task::ready(Ok(CompletionResponse {
 5713                completions: Vec::new(),
 5714                display_options: Default::default(),
 5715                is_incomplete: false,
 5716            }))
 5717        };
 5718
 5719        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5720
 5721        let id = post_inc(&mut self.next_completion_id);
 5722        let task = cx.spawn_in(window, async move |editor, cx| {
 5723            let Ok(()) = editor.update(cx, |this, _| {
 5724                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5725            }) else {
 5726                return;
 5727            };
 5728
 5729            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5730            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5731            let mut completions = Vec::new();
 5732            let mut is_incomplete = false;
 5733            let mut display_options: Option<CompletionDisplayOptions> = None;
 5734            if let Some(provider_responses) = provider_responses.await.log_err()
 5735                && !provider_responses.is_empty()
 5736            {
 5737                for response in provider_responses {
 5738                    completions.extend(response.completions);
 5739                    is_incomplete = is_incomplete || response.is_incomplete;
 5740                    match display_options.as_mut() {
 5741                        None => {
 5742                            display_options = Some(response.display_options);
 5743                        }
 5744                        Some(options) => options.merge(&response.display_options),
 5745                    }
 5746                }
 5747                if completion_settings.words == WordsCompletionMode::Fallback {
 5748                    words = Task::ready(BTreeMap::default());
 5749                }
 5750            }
 5751            let display_options = display_options.unwrap_or_default();
 5752
 5753            let mut words = words.await;
 5754            if let Some(word_to_exclude) = &word_to_exclude {
 5755                words.remove(word_to_exclude);
 5756            }
 5757            for lsp_completion in &completions {
 5758                words.remove(&lsp_completion.new_text);
 5759            }
 5760            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5761                replace_range: word_replace_range.clone(),
 5762                new_text: word.clone(),
 5763                label: CodeLabel::plain(word, None),
 5764                match_start: None,
 5765                snippet_deduplication_key: None,
 5766                icon_path: None,
 5767                documentation: None,
 5768                source: CompletionSource::BufferWord {
 5769                    word_range,
 5770                    resolved: false,
 5771                },
 5772                insert_text_mode: Some(InsertTextMode::AS_IS),
 5773                confirm: None,
 5774            }));
 5775
 5776            completions.extend(
 5777                snippets
 5778                    .await
 5779                    .into_iter()
 5780                    .flat_map(|response| response.completions),
 5781            );
 5782
 5783            let menu = if completions.is_empty() {
 5784                None
 5785            } else {
 5786                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5787                    let languages = editor
 5788                        .workspace
 5789                        .as_ref()
 5790                        .and_then(|(workspace, _)| workspace.upgrade())
 5791                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5792                    let menu = CompletionsMenu::new(
 5793                        id,
 5794                        requested_source.unwrap_or(if load_provider_completions {
 5795                            CompletionsMenuSource::Normal
 5796                        } else {
 5797                            CompletionsMenuSource::SnippetsOnly
 5798                        }),
 5799                        sort_completions,
 5800                        show_completion_documentation,
 5801                        position,
 5802                        query.clone(),
 5803                        is_incomplete,
 5804                        buffer.clone(),
 5805                        completions.into(),
 5806                        display_options,
 5807                        snippet_sort_order,
 5808                        languages,
 5809                        language,
 5810                        cx,
 5811                    );
 5812
 5813                    let query = if filter_completions { query } else { None };
 5814                    let matches_task = menu.do_async_filtering(
 5815                        query.unwrap_or_default(),
 5816                        buffer_position,
 5817                        &buffer,
 5818                        cx,
 5819                    );
 5820                    (menu, matches_task)
 5821                }) else {
 5822                    return;
 5823                };
 5824
 5825                let matches = matches_task.await;
 5826
 5827                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5828                    // Newer menu already set, so exit.
 5829                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5830                        editor.context_menu.borrow().as_ref()
 5831                        && prev_menu.id > id
 5832                    {
 5833                        return;
 5834                    };
 5835
 5836                    // Only valid to take prev_menu because either the new menu is immediately set
 5837                    // below, or the menu is hidden.
 5838                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5839                        editor.context_menu.borrow_mut().take()
 5840                    {
 5841                        let position_matches =
 5842                            if prev_menu.initial_position == menu.initial_position {
 5843                                true
 5844                            } else {
 5845                                let snapshot = editor.buffer.read(cx).read(cx);
 5846                                prev_menu.initial_position.to_offset(&snapshot)
 5847                                    == menu.initial_position.to_offset(&snapshot)
 5848                            };
 5849                        if position_matches {
 5850                            // Preserve markdown cache before `set_filter_results` because it will
 5851                            // try to populate the documentation cache.
 5852                            menu.preserve_markdown_cache(prev_menu);
 5853                        }
 5854                    };
 5855
 5856                    menu.set_filter_results(matches, provider, window, cx);
 5857                }) else {
 5858                    return;
 5859                };
 5860
 5861                menu.visible().then_some(menu)
 5862            };
 5863
 5864            editor
 5865                .update_in(cx, |editor, window, cx| {
 5866                    if editor.focus_handle.is_focused(window)
 5867                        && let Some(menu) = menu
 5868                    {
 5869                        *editor.context_menu.borrow_mut() =
 5870                            Some(CodeContextMenu::Completions(menu));
 5871
 5872                        crate::hover_popover::hide_hover(editor, cx);
 5873                        if editor.show_edit_predictions_in_menu() {
 5874                            editor.update_visible_edit_prediction(window, cx);
 5875                        } else {
 5876                            editor.discard_edit_prediction(false, cx);
 5877                        }
 5878
 5879                        cx.notify();
 5880                        return;
 5881                    }
 5882
 5883                    if editor.completion_tasks.len() <= 1 {
 5884                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5885                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5886                        // If it was already hidden and we don't show edit predictions in the menu,
 5887                        // we should also show the edit prediction when available.
 5888                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5889                            editor.update_visible_edit_prediction(window, cx);
 5890                        }
 5891                    }
 5892                })
 5893                .ok();
 5894        });
 5895
 5896        self.completion_tasks.push((id, task));
 5897    }
 5898
 5899    #[cfg(feature = "test-support")]
 5900    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5901        let menu = self.context_menu.borrow();
 5902        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5903            let completions = menu.completions.borrow();
 5904            Some(completions.to_vec())
 5905        } else {
 5906            None
 5907        }
 5908    }
 5909
 5910    pub fn with_completions_menu_matching_id<R>(
 5911        &self,
 5912        id: CompletionId,
 5913        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5914    ) -> R {
 5915        let mut context_menu = self.context_menu.borrow_mut();
 5916        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5917            return f(None);
 5918        };
 5919        if completions_menu.id != id {
 5920            return f(None);
 5921        }
 5922        f(Some(completions_menu))
 5923    }
 5924
 5925    pub fn confirm_completion(
 5926        &mut self,
 5927        action: &ConfirmCompletion,
 5928        window: &mut Window,
 5929        cx: &mut Context<Self>,
 5930    ) -> Option<Task<Result<()>>> {
 5931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5932        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5933    }
 5934
 5935    pub fn confirm_completion_insert(
 5936        &mut self,
 5937        _: &ConfirmCompletionInsert,
 5938        window: &mut Window,
 5939        cx: &mut Context<Self>,
 5940    ) -> Option<Task<Result<()>>> {
 5941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5942        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5943    }
 5944
 5945    pub fn confirm_completion_replace(
 5946        &mut self,
 5947        _: &ConfirmCompletionReplace,
 5948        window: &mut Window,
 5949        cx: &mut Context<Self>,
 5950    ) -> Option<Task<Result<()>>> {
 5951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5952        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5953    }
 5954
 5955    pub fn compose_completion(
 5956        &mut self,
 5957        action: &ComposeCompletion,
 5958        window: &mut Window,
 5959        cx: &mut Context<Self>,
 5960    ) -> Option<Task<Result<()>>> {
 5961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5962        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5963    }
 5964
 5965    fn do_completion(
 5966        &mut self,
 5967        item_ix: Option<usize>,
 5968        intent: CompletionIntent,
 5969        window: &mut Window,
 5970        cx: &mut Context<Editor>,
 5971    ) -> Option<Task<Result<()>>> {
 5972        use language::ToOffset as _;
 5973
 5974        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5975        else {
 5976            return None;
 5977        };
 5978
 5979        let candidate_id = {
 5980            let entries = completions_menu.entries.borrow();
 5981            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5982            if self.show_edit_predictions_in_menu() {
 5983                self.discard_edit_prediction(true, cx);
 5984            }
 5985            mat.candidate_id
 5986        };
 5987
 5988        let completion = completions_menu
 5989            .completions
 5990            .borrow()
 5991            .get(candidate_id)?
 5992            .clone();
 5993        cx.stop_propagation();
 5994
 5995        let buffer_handle = completions_menu.buffer.clone();
 5996
 5997        let CompletionEdit {
 5998            new_text,
 5999            snippet,
 6000            replace_range,
 6001        } = process_completion_for_edit(
 6002            &completion,
 6003            intent,
 6004            &buffer_handle,
 6005            &completions_menu.initial_position.text_anchor,
 6006            cx,
 6007        );
 6008
 6009        let buffer = buffer_handle.read(cx);
 6010        let snapshot = self.buffer.read(cx).snapshot(cx);
 6011        let newest_anchor = self.selections.newest_anchor();
 6012        let replace_range_multibuffer = {
 6013            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6014            excerpt.map_range_from_buffer(replace_range.clone())
 6015        };
 6016        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6017            return None;
 6018        }
 6019
 6020        let old_text = buffer
 6021            .text_for_range(replace_range.clone())
 6022            .collect::<String>();
 6023        let lookbehind = newest_anchor
 6024            .start
 6025            .text_anchor
 6026            .to_offset(buffer)
 6027            .saturating_sub(replace_range.start.0);
 6028        let lookahead = replace_range
 6029            .end
 6030            .0
 6031            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6032        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6033        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6034
 6035        let selections = self
 6036            .selections
 6037            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6038        let mut ranges = Vec::new();
 6039        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6040
 6041        for selection in &selections {
 6042            let range = if selection.id == newest_anchor.id {
 6043                replace_range_multibuffer.clone()
 6044            } else {
 6045                let mut range = selection.range();
 6046
 6047                // if prefix is present, don't duplicate it
 6048                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6049                    range.start = range.start.saturating_sub_usize(lookbehind);
 6050
 6051                    // if suffix is also present, mimic the newest cursor and replace it
 6052                    if selection.id != newest_anchor.id
 6053                        && snapshot.contains_str_at(range.end, suffix)
 6054                    {
 6055                        range.end += lookahead;
 6056                    }
 6057                }
 6058                range
 6059            };
 6060
 6061            ranges.push(range.clone());
 6062
 6063            if !self.linked_edit_ranges.is_empty() {
 6064                let start_anchor = snapshot.anchor_before(range.start);
 6065                let end_anchor = snapshot.anchor_after(range.end);
 6066                if let Some(ranges) = self
 6067                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6068                {
 6069                    for (buffer, edits) in ranges {
 6070                        linked_edits
 6071                            .entry(buffer.clone())
 6072                            .or_default()
 6073                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6074                    }
 6075                }
 6076            }
 6077        }
 6078
 6079        let common_prefix_len = old_text
 6080            .chars()
 6081            .zip(new_text.chars())
 6082            .take_while(|(a, b)| a == b)
 6083            .map(|(a, _)| a.len_utf8())
 6084            .sum::<usize>();
 6085
 6086        cx.emit(EditorEvent::InputHandled {
 6087            utf16_range_to_replace: None,
 6088            text: new_text[common_prefix_len..].into(),
 6089        });
 6090
 6091        self.transact(window, cx, |editor, window, cx| {
 6092            if let Some(mut snippet) = snippet {
 6093                snippet.text = new_text.to_string();
 6094                editor
 6095                    .insert_snippet(&ranges, snippet, window, cx)
 6096                    .log_err();
 6097            } else {
 6098                editor.buffer.update(cx, |multi_buffer, cx| {
 6099                    let auto_indent = match completion.insert_text_mode {
 6100                        Some(InsertTextMode::AS_IS) => None,
 6101                        _ => editor.autoindent_mode.clone(),
 6102                    };
 6103                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6104                    multi_buffer.edit(edits, auto_indent, cx);
 6105                });
 6106            }
 6107            for (buffer, edits) in linked_edits {
 6108                buffer.update(cx, |buffer, cx| {
 6109                    let snapshot = buffer.snapshot();
 6110                    let edits = edits
 6111                        .into_iter()
 6112                        .map(|(range, text)| {
 6113                            use text::ToPoint as TP;
 6114                            let end_point = TP::to_point(&range.end, &snapshot);
 6115                            let start_point = TP::to_point(&range.start, &snapshot);
 6116                            (start_point..end_point, text)
 6117                        })
 6118                        .sorted_by_key(|(range, _)| range.start);
 6119                    buffer.edit(edits, None, cx);
 6120                })
 6121            }
 6122
 6123            editor.refresh_edit_prediction(true, false, window, cx);
 6124        });
 6125        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6126
 6127        let show_new_completions_on_confirm = completion
 6128            .confirm
 6129            .as_ref()
 6130            .is_some_and(|confirm| confirm(intent, window, cx));
 6131        if show_new_completions_on_confirm {
 6132            self.open_or_update_completions_menu(None, None, false, window, cx);
 6133        }
 6134
 6135        let provider = self.completion_provider.as_ref()?;
 6136        drop(completion);
 6137        let apply_edits = provider.apply_additional_edits_for_completion(
 6138            buffer_handle,
 6139            completions_menu.completions.clone(),
 6140            candidate_id,
 6141            true,
 6142            cx,
 6143        );
 6144
 6145        let editor_settings = EditorSettings::get_global(cx);
 6146        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6147            // After the code completion is finished, users often want to know what signatures are needed.
 6148            // so we should automatically call signature_help
 6149            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6150        }
 6151
 6152        Some(cx.foreground_executor().spawn(async move {
 6153            apply_edits.await?;
 6154            Ok(())
 6155        }))
 6156    }
 6157
 6158    pub fn toggle_code_actions(
 6159        &mut self,
 6160        action: &ToggleCodeActions,
 6161        window: &mut Window,
 6162        cx: &mut Context<Self>,
 6163    ) {
 6164        let quick_launch = action.quick_launch;
 6165        let mut context_menu = self.context_menu.borrow_mut();
 6166        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6167            if code_actions.deployed_from == action.deployed_from {
 6168                // Toggle if we're selecting the same one
 6169                *context_menu = None;
 6170                cx.notify();
 6171                return;
 6172            } else {
 6173                // Otherwise, clear it and start a new one
 6174                *context_menu = None;
 6175                cx.notify();
 6176            }
 6177        }
 6178        drop(context_menu);
 6179        let snapshot = self.snapshot(window, cx);
 6180        let deployed_from = action.deployed_from.clone();
 6181        let action = action.clone();
 6182        self.completion_tasks.clear();
 6183        self.discard_edit_prediction(false, cx);
 6184
 6185        let multibuffer_point = match &action.deployed_from {
 6186            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6187                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6188            }
 6189            _ => self
 6190                .selections
 6191                .newest::<Point>(&snapshot.display_snapshot)
 6192                .head(),
 6193        };
 6194        let Some((buffer, buffer_row)) = snapshot
 6195            .buffer_snapshot()
 6196            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6197            .and_then(|(buffer_snapshot, range)| {
 6198                self.buffer()
 6199                    .read(cx)
 6200                    .buffer(buffer_snapshot.remote_id())
 6201                    .map(|buffer| (buffer, range.start.row))
 6202            })
 6203        else {
 6204            return;
 6205        };
 6206        let buffer_id = buffer.read(cx).remote_id();
 6207        let tasks = self
 6208            .tasks
 6209            .get(&(buffer_id, buffer_row))
 6210            .map(|t| Arc::new(t.to_owned()));
 6211
 6212        if !self.focus_handle.is_focused(window) {
 6213            return;
 6214        }
 6215        let project = self.project.clone();
 6216
 6217        let code_actions_task = match deployed_from {
 6218            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6219            _ => self.code_actions(buffer_row, window, cx),
 6220        };
 6221
 6222        let runnable_task = match deployed_from {
 6223            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6224            _ => {
 6225                let mut task_context_task = Task::ready(None);
 6226                if let Some(tasks) = &tasks
 6227                    && let Some(project) = project
 6228                {
 6229                    task_context_task =
 6230                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6231                }
 6232
 6233                cx.spawn_in(window, {
 6234                    let buffer = buffer.clone();
 6235                    async move |editor, cx| {
 6236                        let task_context = task_context_task.await;
 6237
 6238                        let resolved_tasks =
 6239                            tasks
 6240                                .zip(task_context.clone())
 6241                                .map(|(tasks, task_context)| ResolvedTasks {
 6242                                    templates: tasks.resolve(&task_context).collect(),
 6243                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6244                                        multibuffer_point.row,
 6245                                        tasks.column,
 6246                                    )),
 6247                                });
 6248                        let debug_scenarios = editor
 6249                            .update(cx, |editor, cx| {
 6250                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6251                            })?
 6252                            .await;
 6253                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6254                    }
 6255                })
 6256            }
 6257        };
 6258
 6259        cx.spawn_in(window, async move |editor, cx| {
 6260            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6261            let code_actions = code_actions_task.await;
 6262            let spawn_straight_away = quick_launch
 6263                && resolved_tasks
 6264                    .as_ref()
 6265                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6266                && code_actions
 6267                    .as_ref()
 6268                    .is_none_or(|actions| actions.is_empty())
 6269                && debug_scenarios.is_empty();
 6270
 6271            editor.update_in(cx, |editor, window, cx| {
 6272                crate::hover_popover::hide_hover(editor, cx);
 6273                let actions = CodeActionContents::new(
 6274                    resolved_tasks,
 6275                    code_actions,
 6276                    debug_scenarios,
 6277                    task_context.unwrap_or_default(),
 6278                );
 6279
 6280                // Don't show the menu if there are no actions available
 6281                if actions.is_empty() {
 6282                    cx.notify();
 6283                    return Task::ready(Ok(()));
 6284                }
 6285
 6286                *editor.context_menu.borrow_mut() =
 6287                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6288                        buffer,
 6289                        actions,
 6290                        selected_item: Default::default(),
 6291                        scroll_handle: UniformListScrollHandle::default(),
 6292                        deployed_from,
 6293                    }));
 6294                cx.notify();
 6295                if spawn_straight_away
 6296                    && let Some(task) = editor.confirm_code_action(
 6297                        &ConfirmCodeAction { item_ix: Some(0) },
 6298                        window,
 6299                        cx,
 6300                    )
 6301                {
 6302                    return task;
 6303                }
 6304
 6305                Task::ready(Ok(()))
 6306            })
 6307        })
 6308        .detach_and_log_err(cx);
 6309    }
 6310
 6311    fn debug_scenarios(
 6312        &mut self,
 6313        resolved_tasks: &Option<ResolvedTasks>,
 6314        buffer: &Entity<Buffer>,
 6315        cx: &mut App,
 6316    ) -> Task<Vec<task::DebugScenario>> {
 6317        maybe!({
 6318            let project = self.project()?;
 6319            let dap_store = project.read(cx).dap_store();
 6320            let mut scenarios = vec![];
 6321            let resolved_tasks = resolved_tasks.as_ref()?;
 6322            let buffer = buffer.read(cx);
 6323            let language = buffer.language()?;
 6324            let file = buffer.file();
 6325            let debug_adapter = language_settings(language.name().into(), file, cx)
 6326                .debuggers
 6327                .first()
 6328                .map(SharedString::from)
 6329                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6330
 6331            dap_store.update(cx, |dap_store, cx| {
 6332                for (_, task) in &resolved_tasks.templates {
 6333                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6334                        task.original_task().clone(),
 6335                        debug_adapter.clone().into(),
 6336                        task.display_label().to_owned().into(),
 6337                        cx,
 6338                    );
 6339                    scenarios.push(maybe_scenario);
 6340                }
 6341            });
 6342            Some(cx.background_spawn(async move {
 6343                futures::future::join_all(scenarios)
 6344                    .await
 6345                    .into_iter()
 6346                    .flatten()
 6347                    .collect::<Vec<_>>()
 6348            }))
 6349        })
 6350        .unwrap_or_else(|| Task::ready(vec![]))
 6351    }
 6352
 6353    fn code_actions(
 6354        &mut self,
 6355        buffer_row: u32,
 6356        window: &mut Window,
 6357        cx: &mut Context<Self>,
 6358    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6359        let mut task = self.code_actions_task.take();
 6360        cx.spawn_in(window, async move |editor, cx| {
 6361            while let Some(prev_task) = task {
 6362                prev_task.await.log_err();
 6363                task = editor
 6364                    .update(cx, |this, _| this.code_actions_task.take())
 6365                    .ok()?;
 6366            }
 6367
 6368            editor
 6369                .update(cx, |editor, cx| {
 6370                    editor
 6371                        .available_code_actions
 6372                        .clone()
 6373                        .and_then(|(location, code_actions)| {
 6374                            let snapshot = location.buffer.read(cx).snapshot();
 6375                            let point_range = location.range.to_point(&snapshot);
 6376                            let point_range = point_range.start.row..=point_range.end.row;
 6377                            if point_range.contains(&buffer_row) {
 6378                                Some(code_actions)
 6379                            } else {
 6380                                None
 6381                            }
 6382                        })
 6383                })
 6384                .ok()
 6385                .flatten()
 6386        })
 6387    }
 6388
 6389    pub fn confirm_code_action(
 6390        &mut self,
 6391        action: &ConfirmCodeAction,
 6392        window: &mut Window,
 6393        cx: &mut Context<Self>,
 6394    ) -> Option<Task<Result<()>>> {
 6395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6396
 6397        let actions_menu =
 6398            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6399                menu
 6400            } else {
 6401                return None;
 6402            };
 6403
 6404        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6405        let action = actions_menu.actions.get(action_ix)?;
 6406        let title = action.label();
 6407        let buffer = actions_menu.buffer;
 6408        let workspace = self.workspace()?;
 6409
 6410        match action {
 6411            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6412                workspace.update(cx, |workspace, cx| {
 6413                    workspace.schedule_resolved_task(
 6414                        task_source_kind,
 6415                        resolved_task,
 6416                        false,
 6417                        window,
 6418                        cx,
 6419                    );
 6420
 6421                    Some(Task::ready(Ok(())))
 6422                })
 6423            }
 6424            CodeActionsItem::CodeAction {
 6425                excerpt_id,
 6426                action,
 6427                provider,
 6428            } => {
 6429                let apply_code_action =
 6430                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6431                let workspace = workspace.downgrade();
 6432                Some(cx.spawn_in(window, async move |editor, cx| {
 6433                    let project_transaction = apply_code_action.await?;
 6434                    Self::open_project_transaction(
 6435                        &editor,
 6436                        workspace,
 6437                        project_transaction,
 6438                        title,
 6439                        cx,
 6440                    )
 6441                    .await
 6442                }))
 6443            }
 6444            CodeActionsItem::DebugScenario(scenario) => {
 6445                let context = actions_menu.actions.context;
 6446
 6447                workspace.update(cx, |workspace, cx| {
 6448                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6449                    workspace.start_debug_session(
 6450                        scenario,
 6451                        context,
 6452                        Some(buffer),
 6453                        None,
 6454                        window,
 6455                        cx,
 6456                    );
 6457                });
 6458                Some(Task::ready(Ok(())))
 6459            }
 6460        }
 6461    }
 6462
 6463    pub async fn open_project_transaction(
 6464        editor: &WeakEntity<Editor>,
 6465        workspace: WeakEntity<Workspace>,
 6466        transaction: ProjectTransaction,
 6467        title: String,
 6468        cx: &mut AsyncWindowContext,
 6469    ) -> Result<()> {
 6470        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6471        cx.update(|_, cx| {
 6472            entries.sort_unstable_by_key(|(buffer, _)| {
 6473                buffer.read(cx).file().map(|f| f.path().clone())
 6474            });
 6475        })?;
 6476        if entries.is_empty() {
 6477            return Ok(());
 6478        }
 6479
 6480        // If the project transaction's edits are all contained within this editor, then
 6481        // avoid opening a new editor to display them.
 6482
 6483        if let [(buffer, transaction)] = &*entries {
 6484            let excerpt = editor.update(cx, |editor, cx| {
 6485                editor
 6486                    .buffer()
 6487                    .read(cx)
 6488                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6489            })?;
 6490            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6491                && excerpted_buffer == *buffer
 6492            {
 6493                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6494                    let excerpt_range = excerpt_range.to_offset(buffer);
 6495                    buffer
 6496                        .edited_ranges_for_transaction::<usize>(transaction)
 6497                        .all(|range| {
 6498                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6499                        })
 6500                })?;
 6501
 6502                if all_edits_within_excerpt {
 6503                    return Ok(());
 6504                }
 6505            }
 6506        }
 6507
 6508        let mut ranges_to_highlight = Vec::new();
 6509        let excerpt_buffer = cx.new(|cx| {
 6510            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6511            for (buffer_handle, transaction) in &entries {
 6512                let edited_ranges = buffer_handle
 6513                    .read(cx)
 6514                    .edited_ranges_for_transaction::<Point>(transaction)
 6515                    .collect::<Vec<_>>();
 6516                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6517                    PathKey::for_buffer(buffer_handle, cx),
 6518                    buffer_handle.clone(),
 6519                    edited_ranges,
 6520                    multibuffer_context_lines(cx),
 6521                    cx,
 6522                );
 6523
 6524                ranges_to_highlight.extend(ranges);
 6525            }
 6526            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6527            multibuffer
 6528        })?;
 6529
 6530        workspace.update_in(cx, |workspace, window, cx| {
 6531            let project = workspace.project().clone();
 6532            let editor =
 6533                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6534            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6535            editor.update(cx, |editor, cx| {
 6536                editor.highlight_background::<Self>(
 6537                    &ranges_to_highlight,
 6538                    |theme| theme.colors().editor_highlighted_line_background,
 6539                    cx,
 6540                );
 6541            });
 6542        })?;
 6543
 6544        Ok(())
 6545    }
 6546
 6547    pub fn clear_code_action_providers(&mut self) {
 6548        self.code_action_providers.clear();
 6549        self.available_code_actions.take();
 6550    }
 6551
 6552    pub fn add_code_action_provider(
 6553        &mut self,
 6554        provider: Rc<dyn CodeActionProvider>,
 6555        window: &mut Window,
 6556        cx: &mut Context<Self>,
 6557    ) {
 6558        if self
 6559            .code_action_providers
 6560            .iter()
 6561            .any(|existing_provider| existing_provider.id() == provider.id())
 6562        {
 6563            return;
 6564        }
 6565
 6566        self.code_action_providers.push(provider);
 6567        self.refresh_code_actions(window, cx);
 6568    }
 6569
 6570    pub fn remove_code_action_provider(
 6571        &mut self,
 6572        id: Arc<str>,
 6573        window: &mut Window,
 6574        cx: &mut Context<Self>,
 6575    ) {
 6576        self.code_action_providers
 6577            .retain(|provider| provider.id() != id);
 6578        self.refresh_code_actions(window, cx);
 6579    }
 6580
 6581    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6582        !self.code_action_providers.is_empty()
 6583            && EditorSettings::get_global(cx).toolbar.code_actions
 6584    }
 6585
 6586    pub fn has_available_code_actions(&self) -> bool {
 6587        self.available_code_actions
 6588            .as_ref()
 6589            .is_some_and(|(_, actions)| !actions.is_empty())
 6590    }
 6591
 6592    fn render_inline_code_actions(
 6593        &self,
 6594        icon_size: ui::IconSize,
 6595        display_row: DisplayRow,
 6596        is_active: bool,
 6597        cx: &mut Context<Self>,
 6598    ) -> AnyElement {
 6599        let show_tooltip = !self.context_menu_visible();
 6600        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6601            .icon_size(icon_size)
 6602            .shape(ui::IconButtonShape::Square)
 6603            .icon_color(ui::Color::Hidden)
 6604            .toggle_state(is_active)
 6605            .when(show_tooltip, |this| {
 6606                this.tooltip({
 6607                    let focus_handle = self.focus_handle.clone();
 6608                    move |_window, cx| {
 6609                        Tooltip::for_action_in(
 6610                            "Toggle Code Actions",
 6611                            &ToggleCodeActions {
 6612                                deployed_from: None,
 6613                                quick_launch: false,
 6614                            },
 6615                            &focus_handle,
 6616                            cx,
 6617                        )
 6618                    }
 6619                })
 6620            })
 6621            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6622                window.focus(&editor.focus_handle(cx));
 6623                editor.toggle_code_actions(
 6624                    &crate::actions::ToggleCodeActions {
 6625                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6626                            display_row,
 6627                        )),
 6628                        quick_launch: false,
 6629                    },
 6630                    window,
 6631                    cx,
 6632                );
 6633            }))
 6634            .into_any_element()
 6635    }
 6636
 6637    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6638        &self.context_menu
 6639    }
 6640
 6641    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6642        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6643            cx.background_executor()
 6644                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6645                .await;
 6646
 6647            let (start_buffer, start, _, end, newest_selection) = this
 6648                .update(cx, |this, cx| {
 6649                    let newest_selection = this.selections.newest_anchor().clone();
 6650                    if newest_selection.head().diff_base_anchor.is_some() {
 6651                        return None;
 6652                    }
 6653                    let display_snapshot = this.display_snapshot(cx);
 6654                    let newest_selection_adjusted =
 6655                        this.selections.newest_adjusted(&display_snapshot);
 6656                    let buffer = this.buffer.read(cx);
 6657
 6658                    let (start_buffer, start) =
 6659                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6660                    let (end_buffer, end) =
 6661                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6662
 6663                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6664                })?
 6665                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6666                .context(
 6667                    "Expected selection to lie in a single buffer when refreshing code actions",
 6668                )?;
 6669            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6670                let providers = this.code_action_providers.clone();
 6671                let tasks = this
 6672                    .code_action_providers
 6673                    .iter()
 6674                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6675                    .collect::<Vec<_>>();
 6676                (providers, tasks)
 6677            })?;
 6678
 6679            let mut actions = Vec::new();
 6680            for (provider, provider_actions) in
 6681                providers.into_iter().zip(future::join_all(tasks).await)
 6682            {
 6683                if let Some(provider_actions) = provider_actions.log_err() {
 6684                    actions.extend(provider_actions.into_iter().map(|action| {
 6685                        AvailableCodeAction {
 6686                            excerpt_id: newest_selection.start.excerpt_id,
 6687                            action,
 6688                            provider: provider.clone(),
 6689                        }
 6690                    }));
 6691                }
 6692            }
 6693
 6694            this.update(cx, |this, cx| {
 6695                this.available_code_actions = if actions.is_empty() {
 6696                    None
 6697                } else {
 6698                    Some((
 6699                        Location {
 6700                            buffer: start_buffer,
 6701                            range: start..end,
 6702                        },
 6703                        actions.into(),
 6704                    ))
 6705                };
 6706                cx.notify();
 6707            })
 6708        }));
 6709    }
 6710
 6711    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6712        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6713            self.show_git_blame_inline = false;
 6714
 6715            self.show_git_blame_inline_delay_task =
 6716                Some(cx.spawn_in(window, async move |this, cx| {
 6717                    cx.background_executor().timer(delay).await;
 6718
 6719                    this.update(cx, |this, cx| {
 6720                        this.show_git_blame_inline = true;
 6721                        cx.notify();
 6722                    })
 6723                    .log_err();
 6724                }));
 6725        }
 6726    }
 6727
 6728    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6729        let snapshot = self.snapshot(window, cx);
 6730        let cursor = self
 6731            .selections
 6732            .newest::<Point>(&snapshot.display_snapshot)
 6733            .head();
 6734        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6735        else {
 6736            return;
 6737        };
 6738
 6739        let Some(blame) = self.blame.as_ref() else {
 6740            return;
 6741        };
 6742
 6743        let row_info = RowInfo {
 6744            buffer_id: Some(buffer.remote_id()),
 6745            buffer_row: Some(point.row),
 6746            ..Default::default()
 6747        };
 6748        let Some((buffer, blame_entry)) = blame
 6749            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6750            .flatten()
 6751        else {
 6752            return;
 6753        };
 6754
 6755        let anchor = self.selections.newest_anchor().head();
 6756        let position = self.to_pixel_point(anchor, &snapshot, window);
 6757        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6758            self.show_blame_popover(
 6759                buffer,
 6760                &blame_entry,
 6761                position + last_bounds.origin,
 6762                true,
 6763                cx,
 6764            );
 6765        };
 6766    }
 6767
 6768    fn show_blame_popover(
 6769        &mut self,
 6770        buffer: BufferId,
 6771        blame_entry: &BlameEntry,
 6772        position: gpui::Point<Pixels>,
 6773        ignore_timeout: bool,
 6774        cx: &mut Context<Self>,
 6775    ) {
 6776        if let Some(state) = &mut self.inline_blame_popover {
 6777            state.hide_task.take();
 6778        } else {
 6779            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6780            let blame_entry = blame_entry.clone();
 6781            let show_task = cx.spawn(async move |editor, cx| {
 6782                if !ignore_timeout {
 6783                    cx.background_executor()
 6784                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6785                        .await;
 6786                }
 6787                editor
 6788                    .update(cx, |editor, cx| {
 6789                        editor.inline_blame_popover_show_task.take();
 6790                        let Some(blame) = editor.blame.as_ref() else {
 6791                            return;
 6792                        };
 6793                        let blame = blame.read(cx);
 6794                        let details = blame.details_for_entry(buffer, &blame_entry);
 6795                        let markdown = cx.new(|cx| {
 6796                            Markdown::new(
 6797                                details
 6798                                    .as_ref()
 6799                                    .map(|message| message.message.clone())
 6800                                    .unwrap_or_default(),
 6801                                None,
 6802                                None,
 6803                                cx,
 6804                            )
 6805                        });
 6806                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6807                            position,
 6808                            hide_task: None,
 6809                            popover_bounds: None,
 6810                            popover_state: InlineBlamePopoverState {
 6811                                scroll_handle: ScrollHandle::new(),
 6812                                commit_message: details,
 6813                                markdown,
 6814                            },
 6815                            keyboard_grace: ignore_timeout,
 6816                        });
 6817                        cx.notify();
 6818                    })
 6819                    .ok();
 6820            });
 6821            self.inline_blame_popover_show_task = Some(show_task);
 6822        }
 6823    }
 6824
 6825    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6826        self.inline_blame_popover_show_task.take();
 6827        if let Some(state) = &mut self.inline_blame_popover {
 6828            let hide_task = cx.spawn(async move |editor, cx| {
 6829                if !ignore_timeout {
 6830                    cx.background_executor()
 6831                        .timer(std::time::Duration::from_millis(100))
 6832                        .await;
 6833                }
 6834                editor
 6835                    .update(cx, |editor, cx| {
 6836                        editor.inline_blame_popover.take();
 6837                        cx.notify();
 6838                    })
 6839                    .ok();
 6840            });
 6841            state.hide_task = Some(hide_task);
 6842            true
 6843        } else {
 6844            false
 6845        }
 6846    }
 6847
 6848    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6849        if self.pending_rename.is_some() {
 6850            return None;
 6851        }
 6852
 6853        let provider = self.semantics_provider.clone()?;
 6854        let buffer = self.buffer.read(cx);
 6855        let newest_selection = self.selections.newest_anchor().clone();
 6856        let cursor_position = newest_selection.head();
 6857        let (cursor_buffer, cursor_buffer_position) =
 6858            buffer.text_anchor_for_position(cursor_position, cx)?;
 6859        let (tail_buffer, tail_buffer_position) =
 6860            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6861        if cursor_buffer != tail_buffer {
 6862            return None;
 6863        }
 6864
 6865        let snapshot = cursor_buffer.read(cx).snapshot();
 6866        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6867        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6868        if start_word_range != end_word_range {
 6869            self.document_highlights_task.take();
 6870            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6871            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6872            return None;
 6873        }
 6874
 6875        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6876        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6877            cx.background_executor()
 6878                .timer(Duration::from_millis(debounce))
 6879                .await;
 6880
 6881            let highlights = if let Some(highlights) = cx
 6882                .update(|cx| {
 6883                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6884                })
 6885                .ok()
 6886                .flatten()
 6887            {
 6888                highlights.await.log_err()
 6889            } else {
 6890                None
 6891            };
 6892
 6893            if let Some(highlights) = highlights {
 6894                this.update(cx, |this, cx| {
 6895                    if this.pending_rename.is_some() {
 6896                        return;
 6897                    }
 6898
 6899                    let buffer = this.buffer.read(cx);
 6900                    if buffer
 6901                        .text_anchor_for_position(cursor_position, cx)
 6902                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6903                    {
 6904                        return;
 6905                    }
 6906
 6907                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6908                    let mut write_ranges = Vec::new();
 6909                    let mut read_ranges = Vec::new();
 6910                    for highlight in highlights {
 6911                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6912                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6913                        {
 6914                            let start = highlight
 6915                                .range
 6916                                .start
 6917                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6918                            let end = highlight
 6919                                .range
 6920                                .end
 6921                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6922                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6923                                continue;
 6924                            }
 6925
 6926                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6927                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6928                                write_ranges.push(range);
 6929                            } else {
 6930                                read_ranges.push(range);
 6931                            }
 6932                        }
 6933                    }
 6934
 6935                    this.highlight_background::<DocumentHighlightRead>(
 6936                        &read_ranges,
 6937                        |theme| theme.colors().editor_document_highlight_read_background,
 6938                        cx,
 6939                    );
 6940                    this.highlight_background::<DocumentHighlightWrite>(
 6941                        &write_ranges,
 6942                        |theme| theme.colors().editor_document_highlight_write_background,
 6943                        cx,
 6944                    );
 6945                    cx.notify();
 6946                })
 6947                .log_err();
 6948            }
 6949        }));
 6950        None
 6951    }
 6952
 6953    fn prepare_highlight_query_from_selection(
 6954        &mut self,
 6955        window: &Window,
 6956        cx: &mut Context<Editor>,
 6957    ) -> Option<(String, Range<Anchor>)> {
 6958        if matches!(self.mode, EditorMode::SingleLine) {
 6959            return None;
 6960        }
 6961        if !EditorSettings::get_global(cx).selection_highlight {
 6962            return None;
 6963        }
 6964        if self.selections.count() != 1 || self.selections.line_mode() {
 6965            return None;
 6966        }
 6967        let snapshot = self.snapshot(window, cx);
 6968        let selection = self.selections.newest::<Point>(&snapshot);
 6969        // If the selection spans multiple rows OR it is empty
 6970        if selection.start.row != selection.end.row
 6971            || selection.start.column == selection.end.column
 6972        {
 6973            return None;
 6974        }
 6975        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6976        let query = snapshot
 6977            .buffer_snapshot()
 6978            .text_for_range(selection_anchor_range.clone())
 6979            .collect::<String>();
 6980        if query.trim().is_empty() {
 6981            return None;
 6982        }
 6983        Some((query, selection_anchor_range))
 6984    }
 6985
 6986    fn update_selection_occurrence_highlights(
 6987        &mut self,
 6988        query_text: String,
 6989        query_range: Range<Anchor>,
 6990        multi_buffer_range_to_query: Range<Point>,
 6991        use_debounce: bool,
 6992        window: &mut Window,
 6993        cx: &mut Context<Editor>,
 6994    ) -> Task<()> {
 6995        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6996        cx.spawn_in(window, async move |editor, cx| {
 6997            if use_debounce {
 6998                cx.background_executor()
 6999                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7000                    .await;
 7001            }
 7002            let match_task = cx.background_spawn(async move {
 7003                let buffer_ranges = multi_buffer_snapshot
 7004                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7005                    .into_iter()
 7006                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7007                let mut match_ranges = Vec::new();
 7008                let Ok(regex) = project::search::SearchQuery::text(
 7009                    query_text.clone(),
 7010                    false,
 7011                    false,
 7012                    false,
 7013                    Default::default(),
 7014                    Default::default(),
 7015                    false,
 7016                    None,
 7017                ) else {
 7018                    return Vec::default();
 7019                };
 7020                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7021                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7022                    match_ranges.extend(
 7023                        regex
 7024                            .search(
 7025                                buffer_snapshot,
 7026                                Some(search_range.start.0..search_range.end.0),
 7027                            )
 7028                            .await
 7029                            .into_iter()
 7030                            .filter_map(|match_range| {
 7031                                let match_start = buffer_snapshot
 7032                                    .anchor_after(search_range.start + match_range.start);
 7033                                let match_end = buffer_snapshot
 7034                                    .anchor_before(search_range.start + match_range.end);
 7035                                let match_anchor_range =
 7036                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7037                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7038                            }),
 7039                    );
 7040                }
 7041                match_ranges
 7042            });
 7043            let match_ranges = match_task.await;
 7044            editor
 7045                .update_in(cx, |editor, _, cx| {
 7046                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7047                    if !match_ranges.is_empty() {
 7048                        editor.highlight_background::<SelectedTextHighlight>(
 7049                            &match_ranges,
 7050                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7051                            cx,
 7052                        )
 7053                    }
 7054                })
 7055                .log_err();
 7056        })
 7057    }
 7058
 7059    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7060        struct NewlineFold;
 7061        let type_id = std::any::TypeId::of::<NewlineFold>();
 7062        if !self.mode.is_single_line() {
 7063            return;
 7064        }
 7065        let snapshot = self.snapshot(window, cx);
 7066        if snapshot.buffer_snapshot().max_point().row == 0 {
 7067            return;
 7068        }
 7069        let task = cx.background_spawn(async move {
 7070            let new_newlines = snapshot
 7071                .buffer_chars_at(MultiBufferOffset(0))
 7072                .filter_map(|(c, i)| {
 7073                    if c == '\n' {
 7074                        Some(
 7075                            snapshot.buffer_snapshot().anchor_after(i)
 7076                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7077                        )
 7078                    } else {
 7079                        None
 7080                    }
 7081                })
 7082                .collect::<Vec<_>>();
 7083            let existing_newlines = snapshot
 7084                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7085                .filter_map(|fold| {
 7086                    if fold.placeholder.type_tag == Some(type_id) {
 7087                        Some(fold.range.start..fold.range.end)
 7088                    } else {
 7089                        None
 7090                    }
 7091                })
 7092                .collect::<Vec<_>>();
 7093
 7094            (new_newlines, existing_newlines)
 7095        });
 7096        self.folding_newlines = cx.spawn(async move |this, cx| {
 7097            let (new_newlines, existing_newlines) = task.await;
 7098            if new_newlines == existing_newlines {
 7099                return;
 7100            }
 7101            let placeholder = FoldPlaceholder {
 7102                render: Arc::new(move |_, _, cx| {
 7103                    div()
 7104                        .bg(cx.theme().status().hint_background)
 7105                        .border_b_1()
 7106                        .size_full()
 7107                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7108                        .border_color(cx.theme().status().hint)
 7109                        .child("\\n")
 7110                        .into_any()
 7111                }),
 7112                constrain_width: false,
 7113                merge_adjacent: false,
 7114                type_tag: Some(type_id),
 7115            };
 7116            let creases = new_newlines
 7117                .into_iter()
 7118                .map(|range| Crease::simple(range, placeholder.clone()))
 7119                .collect();
 7120            this.update(cx, |this, cx| {
 7121                this.display_map.update(cx, |display_map, cx| {
 7122                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7123                    display_map.fold(creases, cx);
 7124                });
 7125            })
 7126            .ok();
 7127        });
 7128    }
 7129
 7130    fn refresh_selected_text_highlights(
 7131        &mut self,
 7132        on_buffer_edit: bool,
 7133        window: &mut Window,
 7134        cx: &mut Context<Editor>,
 7135    ) {
 7136        let Some((query_text, query_range)) =
 7137            self.prepare_highlight_query_from_selection(window, cx)
 7138        else {
 7139            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7140            self.quick_selection_highlight_task.take();
 7141            self.debounced_selection_highlight_task.take();
 7142            return;
 7143        };
 7144        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7145        if on_buffer_edit
 7146            || self
 7147                .quick_selection_highlight_task
 7148                .as_ref()
 7149                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7150        {
 7151            let multi_buffer_visible_start = self
 7152                .scroll_manager
 7153                .anchor()
 7154                .anchor
 7155                .to_point(&multi_buffer_snapshot);
 7156            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7157                multi_buffer_visible_start
 7158                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7159                Bias::Left,
 7160            );
 7161            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7162            self.quick_selection_highlight_task = Some((
 7163                query_range.clone(),
 7164                self.update_selection_occurrence_highlights(
 7165                    query_text.clone(),
 7166                    query_range.clone(),
 7167                    multi_buffer_visible_range,
 7168                    false,
 7169                    window,
 7170                    cx,
 7171                ),
 7172            ));
 7173        }
 7174        if on_buffer_edit
 7175            || self
 7176                .debounced_selection_highlight_task
 7177                .as_ref()
 7178                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7179        {
 7180            let multi_buffer_start = multi_buffer_snapshot
 7181                .anchor_before(MultiBufferOffset(0))
 7182                .to_point(&multi_buffer_snapshot);
 7183            let multi_buffer_end = multi_buffer_snapshot
 7184                .anchor_after(multi_buffer_snapshot.len())
 7185                .to_point(&multi_buffer_snapshot);
 7186            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7187            self.debounced_selection_highlight_task = Some((
 7188                query_range.clone(),
 7189                self.update_selection_occurrence_highlights(
 7190                    query_text,
 7191                    query_range,
 7192                    multi_buffer_full_range,
 7193                    true,
 7194                    window,
 7195                    cx,
 7196                ),
 7197            ));
 7198        }
 7199    }
 7200
 7201    pub fn refresh_edit_prediction(
 7202        &mut self,
 7203        debounce: bool,
 7204        user_requested: bool,
 7205        window: &mut Window,
 7206        cx: &mut Context<Self>,
 7207    ) -> Option<()> {
 7208        if DisableAiSettings::get_global(cx).disable_ai {
 7209            return None;
 7210        }
 7211
 7212        let provider = self.edit_prediction_provider()?;
 7213        let cursor = self.selections.newest_anchor().head();
 7214        let (buffer, cursor_buffer_position) =
 7215            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7216
 7217        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7218            self.discard_edit_prediction(false, cx);
 7219            return None;
 7220        }
 7221
 7222        self.update_visible_edit_prediction(window, cx);
 7223
 7224        if !user_requested
 7225            && (!self.should_show_edit_predictions()
 7226                || !self.is_focused(window)
 7227                || buffer.read(cx).is_empty())
 7228        {
 7229            self.discard_edit_prediction(false, cx);
 7230            return None;
 7231        }
 7232
 7233        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7234        Some(())
 7235    }
 7236
 7237    fn show_edit_predictions_in_menu(&self) -> bool {
 7238        match self.edit_prediction_settings {
 7239            EditPredictionSettings::Disabled => false,
 7240            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7241        }
 7242    }
 7243
 7244    pub fn edit_predictions_enabled(&self) -> bool {
 7245        match self.edit_prediction_settings {
 7246            EditPredictionSettings::Disabled => false,
 7247            EditPredictionSettings::Enabled { .. } => true,
 7248        }
 7249    }
 7250
 7251    fn edit_prediction_requires_modifier(&self) -> bool {
 7252        match self.edit_prediction_settings {
 7253            EditPredictionSettings::Disabled => false,
 7254            EditPredictionSettings::Enabled {
 7255                preview_requires_modifier,
 7256                ..
 7257            } => preview_requires_modifier,
 7258        }
 7259    }
 7260
 7261    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7262        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7263            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7264            self.discard_edit_prediction(false, cx);
 7265        } else {
 7266            let selection = self.selections.newest_anchor();
 7267            let cursor = selection.head();
 7268
 7269            if let Some((buffer, cursor_buffer_position)) =
 7270                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7271            {
 7272                self.edit_prediction_settings =
 7273                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7274            }
 7275        }
 7276    }
 7277
 7278    fn edit_prediction_settings_at_position(
 7279        &self,
 7280        buffer: &Entity<Buffer>,
 7281        buffer_position: language::Anchor,
 7282        cx: &App,
 7283    ) -> EditPredictionSettings {
 7284        if !self.mode.is_full()
 7285            || !self.show_edit_predictions_override.unwrap_or(true)
 7286            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7287        {
 7288            return EditPredictionSettings::Disabled;
 7289        }
 7290
 7291        let buffer = buffer.read(cx);
 7292
 7293        let file = buffer.file();
 7294
 7295        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7296            return EditPredictionSettings::Disabled;
 7297        };
 7298
 7299        let by_provider = matches!(
 7300            self.menu_edit_predictions_policy,
 7301            MenuEditPredictionsPolicy::ByProvider
 7302        );
 7303
 7304        let show_in_menu = by_provider
 7305            && self
 7306                .edit_prediction_provider
 7307                .as_ref()
 7308                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7309
 7310        let preview_requires_modifier =
 7311            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7312
 7313        EditPredictionSettings::Enabled {
 7314            show_in_menu,
 7315            preview_requires_modifier,
 7316        }
 7317    }
 7318
 7319    fn should_show_edit_predictions(&self) -> bool {
 7320        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7321    }
 7322
 7323    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7324        matches!(
 7325            self.edit_prediction_preview,
 7326            EditPredictionPreview::Active { .. }
 7327        )
 7328    }
 7329
 7330    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7331        let cursor = self.selections.newest_anchor().head();
 7332        if let Some((buffer, cursor_position)) =
 7333            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7334        {
 7335            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7336        } else {
 7337            false
 7338        }
 7339    }
 7340
 7341    pub fn supports_minimap(&self, cx: &App) -> bool {
 7342        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7343    }
 7344
 7345    fn edit_predictions_enabled_in_buffer(
 7346        &self,
 7347        buffer: &Entity<Buffer>,
 7348        buffer_position: language::Anchor,
 7349        cx: &App,
 7350    ) -> bool {
 7351        maybe!({
 7352            if self.read_only(cx) {
 7353                return Some(false);
 7354            }
 7355            let provider = self.edit_prediction_provider()?;
 7356            if !provider.is_enabled(buffer, buffer_position, cx) {
 7357                return Some(false);
 7358            }
 7359            let buffer = buffer.read(cx);
 7360            let Some(file) = buffer.file() else {
 7361                return Some(true);
 7362            };
 7363            let settings = all_language_settings(Some(file), cx);
 7364            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7365        })
 7366        .unwrap_or(false)
 7367    }
 7368
 7369    fn cycle_edit_prediction(
 7370        &mut self,
 7371        direction: Direction,
 7372        window: &mut Window,
 7373        cx: &mut Context<Self>,
 7374    ) -> Option<()> {
 7375        let provider = self.edit_prediction_provider()?;
 7376        let cursor = self.selections.newest_anchor().head();
 7377        let (buffer, cursor_buffer_position) =
 7378            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7379        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7380            return None;
 7381        }
 7382
 7383        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7384        self.update_visible_edit_prediction(window, cx);
 7385
 7386        Some(())
 7387    }
 7388
 7389    pub fn show_edit_prediction(
 7390        &mut self,
 7391        _: &ShowEditPrediction,
 7392        window: &mut Window,
 7393        cx: &mut Context<Self>,
 7394    ) {
 7395        if !self.has_active_edit_prediction() {
 7396            self.refresh_edit_prediction(false, true, window, cx);
 7397            return;
 7398        }
 7399
 7400        self.update_visible_edit_prediction(window, cx);
 7401    }
 7402
 7403    pub fn display_cursor_names(
 7404        &mut self,
 7405        _: &DisplayCursorNames,
 7406        window: &mut Window,
 7407        cx: &mut Context<Self>,
 7408    ) {
 7409        self.show_cursor_names(window, cx);
 7410    }
 7411
 7412    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7413        self.show_cursor_names = true;
 7414        cx.notify();
 7415        cx.spawn_in(window, async move |this, cx| {
 7416            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7417            this.update(cx, |this, cx| {
 7418                this.show_cursor_names = false;
 7419                cx.notify()
 7420            })
 7421            .ok()
 7422        })
 7423        .detach();
 7424    }
 7425
 7426    pub fn next_edit_prediction(
 7427        &mut self,
 7428        _: &NextEditPrediction,
 7429        window: &mut Window,
 7430        cx: &mut Context<Self>,
 7431    ) {
 7432        if self.has_active_edit_prediction() {
 7433            self.cycle_edit_prediction(Direction::Next, window, cx);
 7434        } else {
 7435            let is_copilot_disabled = self
 7436                .refresh_edit_prediction(false, true, window, cx)
 7437                .is_none();
 7438            if is_copilot_disabled {
 7439                cx.propagate();
 7440            }
 7441        }
 7442    }
 7443
 7444    pub fn previous_edit_prediction(
 7445        &mut self,
 7446        _: &PreviousEditPrediction,
 7447        window: &mut Window,
 7448        cx: &mut Context<Self>,
 7449    ) {
 7450        if self.has_active_edit_prediction() {
 7451            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7452        } else {
 7453            let is_copilot_disabled = self
 7454                .refresh_edit_prediction(false, true, window, cx)
 7455                .is_none();
 7456            if is_copilot_disabled {
 7457                cx.propagate();
 7458            }
 7459        }
 7460    }
 7461
 7462    pub fn accept_edit_prediction(
 7463        &mut self,
 7464        _: &AcceptEditPrediction,
 7465        window: &mut Window,
 7466        cx: &mut Context<Self>,
 7467    ) {
 7468        if self.show_edit_predictions_in_menu() {
 7469            self.hide_context_menu(window, cx);
 7470        }
 7471
 7472        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7473            return;
 7474        };
 7475
 7476        match &active_edit_prediction.completion {
 7477            EditPrediction::MoveWithin { target, .. } => {
 7478                let target = *target;
 7479
 7480                if let Some(position_map) = &self.last_position_map {
 7481                    if position_map
 7482                        .visible_row_range
 7483                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7484                        || !self.edit_prediction_requires_modifier()
 7485                    {
 7486                        self.unfold_ranges(&[target..target], true, false, cx);
 7487                        // Note that this is also done in vim's handler of the Tab action.
 7488                        self.change_selections(
 7489                            SelectionEffects::scroll(Autoscroll::newest()),
 7490                            window,
 7491                            cx,
 7492                            |selections| {
 7493                                selections.select_anchor_ranges([target..target]);
 7494                            },
 7495                        );
 7496                        self.clear_row_highlights::<EditPredictionPreview>();
 7497
 7498                        self.edit_prediction_preview
 7499                            .set_previous_scroll_position(None);
 7500                    } else {
 7501                        self.edit_prediction_preview
 7502                            .set_previous_scroll_position(Some(
 7503                                position_map.snapshot.scroll_anchor,
 7504                            ));
 7505
 7506                        self.highlight_rows::<EditPredictionPreview>(
 7507                            target..target,
 7508                            cx.theme().colors().editor_highlighted_line_background,
 7509                            RowHighlightOptions {
 7510                                autoscroll: true,
 7511                                ..Default::default()
 7512                            },
 7513                            cx,
 7514                        );
 7515                        self.request_autoscroll(Autoscroll::fit(), cx);
 7516                    }
 7517                }
 7518            }
 7519            EditPrediction::MoveOutside { snapshot, target } => {
 7520                if let Some(workspace) = self.workspace() {
 7521                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7522                        .detach_and_log_err(cx);
 7523                }
 7524            }
 7525            EditPrediction::Edit { edits, .. } => {
 7526                self.report_edit_prediction_event(
 7527                    active_edit_prediction.completion_id.clone(),
 7528                    true,
 7529                    cx,
 7530                );
 7531
 7532                if let Some(provider) = self.edit_prediction_provider() {
 7533                    provider.accept(cx);
 7534                }
 7535
 7536                // Store the transaction ID and selections before applying the edit
 7537                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7538
 7539                let snapshot = self.buffer.read(cx).snapshot(cx);
 7540                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7541
 7542                self.buffer.update(cx, |buffer, cx| {
 7543                    buffer.edit(edits.iter().cloned(), None, cx)
 7544                });
 7545
 7546                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7547                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7548                });
 7549
 7550                let selections = self.selections.disjoint_anchors_arc();
 7551                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7552                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7553                    if has_new_transaction {
 7554                        self.selection_history
 7555                            .insert_transaction(transaction_id_now, selections);
 7556                    }
 7557                }
 7558
 7559                self.update_visible_edit_prediction(window, cx);
 7560                if self.active_edit_prediction.is_none() {
 7561                    self.refresh_edit_prediction(true, true, window, cx);
 7562                }
 7563
 7564                cx.notify();
 7565            }
 7566        }
 7567
 7568        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7569    }
 7570
 7571    pub fn accept_partial_edit_prediction(
 7572        &mut self,
 7573        _: &AcceptPartialEditPrediction,
 7574        window: &mut Window,
 7575        cx: &mut Context<Self>,
 7576    ) {
 7577        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7578            return;
 7579        };
 7580        if self.selections.count() != 1 {
 7581            return;
 7582        }
 7583
 7584        match &active_edit_prediction.completion {
 7585            EditPrediction::MoveWithin { target, .. } => {
 7586                let target = *target;
 7587                self.change_selections(
 7588                    SelectionEffects::scroll(Autoscroll::newest()),
 7589                    window,
 7590                    cx,
 7591                    |selections| {
 7592                        selections.select_anchor_ranges([target..target]);
 7593                    },
 7594                );
 7595            }
 7596            EditPrediction::MoveOutside { snapshot, target } => {
 7597                if let Some(workspace) = self.workspace() {
 7598                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7599                        .detach_and_log_err(cx);
 7600                }
 7601            }
 7602            EditPrediction::Edit { edits, .. } => {
 7603                self.report_edit_prediction_event(
 7604                    active_edit_prediction.completion_id.clone(),
 7605                    true,
 7606                    cx,
 7607                );
 7608
 7609                // Find an insertion that starts at the cursor position.
 7610                let snapshot = self.buffer.read(cx).snapshot(cx);
 7611                let cursor_offset = self
 7612                    .selections
 7613                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7614                    .head();
 7615                let insertion = edits.iter().find_map(|(range, text)| {
 7616                    let range = range.to_offset(&snapshot);
 7617                    if range.is_empty() && range.start == cursor_offset {
 7618                        Some(text)
 7619                    } else {
 7620                        None
 7621                    }
 7622                });
 7623
 7624                if let Some(text) = insertion {
 7625                    let mut partial_completion = text
 7626                        .chars()
 7627                        .by_ref()
 7628                        .take_while(|c| c.is_alphabetic())
 7629                        .collect::<String>();
 7630                    if partial_completion.is_empty() {
 7631                        partial_completion = text
 7632                            .chars()
 7633                            .by_ref()
 7634                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7635                            .collect::<String>();
 7636                    }
 7637
 7638                    cx.emit(EditorEvent::InputHandled {
 7639                        utf16_range_to_replace: None,
 7640                        text: partial_completion.clone().into(),
 7641                    });
 7642
 7643                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7644
 7645                    self.refresh_edit_prediction(true, true, window, cx);
 7646                    cx.notify();
 7647                } else {
 7648                    self.accept_edit_prediction(&Default::default(), window, cx);
 7649                }
 7650            }
 7651        }
 7652    }
 7653
 7654    fn discard_edit_prediction(
 7655        &mut self,
 7656        should_report_edit_prediction_event: bool,
 7657        cx: &mut Context<Self>,
 7658    ) -> bool {
 7659        if should_report_edit_prediction_event {
 7660            let completion_id = self
 7661                .active_edit_prediction
 7662                .as_ref()
 7663                .and_then(|active_completion| active_completion.completion_id.clone());
 7664
 7665            self.report_edit_prediction_event(completion_id, false, cx);
 7666        }
 7667
 7668        if let Some(provider) = self.edit_prediction_provider() {
 7669            provider.discard(cx);
 7670        }
 7671
 7672        self.take_active_edit_prediction(cx)
 7673    }
 7674
 7675    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7676        let Some(provider) = self.edit_prediction_provider() else {
 7677            return;
 7678        };
 7679
 7680        let Some((_, buffer, _)) = self
 7681            .buffer
 7682            .read(cx)
 7683            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7684        else {
 7685            return;
 7686        };
 7687
 7688        let extension = buffer
 7689            .read(cx)
 7690            .file()
 7691            .and_then(|file| Some(file.path().extension()?.to_string()));
 7692
 7693        let event_type = match accepted {
 7694            true => "Edit Prediction Accepted",
 7695            false => "Edit Prediction Discarded",
 7696        };
 7697        telemetry::event!(
 7698            event_type,
 7699            provider = provider.name(),
 7700            prediction_id = id,
 7701            suggestion_accepted = accepted,
 7702            file_extension = extension,
 7703        );
 7704    }
 7705
 7706    fn open_editor_at_anchor(
 7707        snapshot: &language::BufferSnapshot,
 7708        target: language::Anchor,
 7709        workspace: &Entity<Workspace>,
 7710        window: &mut Window,
 7711        cx: &mut App,
 7712    ) -> Task<Result<()>> {
 7713        workspace.update(cx, |workspace, cx| {
 7714            let path = snapshot.file().map(|file| file.full_path(cx));
 7715            let Some(path) =
 7716                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7717            else {
 7718                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7719            };
 7720            let target = text::ToPoint::to_point(&target, snapshot);
 7721            let item = workspace.open_path(path, None, true, window, cx);
 7722            window.spawn(cx, async move |cx| {
 7723                let Some(editor) = item.await?.downcast::<Editor>() else {
 7724                    return Ok(());
 7725                };
 7726                editor
 7727                    .update_in(cx, |editor, window, cx| {
 7728                        editor.go_to_singleton_buffer_point(target, window, cx);
 7729                    })
 7730                    .ok();
 7731                anyhow::Ok(())
 7732            })
 7733        })
 7734    }
 7735
 7736    pub fn has_active_edit_prediction(&self) -> bool {
 7737        self.active_edit_prediction.is_some()
 7738    }
 7739
 7740    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7741        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7742            return false;
 7743        };
 7744
 7745        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7746        self.clear_highlights::<EditPredictionHighlight>(cx);
 7747        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7748        true
 7749    }
 7750
 7751    /// Returns true when we're displaying the edit prediction popover below the cursor
 7752    /// like we are not previewing and the LSP autocomplete menu is visible
 7753    /// or we are in `when_holding_modifier` mode.
 7754    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7755        if self.edit_prediction_preview_is_active()
 7756            || !self.show_edit_predictions_in_menu()
 7757            || !self.edit_predictions_enabled()
 7758        {
 7759            return false;
 7760        }
 7761
 7762        if self.has_visible_completions_menu() {
 7763            return true;
 7764        }
 7765
 7766        has_completion && self.edit_prediction_requires_modifier()
 7767    }
 7768
 7769    fn handle_modifiers_changed(
 7770        &mut self,
 7771        modifiers: Modifiers,
 7772        position_map: &PositionMap,
 7773        window: &mut Window,
 7774        cx: &mut Context<Self>,
 7775    ) {
 7776        // Ensure that the edit prediction preview is updated, even when not
 7777        // enabled, if there's an active edit prediction preview.
 7778        if self.show_edit_predictions_in_menu()
 7779            || matches!(
 7780                self.edit_prediction_preview,
 7781                EditPredictionPreview::Active { .. }
 7782            )
 7783        {
 7784            self.update_edit_prediction_preview(&modifiers, window, cx);
 7785        }
 7786
 7787        self.update_selection_mode(&modifiers, position_map, window, cx);
 7788
 7789        let mouse_position = window.mouse_position();
 7790        if !position_map.text_hitbox.is_hovered(window) {
 7791            return;
 7792        }
 7793
 7794        self.update_hovered_link(
 7795            position_map.point_for_position(mouse_position),
 7796            &position_map.snapshot,
 7797            modifiers,
 7798            window,
 7799            cx,
 7800        )
 7801    }
 7802
 7803    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7804        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7805            MultiCursorModifier::Alt => modifiers.secondary(),
 7806            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7807        }
 7808    }
 7809
 7810    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7811        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7812            MultiCursorModifier::Alt => modifiers.alt,
 7813            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7814        }
 7815    }
 7816
 7817    fn columnar_selection_mode(
 7818        modifiers: &Modifiers,
 7819        cx: &mut Context<Self>,
 7820    ) -> Option<ColumnarMode> {
 7821        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7822            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7823                Some(ColumnarMode::FromMouse)
 7824            } else if Self::is_alt_pressed(modifiers, cx) {
 7825                Some(ColumnarMode::FromSelection)
 7826            } else {
 7827                None
 7828            }
 7829        } else {
 7830            None
 7831        }
 7832    }
 7833
 7834    fn update_selection_mode(
 7835        &mut self,
 7836        modifiers: &Modifiers,
 7837        position_map: &PositionMap,
 7838        window: &mut Window,
 7839        cx: &mut Context<Self>,
 7840    ) {
 7841        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7842            return;
 7843        };
 7844        if self.selections.pending_anchor().is_none() {
 7845            return;
 7846        }
 7847
 7848        let mouse_position = window.mouse_position();
 7849        let point_for_position = position_map.point_for_position(mouse_position);
 7850        let position = point_for_position.previous_valid;
 7851
 7852        self.select(
 7853            SelectPhase::BeginColumnar {
 7854                position,
 7855                reset: false,
 7856                mode,
 7857                goal_column: point_for_position.exact_unclipped.column(),
 7858            },
 7859            window,
 7860            cx,
 7861        );
 7862    }
 7863
 7864    fn update_edit_prediction_preview(
 7865        &mut self,
 7866        modifiers: &Modifiers,
 7867        window: &mut Window,
 7868        cx: &mut Context<Self>,
 7869    ) {
 7870        let mut modifiers_held = false;
 7871        if let Some(accept_keystroke) = self
 7872            .accept_edit_prediction_keybind(false, window, cx)
 7873            .keystroke()
 7874        {
 7875            modifiers_held = modifiers_held
 7876                || (accept_keystroke.modifiers() == modifiers
 7877                    && accept_keystroke.modifiers().modified());
 7878        };
 7879        if let Some(accept_partial_keystroke) = self
 7880            .accept_edit_prediction_keybind(true, window, cx)
 7881            .keystroke()
 7882        {
 7883            modifiers_held = modifiers_held
 7884                || (accept_partial_keystroke.modifiers() == modifiers
 7885                    && accept_partial_keystroke.modifiers().modified());
 7886        }
 7887
 7888        if modifiers_held {
 7889            if matches!(
 7890                self.edit_prediction_preview,
 7891                EditPredictionPreview::Inactive { .. }
 7892            ) {
 7893                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7894                    provider.provider.did_show(cx)
 7895                }
 7896
 7897                self.edit_prediction_preview = EditPredictionPreview::Active {
 7898                    previous_scroll_position: None,
 7899                    since: Instant::now(),
 7900                };
 7901
 7902                self.update_visible_edit_prediction(window, cx);
 7903                cx.notify();
 7904            }
 7905        } else if let EditPredictionPreview::Active {
 7906            previous_scroll_position,
 7907            since,
 7908        } = self.edit_prediction_preview
 7909        {
 7910            if let (Some(previous_scroll_position), Some(position_map)) =
 7911                (previous_scroll_position, self.last_position_map.as_ref())
 7912            {
 7913                self.set_scroll_position(
 7914                    previous_scroll_position
 7915                        .scroll_position(&position_map.snapshot.display_snapshot),
 7916                    window,
 7917                    cx,
 7918                );
 7919            }
 7920
 7921            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7922                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7923            };
 7924            self.clear_row_highlights::<EditPredictionPreview>();
 7925            self.update_visible_edit_prediction(window, cx);
 7926            cx.notify();
 7927        }
 7928    }
 7929
 7930    fn update_visible_edit_prediction(
 7931        &mut self,
 7932        _window: &mut Window,
 7933        cx: &mut Context<Self>,
 7934    ) -> Option<()> {
 7935        if DisableAiSettings::get_global(cx).disable_ai {
 7936            return None;
 7937        }
 7938
 7939        if self.ime_transaction.is_some() {
 7940            self.discard_edit_prediction(false, cx);
 7941            return None;
 7942        }
 7943
 7944        let selection = self.selections.newest_anchor();
 7945        let cursor = selection.head();
 7946        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7947        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7948        let excerpt_id = cursor.excerpt_id;
 7949
 7950        let show_in_menu = self.show_edit_predictions_in_menu();
 7951        let completions_menu_has_precedence = !show_in_menu
 7952            && (self.context_menu.borrow().is_some()
 7953                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7954
 7955        if completions_menu_has_precedence
 7956            || !offset_selection.is_empty()
 7957            || self
 7958                .active_edit_prediction
 7959                .as_ref()
 7960                .is_some_and(|completion| {
 7961                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7962                        return false;
 7963                    };
 7964                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7965                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7966                    !invalidation_range.contains(&offset_selection.head())
 7967                })
 7968        {
 7969            self.discard_edit_prediction(false, cx);
 7970            return None;
 7971        }
 7972
 7973        self.take_active_edit_prediction(cx);
 7974        let Some(provider) = self.edit_prediction_provider() else {
 7975            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7976            return None;
 7977        };
 7978
 7979        let (buffer, cursor_buffer_position) =
 7980            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7981
 7982        self.edit_prediction_settings =
 7983            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7984
 7985        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7986
 7987        if self.edit_prediction_indent_conflict {
 7988            let cursor_point = cursor.to_point(&multibuffer);
 7989
 7990            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7991
 7992            if let Some((_, indent)) = indents.iter().next()
 7993                && indent.len == cursor_point.column
 7994            {
 7995                self.edit_prediction_indent_conflict = false;
 7996            }
 7997        }
 7998
 7999        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8000
 8001        let (completion_id, edits, edit_preview) = match edit_prediction {
 8002            edit_prediction::EditPrediction::Local {
 8003                id,
 8004                edits,
 8005                edit_preview,
 8006            } => (id, edits, edit_preview),
 8007            edit_prediction::EditPrediction::Jump {
 8008                id,
 8009                snapshot,
 8010                target,
 8011            } => {
 8012                self.stale_edit_prediction_in_menu = None;
 8013                self.active_edit_prediction = Some(EditPredictionState {
 8014                    inlay_ids: vec![],
 8015                    completion: EditPrediction::MoveOutside { snapshot, target },
 8016                    completion_id: id,
 8017                    invalidation_range: None,
 8018                });
 8019                cx.notify();
 8020                return Some(());
 8021            }
 8022        };
 8023
 8024        let edits = edits
 8025            .into_iter()
 8026            .flat_map(|(range, new_text)| {
 8027                Some((
 8028                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8029                    new_text,
 8030                ))
 8031            })
 8032            .collect::<Vec<_>>();
 8033        if edits.is_empty() {
 8034            return None;
 8035        }
 8036
 8037        let first_edit_start = edits.first().unwrap().0.start;
 8038        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8039        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8040
 8041        let last_edit_end = edits.last().unwrap().0.end;
 8042        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8043        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8044
 8045        let cursor_row = cursor.to_point(&multibuffer).row;
 8046
 8047        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8048
 8049        let mut inlay_ids = Vec::new();
 8050        let invalidation_row_range;
 8051        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8052            Some(cursor_row..edit_end_row)
 8053        } else if cursor_row > edit_end_row {
 8054            Some(edit_start_row..cursor_row)
 8055        } else {
 8056            None
 8057        };
 8058        let supports_jump = self
 8059            .edit_prediction_provider
 8060            .as_ref()
 8061            .map(|provider| provider.provider.supports_jump_to_edit())
 8062            .unwrap_or(true);
 8063
 8064        let is_move = supports_jump
 8065            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8066        let completion = if is_move {
 8067            invalidation_row_range =
 8068                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8069            let target = first_edit_start;
 8070            EditPrediction::MoveWithin { target, snapshot }
 8071        } else {
 8072            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8073                && !self.edit_predictions_hidden_for_vim_mode;
 8074
 8075            if show_completions_in_buffer {
 8076                if let Some(provider) = &self.edit_prediction_provider {
 8077                    provider.provider.did_show(cx);
 8078                }
 8079                if edits
 8080                    .iter()
 8081                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8082                {
 8083                    let mut inlays = Vec::new();
 8084                    for (range, new_text) in &edits {
 8085                        let inlay = Inlay::edit_prediction(
 8086                            post_inc(&mut self.next_inlay_id),
 8087                            range.start,
 8088                            new_text.as_ref(),
 8089                        );
 8090                        inlay_ids.push(inlay.id);
 8091                        inlays.push(inlay);
 8092                    }
 8093
 8094                    self.splice_inlays(&[], inlays, cx);
 8095                } else {
 8096                    let background_color = cx.theme().status().deleted_background;
 8097                    self.highlight_text::<EditPredictionHighlight>(
 8098                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8099                        HighlightStyle {
 8100                            background_color: Some(background_color),
 8101                            ..Default::default()
 8102                        },
 8103                        cx,
 8104                    );
 8105                }
 8106            }
 8107
 8108            invalidation_row_range = edit_start_row..edit_end_row;
 8109
 8110            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8111                if provider.show_tab_accept_marker() {
 8112                    EditDisplayMode::TabAccept
 8113                } else {
 8114                    EditDisplayMode::Inline
 8115                }
 8116            } else {
 8117                EditDisplayMode::DiffPopover
 8118            };
 8119
 8120            EditPrediction::Edit {
 8121                edits,
 8122                edit_preview,
 8123                display_mode,
 8124                snapshot,
 8125            }
 8126        };
 8127
 8128        let invalidation_range = multibuffer
 8129            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8130            ..multibuffer.anchor_after(Point::new(
 8131                invalidation_row_range.end,
 8132                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8133            ));
 8134
 8135        self.stale_edit_prediction_in_menu = None;
 8136        self.active_edit_prediction = Some(EditPredictionState {
 8137            inlay_ids,
 8138            completion,
 8139            completion_id,
 8140            invalidation_range: Some(invalidation_range),
 8141        });
 8142
 8143        cx.notify();
 8144
 8145        Some(())
 8146    }
 8147
 8148    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8149        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8150    }
 8151
 8152    fn clear_tasks(&mut self) {
 8153        self.tasks.clear()
 8154    }
 8155
 8156    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8157        if self.tasks.insert(key, value).is_some() {
 8158            // This case should hopefully be rare, but just in case...
 8159            log::error!(
 8160                "multiple different run targets found on a single line, only the last target will be rendered"
 8161            )
 8162        }
 8163    }
 8164
 8165    /// Get all display points of breakpoints that will be rendered within editor
 8166    ///
 8167    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8168    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8169    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8170    fn active_breakpoints(
 8171        &self,
 8172        range: Range<DisplayRow>,
 8173        window: &mut Window,
 8174        cx: &mut Context<Self>,
 8175    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8176        let mut breakpoint_display_points = HashMap::default();
 8177
 8178        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8179            return breakpoint_display_points;
 8180        };
 8181
 8182        let snapshot = self.snapshot(window, cx);
 8183
 8184        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8185        let Some(project) = self.project() else {
 8186            return breakpoint_display_points;
 8187        };
 8188
 8189        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8190            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8191
 8192        for (buffer_snapshot, range, excerpt_id) in
 8193            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8194        {
 8195            let Some(buffer) = project
 8196                .read(cx)
 8197                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8198            else {
 8199                continue;
 8200            };
 8201            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8202                &buffer,
 8203                Some(
 8204                    buffer_snapshot.anchor_before(range.start)
 8205                        ..buffer_snapshot.anchor_after(range.end),
 8206                ),
 8207                buffer_snapshot,
 8208                cx,
 8209            );
 8210            for (breakpoint, state) in breakpoints {
 8211                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8212                let position = multi_buffer_anchor
 8213                    .to_point(&multi_buffer_snapshot)
 8214                    .to_display_point(&snapshot);
 8215
 8216                breakpoint_display_points.insert(
 8217                    position.row(),
 8218                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8219                );
 8220            }
 8221        }
 8222
 8223        breakpoint_display_points
 8224    }
 8225
 8226    fn breakpoint_context_menu(
 8227        &self,
 8228        anchor: Anchor,
 8229        window: &mut Window,
 8230        cx: &mut Context<Self>,
 8231    ) -> Entity<ui::ContextMenu> {
 8232        let weak_editor = cx.weak_entity();
 8233        let focus_handle = self.focus_handle(cx);
 8234
 8235        let row = self
 8236            .buffer
 8237            .read(cx)
 8238            .snapshot(cx)
 8239            .summary_for_anchor::<Point>(&anchor)
 8240            .row;
 8241
 8242        let breakpoint = self
 8243            .breakpoint_at_row(row, window, cx)
 8244            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8245
 8246        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8247            "Edit Log Breakpoint"
 8248        } else {
 8249            "Set Log Breakpoint"
 8250        };
 8251
 8252        let condition_breakpoint_msg = if breakpoint
 8253            .as_ref()
 8254            .is_some_and(|bp| bp.1.condition.is_some())
 8255        {
 8256            "Edit Condition Breakpoint"
 8257        } else {
 8258            "Set Condition Breakpoint"
 8259        };
 8260
 8261        let hit_condition_breakpoint_msg = if breakpoint
 8262            .as_ref()
 8263            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8264        {
 8265            "Edit Hit Condition Breakpoint"
 8266        } else {
 8267            "Set Hit Condition Breakpoint"
 8268        };
 8269
 8270        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8271            "Unset Breakpoint"
 8272        } else {
 8273            "Set Breakpoint"
 8274        };
 8275
 8276        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8277
 8278        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8279            BreakpointState::Enabled => Some("Disable"),
 8280            BreakpointState::Disabled => Some("Enable"),
 8281        });
 8282
 8283        let (anchor, breakpoint) =
 8284            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8285
 8286        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8287            menu.on_blur_subscription(Subscription::new(|| {}))
 8288                .context(focus_handle)
 8289                .when(run_to_cursor, |this| {
 8290                    let weak_editor = weak_editor.clone();
 8291                    this.entry("Run to cursor", None, move |window, cx| {
 8292                        weak_editor
 8293                            .update(cx, |editor, cx| {
 8294                                editor.change_selections(
 8295                                    SelectionEffects::no_scroll(),
 8296                                    window,
 8297                                    cx,
 8298                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8299                                );
 8300                            })
 8301                            .ok();
 8302
 8303                        window.dispatch_action(Box::new(RunToCursor), cx);
 8304                    })
 8305                    .separator()
 8306                })
 8307                .when_some(toggle_state_msg, |this, msg| {
 8308                    this.entry(msg, None, {
 8309                        let weak_editor = weak_editor.clone();
 8310                        let breakpoint = breakpoint.clone();
 8311                        move |_window, cx| {
 8312                            weak_editor
 8313                                .update(cx, |this, cx| {
 8314                                    this.edit_breakpoint_at_anchor(
 8315                                        anchor,
 8316                                        breakpoint.as_ref().clone(),
 8317                                        BreakpointEditAction::InvertState,
 8318                                        cx,
 8319                                    );
 8320                                })
 8321                                .log_err();
 8322                        }
 8323                    })
 8324                })
 8325                .entry(set_breakpoint_msg, None, {
 8326                    let weak_editor = weak_editor.clone();
 8327                    let breakpoint = breakpoint.clone();
 8328                    move |_window, cx| {
 8329                        weak_editor
 8330                            .update(cx, |this, cx| {
 8331                                this.edit_breakpoint_at_anchor(
 8332                                    anchor,
 8333                                    breakpoint.as_ref().clone(),
 8334                                    BreakpointEditAction::Toggle,
 8335                                    cx,
 8336                                );
 8337                            })
 8338                            .log_err();
 8339                    }
 8340                })
 8341                .entry(log_breakpoint_msg, None, {
 8342                    let breakpoint = breakpoint.clone();
 8343                    let weak_editor = weak_editor.clone();
 8344                    move |window, cx| {
 8345                        weak_editor
 8346                            .update(cx, |this, cx| {
 8347                                this.add_edit_breakpoint_block(
 8348                                    anchor,
 8349                                    breakpoint.as_ref(),
 8350                                    BreakpointPromptEditAction::Log,
 8351                                    window,
 8352                                    cx,
 8353                                );
 8354                            })
 8355                            .log_err();
 8356                    }
 8357                })
 8358                .entry(condition_breakpoint_msg, None, {
 8359                    let breakpoint = breakpoint.clone();
 8360                    let weak_editor = weak_editor.clone();
 8361                    move |window, cx| {
 8362                        weak_editor
 8363                            .update(cx, |this, cx| {
 8364                                this.add_edit_breakpoint_block(
 8365                                    anchor,
 8366                                    breakpoint.as_ref(),
 8367                                    BreakpointPromptEditAction::Condition,
 8368                                    window,
 8369                                    cx,
 8370                                );
 8371                            })
 8372                            .log_err();
 8373                    }
 8374                })
 8375                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8376                    weak_editor
 8377                        .update(cx, |this, cx| {
 8378                            this.add_edit_breakpoint_block(
 8379                                anchor,
 8380                                breakpoint.as_ref(),
 8381                                BreakpointPromptEditAction::HitCondition,
 8382                                window,
 8383                                cx,
 8384                            );
 8385                        })
 8386                        .log_err();
 8387                })
 8388        })
 8389    }
 8390
 8391    fn render_breakpoint(
 8392        &self,
 8393        position: Anchor,
 8394        row: DisplayRow,
 8395        breakpoint: &Breakpoint,
 8396        state: Option<BreakpointSessionState>,
 8397        cx: &mut Context<Self>,
 8398    ) -> IconButton {
 8399        let is_rejected = state.is_some_and(|s| !s.verified);
 8400        // Is it a breakpoint that shows up when hovering over gutter?
 8401        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8402            (false, false),
 8403            |PhantomBreakpointIndicator {
 8404                 is_active,
 8405                 display_row,
 8406                 collides_with_existing_breakpoint,
 8407             }| {
 8408                (
 8409                    is_active && display_row == row,
 8410                    collides_with_existing_breakpoint,
 8411                )
 8412            },
 8413        );
 8414
 8415        let (color, icon) = {
 8416            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8417                (false, false) => ui::IconName::DebugBreakpoint,
 8418                (true, false) => ui::IconName::DebugLogBreakpoint,
 8419                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8420                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8421            };
 8422
 8423            let color = if is_phantom {
 8424                Color::Hint
 8425            } else if is_rejected {
 8426                Color::Disabled
 8427            } else {
 8428                Color::Debugger
 8429            };
 8430
 8431            (color, icon)
 8432        };
 8433
 8434        let breakpoint = Arc::from(breakpoint.clone());
 8435
 8436        let alt_as_text = gpui::Keystroke {
 8437            modifiers: Modifiers::secondary_key(),
 8438            ..Default::default()
 8439        };
 8440        let primary_action_text = if breakpoint.is_disabled() {
 8441            "Enable breakpoint"
 8442        } else if is_phantom && !collides_with_existing {
 8443            "Set breakpoint"
 8444        } else {
 8445            "Unset breakpoint"
 8446        };
 8447        let focus_handle = self.focus_handle.clone();
 8448
 8449        let meta = if is_rejected {
 8450            SharedString::from("No executable code is associated with this line.")
 8451        } else if collides_with_existing && !breakpoint.is_disabled() {
 8452            SharedString::from(format!(
 8453                "{alt_as_text}-click to disable,\nright-click for more options."
 8454            ))
 8455        } else {
 8456            SharedString::from("Right-click for more options.")
 8457        };
 8458        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8459            .icon_size(IconSize::XSmall)
 8460            .size(ui::ButtonSize::None)
 8461            .when(is_rejected, |this| {
 8462                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8463            })
 8464            .icon_color(color)
 8465            .style(ButtonStyle::Transparent)
 8466            .on_click(cx.listener({
 8467                move |editor, event: &ClickEvent, window, cx| {
 8468                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8469                        BreakpointEditAction::InvertState
 8470                    } else {
 8471                        BreakpointEditAction::Toggle
 8472                    };
 8473
 8474                    window.focus(&editor.focus_handle(cx));
 8475                    editor.edit_breakpoint_at_anchor(
 8476                        position,
 8477                        breakpoint.as_ref().clone(),
 8478                        edit_action,
 8479                        cx,
 8480                    );
 8481                }
 8482            }))
 8483            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8484                editor.set_breakpoint_context_menu(
 8485                    row,
 8486                    Some(position),
 8487                    event.position(),
 8488                    window,
 8489                    cx,
 8490                );
 8491            }))
 8492            .tooltip(move |_window, cx| {
 8493                Tooltip::with_meta_in(
 8494                    primary_action_text,
 8495                    Some(&ToggleBreakpoint),
 8496                    meta.clone(),
 8497                    &focus_handle,
 8498                    cx,
 8499                )
 8500            })
 8501    }
 8502
 8503    fn build_tasks_context(
 8504        project: &Entity<Project>,
 8505        buffer: &Entity<Buffer>,
 8506        buffer_row: u32,
 8507        tasks: &Arc<RunnableTasks>,
 8508        cx: &mut Context<Self>,
 8509    ) -> Task<Option<task::TaskContext>> {
 8510        let position = Point::new(buffer_row, tasks.column);
 8511        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8512        let location = Location {
 8513            buffer: buffer.clone(),
 8514            range: range_start..range_start,
 8515        };
 8516        // Fill in the environmental variables from the tree-sitter captures
 8517        let mut captured_task_variables = TaskVariables::default();
 8518        for (capture_name, value) in tasks.extra_variables.clone() {
 8519            captured_task_variables.insert(
 8520                task::VariableName::Custom(capture_name.into()),
 8521                value.clone(),
 8522            );
 8523        }
 8524        project.update(cx, |project, cx| {
 8525            project.task_store().update(cx, |task_store, cx| {
 8526                task_store.task_context_for_location(captured_task_variables, location, cx)
 8527            })
 8528        })
 8529    }
 8530
 8531    pub fn spawn_nearest_task(
 8532        &mut self,
 8533        action: &SpawnNearestTask,
 8534        window: &mut Window,
 8535        cx: &mut Context<Self>,
 8536    ) {
 8537        let Some((workspace, _)) = self.workspace.clone() else {
 8538            return;
 8539        };
 8540        let Some(project) = self.project.clone() else {
 8541            return;
 8542        };
 8543
 8544        // Try to find a closest, enclosing node using tree-sitter that has a task
 8545        let Some((buffer, buffer_row, tasks)) = self
 8546            .find_enclosing_node_task(cx)
 8547            // Or find the task that's closest in row-distance.
 8548            .or_else(|| self.find_closest_task(cx))
 8549        else {
 8550            return;
 8551        };
 8552
 8553        let reveal_strategy = action.reveal;
 8554        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8555        cx.spawn_in(window, async move |_, cx| {
 8556            let context = task_context.await?;
 8557            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8558
 8559            let resolved = &mut resolved_task.resolved;
 8560            resolved.reveal = reveal_strategy;
 8561
 8562            workspace
 8563                .update_in(cx, |workspace, window, cx| {
 8564                    workspace.schedule_resolved_task(
 8565                        task_source_kind,
 8566                        resolved_task,
 8567                        false,
 8568                        window,
 8569                        cx,
 8570                    );
 8571                })
 8572                .ok()
 8573        })
 8574        .detach();
 8575    }
 8576
 8577    fn find_closest_task(
 8578        &mut self,
 8579        cx: &mut Context<Self>,
 8580    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8581        let cursor_row = self
 8582            .selections
 8583            .newest_adjusted(&self.display_snapshot(cx))
 8584            .head()
 8585            .row;
 8586
 8587        let ((buffer_id, row), tasks) = self
 8588            .tasks
 8589            .iter()
 8590            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8591
 8592        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8593        let tasks = Arc::new(tasks.to_owned());
 8594        Some((buffer, *row, tasks))
 8595    }
 8596
 8597    fn find_enclosing_node_task(
 8598        &mut self,
 8599        cx: &mut Context<Self>,
 8600    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8601        let snapshot = self.buffer.read(cx).snapshot(cx);
 8602        let offset = self
 8603            .selections
 8604            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8605            .head();
 8606        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8607        let offset = excerpt.map_offset_to_buffer(offset);
 8608        let buffer_id = excerpt.buffer().remote_id();
 8609
 8610        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8611        let mut cursor = layer.node().walk();
 8612
 8613        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8614            if cursor.node().end_byte() == offset.0 {
 8615                cursor.goto_next_sibling();
 8616            }
 8617        }
 8618
 8619        // Ascend to the smallest ancestor that contains the range and has a task.
 8620        loop {
 8621            let node = cursor.node();
 8622            let node_range = node.byte_range();
 8623            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8624
 8625            // Check if this node contains our offset
 8626            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8627                // If it contains offset, check for task
 8628                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8629                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8630                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8631                }
 8632            }
 8633
 8634            if !cursor.goto_parent() {
 8635                break;
 8636            }
 8637        }
 8638        None
 8639    }
 8640
 8641    fn render_run_indicator(
 8642        &self,
 8643        _style: &EditorStyle,
 8644        is_active: bool,
 8645        row: DisplayRow,
 8646        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8647        cx: &mut Context<Self>,
 8648    ) -> IconButton {
 8649        let color = Color::Muted;
 8650        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8651
 8652        IconButton::new(
 8653            ("run_indicator", row.0 as usize),
 8654            ui::IconName::PlayOutlined,
 8655        )
 8656        .shape(ui::IconButtonShape::Square)
 8657        .icon_size(IconSize::XSmall)
 8658        .icon_color(color)
 8659        .toggle_state(is_active)
 8660        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8661            let quick_launch = match e {
 8662                ClickEvent::Keyboard(_) => true,
 8663                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8664            };
 8665
 8666            window.focus(&editor.focus_handle(cx));
 8667            editor.toggle_code_actions(
 8668                &ToggleCodeActions {
 8669                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8670                    quick_launch,
 8671                },
 8672                window,
 8673                cx,
 8674            );
 8675        }))
 8676        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8677            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8678        }))
 8679    }
 8680
 8681    pub fn context_menu_visible(&self) -> bool {
 8682        !self.edit_prediction_preview_is_active()
 8683            && self
 8684                .context_menu
 8685                .borrow()
 8686                .as_ref()
 8687                .is_some_and(|menu| menu.visible())
 8688    }
 8689
 8690    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8691        self.context_menu
 8692            .borrow()
 8693            .as_ref()
 8694            .map(|menu| menu.origin())
 8695    }
 8696
 8697    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8698        self.context_menu_options = Some(options);
 8699    }
 8700
 8701    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8702    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8703
 8704    fn render_edit_prediction_popover(
 8705        &mut self,
 8706        text_bounds: &Bounds<Pixels>,
 8707        content_origin: gpui::Point<Pixels>,
 8708        right_margin: Pixels,
 8709        editor_snapshot: &EditorSnapshot,
 8710        visible_row_range: Range<DisplayRow>,
 8711        scroll_top: ScrollOffset,
 8712        scroll_bottom: ScrollOffset,
 8713        line_layouts: &[LineWithInvisibles],
 8714        line_height: Pixels,
 8715        scroll_position: gpui::Point<ScrollOffset>,
 8716        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8717        newest_selection_head: Option<DisplayPoint>,
 8718        editor_width: Pixels,
 8719        style: &EditorStyle,
 8720        window: &mut Window,
 8721        cx: &mut App,
 8722    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8723        if self.mode().is_minimap() {
 8724            return None;
 8725        }
 8726        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8727
 8728        if self.edit_prediction_visible_in_cursor_popover(true) {
 8729            return None;
 8730        }
 8731
 8732        match &active_edit_prediction.completion {
 8733            EditPrediction::MoveWithin { target, .. } => {
 8734                let target_display_point = target.to_display_point(editor_snapshot);
 8735
 8736                if self.edit_prediction_requires_modifier() {
 8737                    if !self.edit_prediction_preview_is_active() {
 8738                        return None;
 8739                    }
 8740
 8741                    self.render_edit_prediction_modifier_jump_popover(
 8742                        text_bounds,
 8743                        content_origin,
 8744                        visible_row_range,
 8745                        line_layouts,
 8746                        line_height,
 8747                        scroll_pixel_position,
 8748                        newest_selection_head,
 8749                        target_display_point,
 8750                        window,
 8751                        cx,
 8752                    )
 8753                } else {
 8754                    self.render_edit_prediction_eager_jump_popover(
 8755                        text_bounds,
 8756                        content_origin,
 8757                        editor_snapshot,
 8758                        visible_row_range,
 8759                        scroll_top,
 8760                        scroll_bottom,
 8761                        line_height,
 8762                        scroll_pixel_position,
 8763                        target_display_point,
 8764                        editor_width,
 8765                        window,
 8766                        cx,
 8767                    )
 8768                }
 8769            }
 8770            EditPrediction::Edit {
 8771                display_mode: EditDisplayMode::Inline,
 8772                ..
 8773            } => None,
 8774            EditPrediction::Edit {
 8775                display_mode: EditDisplayMode::TabAccept,
 8776                edits,
 8777                ..
 8778            } => {
 8779                let range = &edits.first()?.0;
 8780                let target_display_point = range.end.to_display_point(editor_snapshot);
 8781
 8782                self.render_edit_prediction_end_of_line_popover(
 8783                    "Accept",
 8784                    editor_snapshot,
 8785                    visible_row_range,
 8786                    target_display_point,
 8787                    line_height,
 8788                    scroll_pixel_position,
 8789                    content_origin,
 8790                    editor_width,
 8791                    window,
 8792                    cx,
 8793                )
 8794            }
 8795            EditPrediction::Edit {
 8796                edits,
 8797                edit_preview,
 8798                display_mode: EditDisplayMode::DiffPopover,
 8799                snapshot,
 8800            } => self.render_edit_prediction_diff_popover(
 8801                text_bounds,
 8802                content_origin,
 8803                right_margin,
 8804                editor_snapshot,
 8805                visible_row_range,
 8806                line_layouts,
 8807                line_height,
 8808                scroll_position,
 8809                scroll_pixel_position,
 8810                newest_selection_head,
 8811                editor_width,
 8812                style,
 8813                edits,
 8814                edit_preview,
 8815                snapshot,
 8816                window,
 8817                cx,
 8818            ),
 8819            EditPrediction::MoveOutside { snapshot, .. } => {
 8820                let mut element = self
 8821                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8822                    .into_any();
 8823
 8824                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8825                let origin_x = text_bounds.size.width - size.width - px(30.);
 8826                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8827                element.prepaint_at(origin, window, cx);
 8828
 8829                Some((element, origin))
 8830            }
 8831        }
 8832    }
 8833
 8834    fn render_edit_prediction_modifier_jump_popover(
 8835        &mut self,
 8836        text_bounds: &Bounds<Pixels>,
 8837        content_origin: gpui::Point<Pixels>,
 8838        visible_row_range: Range<DisplayRow>,
 8839        line_layouts: &[LineWithInvisibles],
 8840        line_height: Pixels,
 8841        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8842        newest_selection_head: Option<DisplayPoint>,
 8843        target_display_point: DisplayPoint,
 8844        window: &mut Window,
 8845        cx: &mut App,
 8846    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8847        let scrolled_content_origin =
 8848            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8849
 8850        const SCROLL_PADDING_Y: Pixels = px(12.);
 8851
 8852        if target_display_point.row() < visible_row_range.start {
 8853            return self.render_edit_prediction_scroll_popover(
 8854                |_| SCROLL_PADDING_Y,
 8855                IconName::ArrowUp,
 8856                visible_row_range,
 8857                line_layouts,
 8858                newest_selection_head,
 8859                scrolled_content_origin,
 8860                window,
 8861                cx,
 8862            );
 8863        } else if target_display_point.row() >= visible_row_range.end {
 8864            return self.render_edit_prediction_scroll_popover(
 8865                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8866                IconName::ArrowDown,
 8867                visible_row_range,
 8868                line_layouts,
 8869                newest_selection_head,
 8870                scrolled_content_origin,
 8871                window,
 8872                cx,
 8873            );
 8874        }
 8875
 8876        const POLE_WIDTH: Pixels = px(2.);
 8877
 8878        let line_layout =
 8879            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8880        let target_column = target_display_point.column() as usize;
 8881
 8882        let target_x = line_layout.x_for_index(target_column);
 8883        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8884            - scroll_pixel_position.y;
 8885
 8886        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8887
 8888        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8889        border_color.l += 0.001;
 8890
 8891        let mut element = v_flex()
 8892            .items_end()
 8893            .when(flag_on_right, |el| el.items_start())
 8894            .child(if flag_on_right {
 8895                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8896                    .rounded_bl(px(0.))
 8897                    .rounded_tl(px(0.))
 8898                    .border_l_2()
 8899                    .border_color(border_color)
 8900            } else {
 8901                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8902                    .rounded_br(px(0.))
 8903                    .rounded_tr(px(0.))
 8904                    .border_r_2()
 8905                    .border_color(border_color)
 8906            })
 8907            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8908            .into_any();
 8909
 8910        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8911
 8912        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8913            - point(
 8914                if flag_on_right {
 8915                    POLE_WIDTH
 8916                } else {
 8917                    size.width - POLE_WIDTH
 8918                },
 8919                size.height - line_height,
 8920            );
 8921
 8922        origin.x = origin.x.max(content_origin.x);
 8923
 8924        element.prepaint_at(origin, window, cx);
 8925
 8926        Some((element, origin))
 8927    }
 8928
 8929    fn render_edit_prediction_scroll_popover(
 8930        &mut self,
 8931        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8932        scroll_icon: IconName,
 8933        visible_row_range: Range<DisplayRow>,
 8934        line_layouts: &[LineWithInvisibles],
 8935        newest_selection_head: Option<DisplayPoint>,
 8936        scrolled_content_origin: gpui::Point<Pixels>,
 8937        window: &mut Window,
 8938        cx: &mut App,
 8939    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8940        let mut element = self
 8941            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8942            .into_any();
 8943
 8944        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8945
 8946        let cursor = newest_selection_head?;
 8947        let cursor_row_layout =
 8948            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8949        let cursor_column = cursor.column() as usize;
 8950
 8951        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8952
 8953        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8954
 8955        element.prepaint_at(origin, window, cx);
 8956        Some((element, origin))
 8957    }
 8958
 8959    fn render_edit_prediction_eager_jump_popover(
 8960        &mut self,
 8961        text_bounds: &Bounds<Pixels>,
 8962        content_origin: gpui::Point<Pixels>,
 8963        editor_snapshot: &EditorSnapshot,
 8964        visible_row_range: Range<DisplayRow>,
 8965        scroll_top: ScrollOffset,
 8966        scroll_bottom: ScrollOffset,
 8967        line_height: Pixels,
 8968        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8969        target_display_point: DisplayPoint,
 8970        editor_width: Pixels,
 8971        window: &mut Window,
 8972        cx: &mut App,
 8973    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8974        if target_display_point.row().as_f64() < scroll_top {
 8975            let mut element = self
 8976                .render_edit_prediction_line_popover(
 8977                    "Jump to Edit",
 8978                    Some(IconName::ArrowUp),
 8979                    window,
 8980                    cx,
 8981                )
 8982                .into_any();
 8983
 8984            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8985            let offset = point(
 8986                (text_bounds.size.width - size.width) / 2.,
 8987                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8988            );
 8989
 8990            let origin = text_bounds.origin + offset;
 8991            element.prepaint_at(origin, window, cx);
 8992            Some((element, origin))
 8993        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8994            let mut element = self
 8995                .render_edit_prediction_line_popover(
 8996                    "Jump to Edit",
 8997                    Some(IconName::ArrowDown),
 8998                    window,
 8999                    cx,
 9000                )
 9001                .into_any();
 9002
 9003            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9004            let offset = point(
 9005                (text_bounds.size.width - size.width) / 2.,
 9006                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9007            );
 9008
 9009            let origin = text_bounds.origin + offset;
 9010            element.prepaint_at(origin, window, cx);
 9011            Some((element, origin))
 9012        } else {
 9013            self.render_edit_prediction_end_of_line_popover(
 9014                "Jump to Edit",
 9015                editor_snapshot,
 9016                visible_row_range,
 9017                target_display_point,
 9018                line_height,
 9019                scroll_pixel_position,
 9020                content_origin,
 9021                editor_width,
 9022                window,
 9023                cx,
 9024            )
 9025        }
 9026    }
 9027
 9028    fn render_edit_prediction_end_of_line_popover(
 9029        self: &mut Editor,
 9030        label: &'static str,
 9031        editor_snapshot: &EditorSnapshot,
 9032        visible_row_range: Range<DisplayRow>,
 9033        target_display_point: DisplayPoint,
 9034        line_height: Pixels,
 9035        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9036        content_origin: gpui::Point<Pixels>,
 9037        editor_width: Pixels,
 9038        window: &mut Window,
 9039        cx: &mut App,
 9040    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9041        let target_line_end = DisplayPoint::new(
 9042            target_display_point.row(),
 9043            editor_snapshot.line_len(target_display_point.row()),
 9044        );
 9045
 9046        let mut element = self
 9047            .render_edit_prediction_line_popover(label, None, window, cx)
 9048            .into_any();
 9049
 9050        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9051
 9052        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9053
 9054        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9055        let mut origin = start_point
 9056            + line_origin
 9057            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9058        origin.x = origin.x.max(content_origin.x);
 9059
 9060        let max_x = content_origin.x + editor_width - size.width;
 9061
 9062        if origin.x > max_x {
 9063            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9064
 9065            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9066                origin.y += offset;
 9067                IconName::ArrowUp
 9068            } else {
 9069                origin.y -= offset;
 9070                IconName::ArrowDown
 9071            };
 9072
 9073            element = self
 9074                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9075                .into_any();
 9076
 9077            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9078
 9079            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9080        }
 9081
 9082        element.prepaint_at(origin, window, cx);
 9083        Some((element, origin))
 9084    }
 9085
 9086    fn render_edit_prediction_diff_popover(
 9087        self: &Editor,
 9088        text_bounds: &Bounds<Pixels>,
 9089        content_origin: gpui::Point<Pixels>,
 9090        right_margin: Pixels,
 9091        editor_snapshot: &EditorSnapshot,
 9092        visible_row_range: Range<DisplayRow>,
 9093        line_layouts: &[LineWithInvisibles],
 9094        line_height: Pixels,
 9095        scroll_position: gpui::Point<ScrollOffset>,
 9096        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9097        newest_selection_head: Option<DisplayPoint>,
 9098        editor_width: Pixels,
 9099        style: &EditorStyle,
 9100        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9101        edit_preview: &Option<language::EditPreview>,
 9102        snapshot: &language::BufferSnapshot,
 9103        window: &mut Window,
 9104        cx: &mut App,
 9105    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9106        let edit_start = edits
 9107            .first()
 9108            .unwrap()
 9109            .0
 9110            .start
 9111            .to_display_point(editor_snapshot);
 9112        let edit_end = edits
 9113            .last()
 9114            .unwrap()
 9115            .0
 9116            .end
 9117            .to_display_point(editor_snapshot);
 9118
 9119        let is_visible = visible_row_range.contains(&edit_start.row())
 9120            || visible_row_range.contains(&edit_end.row());
 9121        if !is_visible {
 9122            return None;
 9123        }
 9124
 9125        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9126            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9127        } else {
 9128            // Fallback for providers without edit_preview
 9129            crate::edit_prediction_fallback_text(edits, cx)
 9130        };
 9131
 9132        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9133        let line_count = highlighted_edits.text.lines().count();
 9134
 9135        const BORDER_WIDTH: Pixels = px(1.);
 9136
 9137        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9138        let has_keybind = keybind.is_some();
 9139
 9140        let mut element = h_flex()
 9141            .items_start()
 9142            .child(
 9143                h_flex()
 9144                    .bg(cx.theme().colors().editor_background)
 9145                    .border(BORDER_WIDTH)
 9146                    .shadow_xs()
 9147                    .border_color(cx.theme().colors().border)
 9148                    .rounded_l_lg()
 9149                    .when(line_count > 1, |el| el.rounded_br_lg())
 9150                    .pr_1()
 9151                    .child(styled_text),
 9152            )
 9153            .child(
 9154                h_flex()
 9155                    .h(line_height + BORDER_WIDTH * 2.)
 9156                    .px_1p5()
 9157                    .gap_1()
 9158                    // Workaround: For some reason, there's a gap if we don't do this
 9159                    .ml(-BORDER_WIDTH)
 9160                    .shadow(vec![gpui::BoxShadow {
 9161                        color: gpui::black().opacity(0.05),
 9162                        offset: point(px(1.), px(1.)),
 9163                        blur_radius: px(2.),
 9164                        spread_radius: px(0.),
 9165                    }])
 9166                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9167                    .border(BORDER_WIDTH)
 9168                    .border_color(cx.theme().colors().border)
 9169                    .rounded_r_lg()
 9170                    .id("edit_prediction_diff_popover_keybind")
 9171                    .when(!has_keybind, |el| {
 9172                        let status_colors = cx.theme().status();
 9173
 9174                        el.bg(status_colors.error_background)
 9175                            .border_color(status_colors.error.opacity(0.6))
 9176                            .child(Icon::new(IconName::Info).color(Color::Error))
 9177                            .cursor_default()
 9178                            .hoverable_tooltip(move |_window, cx| {
 9179                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9180                            })
 9181                    })
 9182                    .children(keybind),
 9183            )
 9184            .into_any();
 9185
 9186        let longest_row =
 9187            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9188        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9189            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9190        } else {
 9191            layout_line(
 9192                longest_row,
 9193                editor_snapshot,
 9194                style,
 9195                editor_width,
 9196                |_| false,
 9197                window,
 9198                cx,
 9199            )
 9200            .width
 9201        };
 9202
 9203        let viewport_bounds =
 9204            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9205                right: -right_margin,
 9206                ..Default::default()
 9207            });
 9208
 9209        let x_after_longest = Pixels::from(
 9210            ScrollPixelOffset::from(
 9211                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9212            ) - scroll_pixel_position.x,
 9213        );
 9214
 9215        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9216
 9217        // Fully visible if it can be displayed within the window (allow overlapping other
 9218        // panes). However, this is only allowed if the popover starts within text_bounds.
 9219        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9220            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9221
 9222        let mut origin = if can_position_to_the_right {
 9223            point(
 9224                x_after_longest,
 9225                text_bounds.origin.y
 9226                    + Pixels::from(
 9227                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9228                            - scroll_pixel_position.y,
 9229                    ),
 9230            )
 9231        } else {
 9232            let cursor_row = newest_selection_head.map(|head| head.row());
 9233            let above_edit = edit_start
 9234                .row()
 9235                .0
 9236                .checked_sub(line_count as u32)
 9237                .map(DisplayRow);
 9238            let below_edit = Some(edit_end.row() + 1);
 9239            let above_cursor =
 9240                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9241            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9242
 9243            // Place the edit popover adjacent to the edit if there is a location
 9244            // available that is onscreen and does not obscure the cursor. Otherwise,
 9245            // place it adjacent to the cursor.
 9246            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9247                .into_iter()
 9248                .flatten()
 9249                .find(|&start_row| {
 9250                    let end_row = start_row + line_count as u32;
 9251                    visible_row_range.contains(&start_row)
 9252                        && visible_row_range.contains(&end_row)
 9253                        && cursor_row
 9254                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9255                })?;
 9256
 9257            content_origin
 9258                + point(
 9259                    Pixels::from(-scroll_pixel_position.x),
 9260                    Pixels::from(
 9261                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9262                    ),
 9263                )
 9264        };
 9265
 9266        origin.x -= BORDER_WIDTH;
 9267
 9268        window.defer_draw(element, origin, 1);
 9269
 9270        // Do not return an element, since it will already be drawn due to defer_draw.
 9271        None
 9272    }
 9273
 9274    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9275        px(30.)
 9276    }
 9277
 9278    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9279        if self.read_only(cx) {
 9280            cx.theme().players().read_only()
 9281        } else {
 9282            self.style.as_ref().unwrap().local_player
 9283        }
 9284    }
 9285
 9286    fn render_edit_prediction_accept_keybind(
 9287        &self,
 9288        window: &mut Window,
 9289        cx: &mut App,
 9290    ) -> Option<AnyElement> {
 9291        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9292        let accept_keystroke = accept_binding.keystroke()?;
 9293
 9294        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9295
 9296        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9297            Color::Accent
 9298        } else {
 9299            Color::Muted
 9300        };
 9301
 9302        h_flex()
 9303            .px_0p5()
 9304            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9305            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9306            .text_size(TextSize::XSmall.rems(cx))
 9307            .child(h_flex().children(ui::render_modifiers(
 9308                accept_keystroke.modifiers(),
 9309                PlatformStyle::platform(),
 9310                Some(modifiers_color),
 9311                Some(IconSize::XSmall.rems().into()),
 9312                true,
 9313            )))
 9314            .when(is_platform_style_mac, |parent| {
 9315                parent.child(accept_keystroke.key().to_string())
 9316            })
 9317            .when(!is_platform_style_mac, |parent| {
 9318                parent.child(
 9319                    Key::new(
 9320                        util::capitalize(accept_keystroke.key()),
 9321                        Some(Color::Default),
 9322                    )
 9323                    .size(Some(IconSize::XSmall.rems().into())),
 9324                )
 9325            })
 9326            .into_any()
 9327            .into()
 9328    }
 9329
 9330    fn render_edit_prediction_line_popover(
 9331        &self,
 9332        label: impl Into<SharedString>,
 9333        icon: Option<IconName>,
 9334        window: &mut Window,
 9335        cx: &mut App,
 9336    ) -> Stateful<Div> {
 9337        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9338
 9339        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9340        let has_keybind = keybind.is_some();
 9341
 9342        h_flex()
 9343            .id("ep-line-popover")
 9344            .py_0p5()
 9345            .pl_1()
 9346            .pr(padding_right)
 9347            .gap_1()
 9348            .rounded_md()
 9349            .border_1()
 9350            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9351            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9352            .shadow_xs()
 9353            .when(!has_keybind, |el| {
 9354                let status_colors = cx.theme().status();
 9355
 9356                el.bg(status_colors.error_background)
 9357                    .border_color(status_colors.error.opacity(0.6))
 9358                    .pl_2()
 9359                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9360                    .cursor_default()
 9361                    .hoverable_tooltip(move |_window, cx| {
 9362                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9363                    })
 9364            })
 9365            .children(keybind)
 9366            .child(
 9367                Label::new(label)
 9368                    .size(LabelSize::Small)
 9369                    .when(!has_keybind, |el| {
 9370                        el.color(cx.theme().status().error.into()).strikethrough()
 9371                    }),
 9372            )
 9373            .when(!has_keybind, |el| {
 9374                el.child(
 9375                    h_flex().ml_1().child(
 9376                        Icon::new(IconName::Info)
 9377                            .size(IconSize::Small)
 9378                            .color(cx.theme().status().error.into()),
 9379                    ),
 9380                )
 9381            })
 9382            .when_some(icon, |element, icon| {
 9383                element.child(
 9384                    div()
 9385                        .mt(px(1.5))
 9386                        .child(Icon::new(icon).size(IconSize::Small)),
 9387                )
 9388            })
 9389    }
 9390
 9391    fn render_edit_prediction_jump_outside_popover(
 9392        &self,
 9393        snapshot: &BufferSnapshot,
 9394        window: &mut Window,
 9395        cx: &mut App,
 9396    ) -> Stateful<Div> {
 9397        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9398        let has_keybind = keybind.is_some();
 9399
 9400        let file_name = snapshot
 9401            .file()
 9402            .map(|file| SharedString::new(file.file_name(cx)))
 9403            .unwrap_or(SharedString::new_static("untitled"));
 9404
 9405        h_flex()
 9406            .id("ep-jump-outside-popover")
 9407            .py_1()
 9408            .px_2()
 9409            .gap_1()
 9410            .rounded_md()
 9411            .border_1()
 9412            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9413            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9414            .shadow_xs()
 9415            .when(!has_keybind, |el| {
 9416                let status_colors = cx.theme().status();
 9417
 9418                el.bg(status_colors.error_background)
 9419                    .border_color(status_colors.error.opacity(0.6))
 9420                    .pl_2()
 9421                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9422                    .cursor_default()
 9423                    .hoverable_tooltip(move |_window, cx| {
 9424                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9425                    })
 9426            })
 9427            .children(keybind)
 9428            .child(
 9429                Label::new(file_name)
 9430                    .size(LabelSize::Small)
 9431                    .buffer_font(cx)
 9432                    .when(!has_keybind, |el| {
 9433                        el.color(cx.theme().status().error.into()).strikethrough()
 9434                    }),
 9435            )
 9436            .when(!has_keybind, |el| {
 9437                el.child(
 9438                    h_flex().ml_1().child(
 9439                        Icon::new(IconName::Info)
 9440                            .size(IconSize::Small)
 9441                            .color(cx.theme().status().error.into()),
 9442                    ),
 9443                )
 9444            })
 9445            .child(
 9446                div()
 9447                    .mt(px(1.5))
 9448                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9449            )
 9450    }
 9451
 9452    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9453        let accent_color = cx.theme().colors().text_accent;
 9454        let editor_bg_color = cx.theme().colors().editor_background;
 9455        editor_bg_color.blend(accent_color.opacity(0.1))
 9456    }
 9457
 9458    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9459        let accent_color = cx.theme().colors().text_accent;
 9460        let editor_bg_color = cx.theme().colors().editor_background;
 9461        editor_bg_color.blend(accent_color.opacity(0.6))
 9462    }
 9463    fn get_prediction_provider_icon_name(
 9464        provider: &Option<RegisteredEditPredictionProvider>,
 9465    ) -> IconName {
 9466        match provider {
 9467            Some(provider) => match provider.provider.name() {
 9468                "copilot" => IconName::Copilot,
 9469                "supermaven" => IconName::Supermaven,
 9470                _ => IconName::ZedPredict,
 9471            },
 9472            None => IconName::ZedPredict,
 9473        }
 9474    }
 9475
 9476    fn render_edit_prediction_cursor_popover(
 9477        &self,
 9478        min_width: Pixels,
 9479        max_width: Pixels,
 9480        cursor_point: Point,
 9481        style: &EditorStyle,
 9482        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9483        _window: &Window,
 9484        cx: &mut Context<Editor>,
 9485    ) -> Option<AnyElement> {
 9486        let provider = self.edit_prediction_provider.as_ref()?;
 9487        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9488
 9489        let is_refreshing = provider.provider.is_refreshing(cx);
 9490
 9491        fn pending_completion_container(icon: IconName) -> Div {
 9492            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9493        }
 9494
 9495        let completion = match &self.active_edit_prediction {
 9496            Some(prediction) => {
 9497                if !self.has_visible_completions_menu() {
 9498                    const RADIUS: Pixels = px(6.);
 9499                    const BORDER_WIDTH: Pixels = px(1.);
 9500
 9501                    return Some(
 9502                        h_flex()
 9503                            .elevation_2(cx)
 9504                            .border(BORDER_WIDTH)
 9505                            .border_color(cx.theme().colors().border)
 9506                            .when(accept_keystroke.is_none(), |el| {
 9507                                el.border_color(cx.theme().status().error)
 9508                            })
 9509                            .rounded(RADIUS)
 9510                            .rounded_tl(px(0.))
 9511                            .overflow_hidden()
 9512                            .child(div().px_1p5().child(match &prediction.completion {
 9513                                EditPrediction::MoveWithin { target, snapshot } => {
 9514                                    use text::ToPoint as _;
 9515                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9516                                    {
 9517                                        Icon::new(IconName::ZedPredictDown)
 9518                                    } else {
 9519                                        Icon::new(IconName::ZedPredictUp)
 9520                                    }
 9521                                }
 9522                                EditPrediction::MoveOutside { .. } => {
 9523                                    // TODO [zeta2] custom icon for external jump?
 9524                                    Icon::new(provider_icon)
 9525                                }
 9526                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9527                            }))
 9528                            .child(
 9529                                h_flex()
 9530                                    .gap_1()
 9531                                    .py_1()
 9532                                    .px_2()
 9533                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9534                                    .border_l_1()
 9535                                    .border_color(cx.theme().colors().border)
 9536                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9537                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9538                                        el.child(
 9539                                            Label::new("Hold")
 9540                                                .size(LabelSize::Small)
 9541                                                .when(accept_keystroke.is_none(), |el| {
 9542                                                    el.strikethrough()
 9543                                                })
 9544                                                .line_height_style(LineHeightStyle::UiLabel),
 9545                                        )
 9546                                    })
 9547                                    .id("edit_prediction_cursor_popover_keybind")
 9548                                    .when(accept_keystroke.is_none(), |el| {
 9549                                        let status_colors = cx.theme().status();
 9550
 9551                                        el.bg(status_colors.error_background)
 9552                                            .border_color(status_colors.error.opacity(0.6))
 9553                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9554                                            .cursor_default()
 9555                                            .hoverable_tooltip(move |_window, cx| {
 9556                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9557                                                    .into()
 9558                                            })
 9559                                    })
 9560                                    .when_some(
 9561                                        accept_keystroke.as_ref(),
 9562                                        |el, accept_keystroke| {
 9563                                            el.child(h_flex().children(ui::render_modifiers(
 9564                                                accept_keystroke.modifiers(),
 9565                                                PlatformStyle::platform(),
 9566                                                Some(Color::Default),
 9567                                                Some(IconSize::XSmall.rems().into()),
 9568                                                false,
 9569                                            )))
 9570                                        },
 9571                                    ),
 9572                            )
 9573                            .into_any(),
 9574                    );
 9575                }
 9576
 9577                self.render_edit_prediction_cursor_popover_preview(
 9578                    prediction,
 9579                    cursor_point,
 9580                    style,
 9581                    cx,
 9582                )?
 9583            }
 9584
 9585            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9586                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9587                    stale_completion,
 9588                    cursor_point,
 9589                    style,
 9590                    cx,
 9591                )?,
 9592
 9593                None => pending_completion_container(provider_icon)
 9594                    .child(Label::new("...").size(LabelSize::Small)),
 9595            },
 9596
 9597            None => pending_completion_container(provider_icon)
 9598                .child(Label::new("...").size(LabelSize::Small)),
 9599        };
 9600
 9601        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9602            completion
 9603                .with_animation(
 9604                    "loading-completion",
 9605                    Animation::new(Duration::from_secs(2))
 9606                        .repeat()
 9607                        .with_easing(pulsating_between(0.4, 0.8)),
 9608                    |label, delta| label.opacity(delta),
 9609                )
 9610                .into_any_element()
 9611        } else {
 9612            completion.into_any_element()
 9613        };
 9614
 9615        let has_completion = self.active_edit_prediction.is_some();
 9616
 9617        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9618        Some(
 9619            h_flex()
 9620                .min_w(min_width)
 9621                .max_w(max_width)
 9622                .flex_1()
 9623                .elevation_2(cx)
 9624                .border_color(cx.theme().colors().border)
 9625                .child(
 9626                    div()
 9627                        .flex_1()
 9628                        .py_1()
 9629                        .px_2()
 9630                        .overflow_hidden()
 9631                        .child(completion),
 9632                )
 9633                .when_some(accept_keystroke, |el, accept_keystroke| {
 9634                    if !accept_keystroke.modifiers().modified() {
 9635                        return el;
 9636                    }
 9637
 9638                    el.child(
 9639                        h_flex()
 9640                            .h_full()
 9641                            .border_l_1()
 9642                            .rounded_r_lg()
 9643                            .border_color(cx.theme().colors().border)
 9644                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9645                            .gap_1()
 9646                            .py_1()
 9647                            .px_2()
 9648                            .child(
 9649                                h_flex()
 9650                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9651                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9652                                    .child(h_flex().children(ui::render_modifiers(
 9653                                        accept_keystroke.modifiers(),
 9654                                        PlatformStyle::platform(),
 9655                                        Some(if !has_completion {
 9656                                            Color::Muted
 9657                                        } else {
 9658                                            Color::Default
 9659                                        }),
 9660                                        None,
 9661                                        false,
 9662                                    ))),
 9663                            )
 9664                            .child(Label::new("Preview").into_any_element())
 9665                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9666                    )
 9667                })
 9668                .into_any(),
 9669        )
 9670    }
 9671
 9672    fn render_edit_prediction_cursor_popover_preview(
 9673        &self,
 9674        completion: &EditPredictionState,
 9675        cursor_point: Point,
 9676        style: &EditorStyle,
 9677        cx: &mut Context<Editor>,
 9678    ) -> Option<Div> {
 9679        use text::ToPoint as _;
 9680
 9681        fn render_relative_row_jump(
 9682            prefix: impl Into<String>,
 9683            current_row: u32,
 9684            target_row: u32,
 9685        ) -> Div {
 9686            let (row_diff, arrow) = if target_row < current_row {
 9687                (current_row - target_row, IconName::ArrowUp)
 9688            } else {
 9689                (target_row - current_row, IconName::ArrowDown)
 9690            };
 9691
 9692            h_flex()
 9693                .child(
 9694                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9695                        .color(Color::Muted)
 9696                        .size(LabelSize::Small),
 9697                )
 9698                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9699        }
 9700
 9701        let supports_jump = self
 9702            .edit_prediction_provider
 9703            .as_ref()
 9704            .map(|provider| provider.provider.supports_jump_to_edit())
 9705            .unwrap_or(true);
 9706
 9707        match &completion.completion {
 9708            EditPrediction::MoveWithin {
 9709                target, snapshot, ..
 9710            } => {
 9711                if !supports_jump {
 9712                    return None;
 9713                }
 9714
 9715                Some(
 9716                    h_flex()
 9717                        .px_2()
 9718                        .gap_2()
 9719                        .flex_1()
 9720                        .child(
 9721                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9722                                Icon::new(IconName::ZedPredictDown)
 9723                            } else {
 9724                                Icon::new(IconName::ZedPredictUp)
 9725                            },
 9726                        )
 9727                        .child(Label::new("Jump to Edit")),
 9728                )
 9729            }
 9730            EditPrediction::MoveOutside { snapshot, .. } => {
 9731                let file_name = snapshot
 9732                    .file()
 9733                    .map(|file| file.file_name(cx))
 9734                    .unwrap_or("untitled");
 9735                Some(
 9736                    h_flex()
 9737                        .px_2()
 9738                        .gap_2()
 9739                        .flex_1()
 9740                        .child(Icon::new(IconName::ZedPredict))
 9741                        .child(Label::new(format!("Jump to {file_name}"))),
 9742                )
 9743            }
 9744            EditPrediction::Edit {
 9745                edits,
 9746                edit_preview,
 9747                snapshot,
 9748                display_mode: _,
 9749            } => {
 9750                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9751
 9752                let (highlighted_edits, has_more_lines) =
 9753                    if let Some(edit_preview) = edit_preview.as_ref() {
 9754                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9755                            .first_line_preview()
 9756                    } else {
 9757                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9758                    };
 9759
 9760                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9761                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9762
 9763                let preview = h_flex()
 9764                    .gap_1()
 9765                    .min_w_16()
 9766                    .child(styled_text)
 9767                    .when(has_more_lines, |parent| parent.child(""));
 9768
 9769                let left = if supports_jump && first_edit_row != cursor_point.row {
 9770                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9771                        .into_any_element()
 9772                } else {
 9773                    let icon_name =
 9774                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9775                    Icon::new(icon_name).into_any_element()
 9776                };
 9777
 9778                Some(
 9779                    h_flex()
 9780                        .h_full()
 9781                        .flex_1()
 9782                        .gap_2()
 9783                        .pr_1()
 9784                        .overflow_x_hidden()
 9785                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9786                        .child(left)
 9787                        .child(preview),
 9788                )
 9789            }
 9790        }
 9791    }
 9792
 9793    pub fn render_context_menu(
 9794        &self,
 9795        style: &EditorStyle,
 9796        max_height_in_lines: u32,
 9797        window: &mut Window,
 9798        cx: &mut Context<Editor>,
 9799    ) -> Option<AnyElement> {
 9800        let menu = self.context_menu.borrow();
 9801        let menu = menu.as_ref()?;
 9802        if !menu.visible() {
 9803            return None;
 9804        };
 9805        Some(menu.render(style, max_height_in_lines, window, cx))
 9806    }
 9807
 9808    fn render_context_menu_aside(
 9809        &mut self,
 9810        max_size: Size<Pixels>,
 9811        window: &mut Window,
 9812        cx: &mut Context<Editor>,
 9813    ) -> Option<AnyElement> {
 9814        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9815            if menu.visible() {
 9816                menu.render_aside(max_size, window, cx)
 9817            } else {
 9818                None
 9819            }
 9820        })
 9821    }
 9822
 9823    fn hide_context_menu(
 9824        &mut self,
 9825        window: &mut Window,
 9826        cx: &mut Context<Self>,
 9827    ) -> Option<CodeContextMenu> {
 9828        cx.notify();
 9829        self.completion_tasks.clear();
 9830        let context_menu = self.context_menu.borrow_mut().take();
 9831        self.stale_edit_prediction_in_menu.take();
 9832        self.update_visible_edit_prediction(window, cx);
 9833        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9834            && let Some(completion_provider) = &self.completion_provider
 9835        {
 9836            completion_provider.selection_changed(None, window, cx);
 9837        }
 9838        context_menu
 9839    }
 9840
 9841    fn show_snippet_choices(
 9842        &mut self,
 9843        choices: &Vec<String>,
 9844        selection: Range<Anchor>,
 9845        cx: &mut Context<Self>,
 9846    ) {
 9847        let Some((_, buffer, _)) = self
 9848            .buffer()
 9849            .read(cx)
 9850            .excerpt_containing(selection.start, cx)
 9851        else {
 9852            return;
 9853        };
 9854        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9855        else {
 9856            return;
 9857        };
 9858        if buffer != end_buffer {
 9859            log::error!("expected anchor range to have matching buffer IDs");
 9860            return;
 9861        }
 9862
 9863        let id = post_inc(&mut self.next_completion_id);
 9864        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9865        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9866            CompletionsMenu::new_snippet_choices(
 9867                id,
 9868                true,
 9869                choices,
 9870                selection,
 9871                buffer,
 9872                snippet_sort_order,
 9873            ),
 9874        ));
 9875    }
 9876
 9877    pub fn insert_snippet(
 9878        &mut self,
 9879        insertion_ranges: &[Range<MultiBufferOffset>],
 9880        snippet: Snippet,
 9881        window: &mut Window,
 9882        cx: &mut Context<Self>,
 9883    ) -> Result<()> {
 9884        struct Tabstop<T> {
 9885            is_end_tabstop: bool,
 9886            ranges: Vec<Range<T>>,
 9887            choices: Option<Vec<String>>,
 9888        }
 9889
 9890        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9891            let snippet_text: Arc<str> = snippet.text.clone().into();
 9892            let edits = insertion_ranges
 9893                .iter()
 9894                .cloned()
 9895                .map(|range| (range, snippet_text.clone()));
 9896            let autoindent_mode = AutoindentMode::Block {
 9897                original_indent_columns: Vec::new(),
 9898            };
 9899            buffer.edit(edits, Some(autoindent_mode), cx);
 9900
 9901            let snapshot = &*buffer.read(cx);
 9902            let snippet = &snippet;
 9903            snippet
 9904                .tabstops
 9905                .iter()
 9906                .map(|tabstop| {
 9907                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9908                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9909                    });
 9910                    let mut tabstop_ranges = tabstop
 9911                        .ranges
 9912                        .iter()
 9913                        .flat_map(|tabstop_range| {
 9914                            let mut delta = 0_isize;
 9915                            insertion_ranges.iter().map(move |insertion_range| {
 9916                                let insertion_start = insertion_range.start + delta;
 9917                                delta += snippet.text.len() as isize
 9918                                    - (insertion_range.end - insertion_range.start) as isize;
 9919
 9920                                let start =
 9921                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9922                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9923                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9924                            })
 9925                        })
 9926                        .collect::<Vec<_>>();
 9927                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9928
 9929                    Tabstop {
 9930                        is_end_tabstop,
 9931                        ranges: tabstop_ranges,
 9932                        choices: tabstop.choices.clone(),
 9933                    }
 9934                })
 9935                .collect::<Vec<_>>()
 9936        });
 9937        if let Some(tabstop) = tabstops.first() {
 9938            self.change_selections(Default::default(), window, cx, |s| {
 9939                // Reverse order so that the first range is the newest created selection.
 9940                // Completions will use it and autoscroll will prioritize it.
 9941                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9942            });
 9943
 9944            if let Some(choices) = &tabstop.choices
 9945                && let Some(selection) = tabstop.ranges.first()
 9946            {
 9947                self.show_snippet_choices(choices, selection.clone(), cx)
 9948            }
 9949
 9950            // If we're already at the last tabstop and it's at the end of the snippet,
 9951            // we're done, we don't need to keep the state around.
 9952            if !tabstop.is_end_tabstop {
 9953                let choices = tabstops
 9954                    .iter()
 9955                    .map(|tabstop| tabstop.choices.clone())
 9956                    .collect();
 9957
 9958                let ranges = tabstops
 9959                    .into_iter()
 9960                    .map(|tabstop| tabstop.ranges)
 9961                    .collect::<Vec<_>>();
 9962
 9963                self.snippet_stack.push(SnippetState {
 9964                    active_index: 0,
 9965                    ranges,
 9966                    choices,
 9967                });
 9968            }
 9969
 9970            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9971            if self.autoclose_regions.is_empty() {
 9972                let snapshot = self.buffer.read(cx).snapshot(cx);
 9973                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9974                    let selection_head = selection.head();
 9975                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9976                        continue;
 9977                    };
 9978
 9979                    let mut bracket_pair = None;
 9980                    let max_lookup_length = scope
 9981                        .brackets()
 9982                        .map(|(pair, _)| {
 9983                            pair.start
 9984                                .as_str()
 9985                                .chars()
 9986                                .count()
 9987                                .max(pair.end.as_str().chars().count())
 9988                        })
 9989                        .max();
 9990                    if let Some(max_lookup_length) = max_lookup_length {
 9991                        let next_text = snapshot
 9992                            .chars_at(selection_head)
 9993                            .take(max_lookup_length)
 9994                            .collect::<String>();
 9995                        let prev_text = snapshot
 9996                            .reversed_chars_at(selection_head)
 9997                            .take(max_lookup_length)
 9998                            .collect::<String>();
 9999
10000                        for (pair, enabled) in scope.brackets() {
10001                            if enabled
10002                                && pair.close
10003                                && prev_text.starts_with(pair.start.as_str())
10004                                && next_text.starts_with(pair.end.as_str())
10005                            {
10006                                bracket_pair = Some(pair.clone());
10007                                break;
10008                            }
10009                        }
10010                    }
10011
10012                    if let Some(pair) = bracket_pair {
10013                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10014                        let autoclose_enabled =
10015                            self.use_autoclose && snapshot_settings.use_autoclose;
10016                        if autoclose_enabled {
10017                            let start = snapshot.anchor_after(selection_head);
10018                            let end = snapshot.anchor_after(selection_head);
10019                            self.autoclose_regions.push(AutocloseRegion {
10020                                selection_id: selection.id,
10021                                range: start..end,
10022                                pair,
10023                            });
10024                        }
10025                    }
10026                }
10027            }
10028        }
10029        Ok(())
10030    }
10031
10032    pub fn move_to_next_snippet_tabstop(
10033        &mut self,
10034        window: &mut Window,
10035        cx: &mut Context<Self>,
10036    ) -> bool {
10037        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10038    }
10039
10040    pub fn move_to_prev_snippet_tabstop(
10041        &mut self,
10042        window: &mut Window,
10043        cx: &mut Context<Self>,
10044    ) -> bool {
10045        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10046    }
10047
10048    pub fn move_to_snippet_tabstop(
10049        &mut self,
10050        bias: Bias,
10051        window: &mut Window,
10052        cx: &mut Context<Self>,
10053    ) -> bool {
10054        if let Some(mut snippet) = self.snippet_stack.pop() {
10055            match bias {
10056                Bias::Left => {
10057                    if snippet.active_index > 0 {
10058                        snippet.active_index -= 1;
10059                    } else {
10060                        self.snippet_stack.push(snippet);
10061                        return false;
10062                    }
10063                }
10064                Bias::Right => {
10065                    if snippet.active_index + 1 < snippet.ranges.len() {
10066                        snippet.active_index += 1;
10067                    } else {
10068                        self.snippet_stack.push(snippet);
10069                        return false;
10070                    }
10071                }
10072            }
10073            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10074                self.change_selections(Default::default(), window, cx, |s| {
10075                    // Reverse order so that the first range is the newest created selection.
10076                    // Completions will use it and autoscroll will prioritize it.
10077                    s.select_ranges(current_ranges.iter().rev().cloned())
10078                });
10079
10080                if let Some(choices) = &snippet.choices[snippet.active_index]
10081                    && let Some(selection) = current_ranges.first()
10082                {
10083                    self.show_snippet_choices(choices, selection.clone(), cx);
10084                }
10085
10086                // If snippet state is not at the last tabstop, push it back on the stack
10087                if snippet.active_index + 1 < snippet.ranges.len() {
10088                    self.snippet_stack.push(snippet);
10089                }
10090                return true;
10091            }
10092        }
10093
10094        false
10095    }
10096
10097    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10098        self.transact(window, cx, |this, window, cx| {
10099            this.select_all(&SelectAll, window, cx);
10100            this.insert("", window, cx);
10101        });
10102    }
10103
10104    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10105        if self.read_only(cx) {
10106            return;
10107        }
10108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10109        self.transact(window, cx, |this, window, cx| {
10110            this.select_autoclose_pair(window, cx);
10111
10112            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10113
10114            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10115            if !this.linked_edit_ranges.is_empty() {
10116                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10117                let snapshot = this.buffer.read(cx).snapshot(cx);
10118
10119                for selection in selections.iter() {
10120                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10121                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10122                    if selection_start.buffer_id != selection_end.buffer_id {
10123                        continue;
10124                    }
10125                    if let Some(ranges) =
10126                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10127                    {
10128                        for (buffer, entries) in ranges {
10129                            linked_ranges.entry(buffer).or_default().extend(entries);
10130                        }
10131                    }
10132                }
10133            }
10134
10135            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10136            for selection in &mut selections {
10137                if selection.is_empty() {
10138                    let old_head = selection.head();
10139                    let mut new_head =
10140                        movement::left(&display_map, old_head.to_display_point(&display_map))
10141                            .to_point(&display_map);
10142                    if let Some((buffer, line_buffer_range)) = display_map
10143                        .buffer_snapshot()
10144                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10145                    {
10146                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10147                        let indent_len = match indent_size.kind {
10148                            IndentKind::Space => {
10149                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10150                            }
10151                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10152                        };
10153                        if old_head.column <= indent_size.len && old_head.column > 0 {
10154                            let indent_len = indent_len.get();
10155                            new_head = cmp::min(
10156                                new_head,
10157                                MultiBufferPoint::new(
10158                                    old_head.row,
10159                                    ((old_head.column - 1) / indent_len) * indent_len,
10160                                ),
10161                            );
10162                        }
10163                    }
10164
10165                    selection.set_head(new_head, SelectionGoal::None);
10166                }
10167            }
10168
10169            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10170            this.insert("", window, cx);
10171            let empty_str: Arc<str> = Arc::from("");
10172            for (buffer, edits) in linked_ranges {
10173                let snapshot = buffer.read(cx).snapshot();
10174                use text::ToPoint as TP;
10175
10176                let edits = edits
10177                    .into_iter()
10178                    .map(|range| {
10179                        let end_point = TP::to_point(&range.end, &snapshot);
10180                        let mut start_point = TP::to_point(&range.start, &snapshot);
10181
10182                        if end_point == start_point {
10183                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10184                                .saturating_sub(1);
10185                            start_point =
10186                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10187                        };
10188
10189                        (start_point..end_point, empty_str.clone())
10190                    })
10191                    .sorted_by_key(|(range, _)| range.start)
10192                    .collect::<Vec<_>>();
10193                buffer.update(cx, |this, cx| {
10194                    this.edit(edits, None, cx);
10195                })
10196            }
10197            this.refresh_edit_prediction(true, false, window, cx);
10198            refresh_linked_ranges(this, window, cx);
10199        });
10200    }
10201
10202    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10203        if self.read_only(cx) {
10204            return;
10205        }
10206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10207        self.transact(window, cx, |this, window, cx| {
10208            this.change_selections(Default::default(), window, cx, |s| {
10209                s.move_with(|map, selection| {
10210                    if selection.is_empty() {
10211                        let cursor = movement::right(map, selection.head());
10212                        selection.end = cursor;
10213                        selection.reversed = true;
10214                        selection.goal = SelectionGoal::None;
10215                    }
10216                })
10217            });
10218            this.insert("", window, cx);
10219            this.refresh_edit_prediction(true, false, window, cx);
10220        });
10221    }
10222
10223    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10224        if self.mode.is_single_line() {
10225            cx.propagate();
10226            return;
10227        }
10228
10229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10230        if self.move_to_prev_snippet_tabstop(window, cx) {
10231            return;
10232        }
10233        self.outdent(&Outdent, window, cx);
10234    }
10235
10236    pub fn next_snippet_tabstop(
10237        &mut self,
10238        _: &NextSnippetTabstop,
10239        window: &mut Window,
10240        cx: &mut Context<Self>,
10241    ) {
10242        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10243            cx.propagate();
10244            return;
10245        }
10246
10247        if self.move_to_next_snippet_tabstop(window, cx) {
10248            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10249            return;
10250        }
10251        cx.propagate();
10252    }
10253
10254    pub fn previous_snippet_tabstop(
10255        &mut self,
10256        _: &PreviousSnippetTabstop,
10257        window: &mut Window,
10258        cx: &mut Context<Self>,
10259    ) {
10260        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10261            cx.propagate();
10262            return;
10263        }
10264
10265        if self.move_to_prev_snippet_tabstop(window, cx) {
10266            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10267            return;
10268        }
10269        cx.propagate();
10270    }
10271
10272    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10273        if self.mode.is_single_line() {
10274            cx.propagate();
10275            return;
10276        }
10277
10278        if self.move_to_next_snippet_tabstop(window, cx) {
10279            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10280            return;
10281        }
10282        if self.read_only(cx) {
10283            return;
10284        }
10285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10286        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10287        let buffer = self.buffer.read(cx);
10288        let snapshot = buffer.snapshot(cx);
10289        let rows_iter = selections.iter().map(|s| s.head().row);
10290        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10291
10292        let has_some_cursor_in_whitespace = selections
10293            .iter()
10294            .filter(|selection| selection.is_empty())
10295            .any(|selection| {
10296                let cursor = selection.head();
10297                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10298                cursor.column < current_indent.len
10299            });
10300
10301        let mut edits = Vec::new();
10302        let mut prev_edited_row = 0;
10303        let mut row_delta = 0;
10304        for selection in &mut selections {
10305            if selection.start.row != prev_edited_row {
10306                row_delta = 0;
10307            }
10308            prev_edited_row = selection.end.row;
10309
10310            // If the selection is non-empty, then increase the indentation of the selected lines.
10311            if !selection.is_empty() {
10312                row_delta =
10313                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10314                continue;
10315            }
10316
10317            let cursor = selection.head();
10318            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10319            if let Some(suggested_indent) =
10320                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10321            {
10322                // Don't do anything if already at suggested indent
10323                // and there is any other cursor which is not
10324                if has_some_cursor_in_whitespace
10325                    && cursor.column == current_indent.len
10326                    && current_indent.len == suggested_indent.len
10327                {
10328                    continue;
10329                }
10330
10331                // Adjust line and move cursor to suggested indent
10332                // if cursor is not at suggested indent
10333                if cursor.column < suggested_indent.len
10334                    && cursor.column <= current_indent.len
10335                    && current_indent.len <= suggested_indent.len
10336                {
10337                    selection.start = Point::new(cursor.row, suggested_indent.len);
10338                    selection.end = selection.start;
10339                    if row_delta == 0 {
10340                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10341                            cursor.row,
10342                            current_indent,
10343                            suggested_indent,
10344                        ));
10345                        row_delta = suggested_indent.len - current_indent.len;
10346                    }
10347                    continue;
10348                }
10349
10350                // If current indent is more than suggested indent
10351                // only move cursor to current indent and skip indent
10352                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10353                    selection.start = Point::new(cursor.row, current_indent.len);
10354                    selection.end = selection.start;
10355                    continue;
10356                }
10357            }
10358
10359            // Otherwise, insert a hard or soft tab.
10360            let settings = buffer.language_settings_at(cursor, cx);
10361            let tab_size = if settings.hard_tabs {
10362                IndentSize::tab()
10363            } else {
10364                let tab_size = settings.tab_size.get();
10365                let indent_remainder = snapshot
10366                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10367                    .flat_map(str::chars)
10368                    .fold(row_delta % tab_size, |counter: u32, c| {
10369                        if c == '\t' {
10370                            0
10371                        } else {
10372                            (counter + 1) % tab_size
10373                        }
10374                    });
10375
10376                let chars_to_next_tab_stop = tab_size - indent_remainder;
10377                IndentSize::spaces(chars_to_next_tab_stop)
10378            };
10379            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10380            selection.end = selection.start;
10381            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10382            row_delta += tab_size.len;
10383        }
10384
10385        self.transact(window, cx, |this, window, cx| {
10386            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10387            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10388            this.refresh_edit_prediction(true, false, window, cx);
10389        });
10390    }
10391
10392    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10393        if self.read_only(cx) {
10394            return;
10395        }
10396        if self.mode.is_single_line() {
10397            cx.propagate();
10398            return;
10399        }
10400
10401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10402        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10403        let mut prev_edited_row = 0;
10404        let mut row_delta = 0;
10405        let mut edits = Vec::new();
10406        let buffer = self.buffer.read(cx);
10407        let snapshot = buffer.snapshot(cx);
10408        for selection in &mut selections {
10409            if selection.start.row != prev_edited_row {
10410                row_delta = 0;
10411            }
10412            prev_edited_row = selection.end.row;
10413
10414            row_delta =
10415                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10416        }
10417
10418        self.transact(window, cx, |this, window, cx| {
10419            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10420            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10421        });
10422    }
10423
10424    fn indent_selection(
10425        buffer: &MultiBuffer,
10426        snapshot: &MultiBufferSnapshot,
10427        selection: &mut Selection<Point>,
10428        edits: &mut Vec<(Range<Point>, String)>,
10429        delta_for_start_row: u32,
10430        cx: &App,
10431    ) -> u32 {
10432        let settings = buffer.language_settings_at(selection.start, cx);
10433        let tab_size = settings.tab_size.get();
10434        let indent_kind = if settings.hard_tabs {
10435            IndentKind::Tab
10436        } else {
10437            IndentKind::Space
10438        };
10439        let mut start_row = selection.start.row;
10440        let mut end_row = selection.end.row + 1;
10441
10442        // If a selection ends at the beginning of a line, don't indent
10443        // that last line.
10444        if selection.end.column == 0 && selection.end.row > selection.start.row {
10445            end_row -= 1;
10446        }
10447
10448        // Avoid re-indenting a row that has already been indented by a
10449        // previous selection, but still update this selection's column
10450        // to reflect that indentation.
10451        if delta_for_start_row > 0 {
10452            start_row += 1;
10453            selection.start.column += delta_for_start_row;
10454            if selection.end.row == selection.start.row {
10455                selection.end.column += delta_for_start_row;
10456            }
10457        }
10458
10459        let mut delta_for_end_row = 0;
10460        let has_multiple_rows = start_row + 1 != end_row;
10461        for row in start_row..end_row {
10462            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10463            let indent_delta = match (current_indent.kind, indent_kind) {
10464                (IndentKind::Space, IndentKind::Space) => {
10465                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10466                    IndentSize::spaces(columns_to_next_tab_stop)
10467                }
10468                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10469                (_, IndentKind::Tab) => IndentSize::tab(),
10470            };
10471
10472            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10473                0
10474            } else {
10475                selection.start.column
10476            };
10477            let row_start = Point::new(row, start);
10478            edits.push((
10479                row_start..row_start,
10480                indent_delta.chars().collect::<String>(),
10481            ));
10482
10483            // Update this selection's endpoints to reflect the indentation.
10484            if row == selection.start.row {
10485                selection.start.column += indent_delta.len;
10486            }
10487            if row == selection.end.row {
10488                selection.end.column += indent_delta.len;
10489                delta_for_end_row = indent_delta.len;
10490            }
10491        }
10492
10493        if selection.start.row == selection.end.row {
10494            delta_for_start_row + delta_for_end_row
10495        } else {
10496            delta_for_end_row
10497        }
10498    }
10499
10500    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10501        if self.read_only(cx) {
10502            return;
10503        }
10504        if self.mode.is_single_line() {
10505            cx.propagate();
10506            return;
10507        }
10508
10509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10511        let selections = self.selections.all::<Point>(&display_map);
10512        let mut deletion_ranges = Vec::new();
10513        let mut last_outdent = None;
10514        {
10515            let buffer = self.buffer.read(cx);
10516            let snapshot = buffer.snapshot(cx);
10517            for selection in &selections {
10518                let settings = buffer.language_settings_at(selection.start, cx);
10519                let tab_size = settings.tab_size.get();
10520                let mut rows = selection.spanned_rows(false, &display_map);
10521
10522                // Avoid re-outdenting a row that has already been outdented by a
10523                // previous selection.
10524                if let Some(last_row) = last_outdent
10525                    && last_row == rows.start
10526                {
10527                    rows.start = rows.start.next_row();
10528                }
10529                let has_multiple_rows = rows.len() > 1;
10530                for row in rows.iter_rows() {
10531                    let indent_size = snapshot.indent_size_for_line(row);
10532                    if indent_size.len > 0 {
10533                        let deletion_len = match indent_size.kind {
10534                            IndentKind::Space => {
10535                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10536                                if columns_to_prev_tab_stop == 0 {
10537                                    tab_size
10538                                } else {
10539                                    columns_to_prev_tab_stop
10540                                }
10541                            }
10542                            IndentKind::Tab => 1,
10543                        };
10544                        let start = if has_multiple_rows
10545                            || deletion_len > selection.start.column
10546                            || indent_size.len < selection.start.column
10547                        {
10548                            0
10549                        } else {
10550                            selection.start.column - deletion_len
10551                        };
10552                        deletion_ranges.push(
10553                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10554                        );
10555                        last_outdent = Some(row);
10556                    }
10557                }
10558            }
10559        }
10560
10561        self.transact(window, cx, |this, window, cx| {
10562            this.buffer.update(cx, |buffer, cx| {
10563                let empty_str: Arc<str> = Arc::default();
10564                buffer.edit(
10565                    deletion_ranges
10566                        .into_iter()
10567                        .map(|range| (range, empty_str.clone())),
10568                    None,
10569                    cx,
10570                );
10571            });
10572            let selections = this
10573                .selections
10574                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10575            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10576        });
10577    }
10578
10579    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10580        if self.read_only(cx) {
10581            return;
10582        }
10583        if self.mode.is_single_line() {
10584            cx.propagate();
10585            return;
10586        }
10587
10588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10589        let selections = self
10590            .selections
10591            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10592            .into_iter()
10593            .map(|s| s.range());
10594
10595        self.transact(window, cx, |this, window, cx| {
10596            this.buffer.update(cx, |buffer, cx| {
10597                buffer.autoindent_ranges(selections, cx);
10598            });
10599            let selections = this
10600                .selections
10601                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10602            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10603        });
10604    }
10605
10606    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10609        let selections = self.selections.all::<Point>(&display_map);
10610
10611        let mut new_cursors = Vec::new();
10612        let mut edit_ranges = Vec::new();
10613        let mut selections = selections.iter().peekable();
10614        while let Some(selection) = selections.next() {
10615            let mut rows = selection.spanned_rows(false, &display_map);
10616
10617            // Accumulate contiguous regions of rows that we want to delete.
10618            while let Some(next_selection) = selections.peek() {
10619                let next_rows = next_selection.spanned_rows(false, &display_map);
10620                if next_rows.start <= rows.end {
10621                    rows.end = next_rows.end;
10622                    selections.next().unwrap();
10623                } else {
10624                    break;
10625                }
10626            }
10627
10628            let buffer = display_map.buffer_snapshot();
10629            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10630            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10631                // If there's a line after the range, delete the \n from the end of the row range
10632                (
10633                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10634                    rows.end,
10635                )
10636            } else {
10637                // If there isn't a line after the range, delete the \n from the line before the
10638                // start of the row range
10639                edit_start = edit_start.saturating_sub_usize(1);
10640                (buffer.len(), rows.start.previous_row())
10641            };
10642
10643            let text_layout_details = self.text_layout_details(window);
10644            let x = display_map.x_for_display_point(
10645                selection.head().to_display_point(&display_map),
10646                &text_layout_details,
10647            );
10648            let row = Point::new(target_row.0, 0)
10649                .to_display_point(&display_map)
10650                .row();
10651            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10652
10653            new_cursors.push((
10654                selection.id,
10655                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10656                SelectionGoal::None,
10657            ));
10658            edit_ranges.push(edit_start..edit_end);
10659        }
10660
10661        self.transact(window, cx, |this, window, cx| {
10662            let buffer = this.buffer.update(cx, |buffer, cx| {
10663                let empty_str: Arc<str> = Arc::default();
10664                buffer.edit(
10665                    edit_ranges
10666                        .into_iter()
10667                        .map(|range| (range, empty_str.clone())),
10668                    None,
10669                    cx,
10670                );
10671                buffer.snapshot(cx)
10672            });
10673            let new_selections = new_cursors
10674                .into_iter()
10675                .map(|(id, cursor, goal)| {
10676                    let cursor = cursor.to_point(&buffer);
10677                    Selection {
10678                        id,
10679                        start: cursor,
10680                        end: cursor,
10681                        reversed: false,
10682                        goal,
10683                    }
10684                })
10685                .collect();
10686
10687            this.change_selections(Default::default(), window, cx, |s| {
10688                s.select(new_selections);
10689            });
10690        });
10691    }
10692
10693    pub fn join_lines_impl(
10694        &mut self,
10695        insert_whitespace: bool,
10696        window: &mut Window,
10697        cx: &mut Context<Self>,
10698    ) {
10699        if self.read_only(cx) {
10700            return;
10701        }
10702        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10703        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10704            let start = MultiBufferRow(selection.start.row);
10705            // Treat single line selections as if they include the next line. Otherwise this action
10706            // would do nothing for single line selections individual cursors.
10707            let end = if selection.start.row == selection.end.row {
10708                MultiBufferRow(selection.start.row + 1)
10709            } else {
10710                MultiBufferRow(selection.end.row)
10711            };
10712
10713            if let Some(last_row_range) = row_ranges.last_mut()
10714                && start <= last_row_range.end
10715            {
10716                last_row_range.end = end;
10717                continue;
10718            }
10719            row_ranges.push(start..end);
10720        }
10721
10722        let snapshot = self.buffer.read(cx).snapshot(cx);
10723        let mut cursor_positions = Vec::new();
10724        for row_range in &row_ranges {
10725            let anchor = snapshot.anchor_before(Point::new(
10726                row_range.end.previous_row().0,
10727                snapshot.line_len(row_range.end.previous_row()),
10728            ));
10729            cursor_positions.push(anchor..anchor);
10730        }
10731
10732        self.transact(window, cx, |this, window, cx| {
10733            for row_range in row_ranges.into_iter().rev() {
10734                for row in row_range.iter_rows().rev() {
10735                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10736                    let next_line_row = row.next_row();
10737                    let indent = snapshot.indent_size_for_line(next_line_row);
10738                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10739
10740                    let replace =
10741                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10742                            " "
10743                        } else {
10744                            ""
10745                        };
10746
10747                    this.buffer.update(cx, |buffer, cx| {
10748                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10749                    });
10750                }
10751            }
10752
10753            this.change_selections(Default::default(), window, cx, |s| {
10754                s.select_anchor_ranges(cursor_positions)
10755            });
10756        });
10757    }
10758
10759    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10761        self.join_lines_impl(true, window, cx);
10762    }
10763
10764    pub fn sort_lines_case_sensitive(
10765        &mut self,
10766        _: &SortLinesCaseSensitive,
10767        window: &mut Window,
10768        cx: &mut Context<Self>,
10769    ) {
10770        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10771    }
10772
10773    pub fn sort_lines_by_length(
10774        &mut self,
10775        _: &SortLinesByLength,
10776        window: &mut Window,
10777        cx: &mut Context<Self>,
10778    ) {
10779        self.manipulate_immutable_lines(window, cx, |lines| {
10780            lines.sort_by_key(|&line| line.chars().count())
10781        })
10782    }
10783
10784    pub fn sort_lines_case_insensitive(
10785        &mut self,
10786        _: &SortLinesCaseInsensitive,
10787        window: &mut Window,
10788        cx: &mut Context<Self>,
10789    ) {
10790        self.manipulate_immutable_lines(window, cx, |lines| {
10791            lines.sort_by_key(|line| line.to_lowercase())
10792        })
10793    }
10794
10795    pub fn unique_lines_case_insensitive(
10796        &mut self,
10797        _: &UniqueLinesCaseInsensitive,
10798        window: &mut Window,
10799        cx: &mut Context<Self>,
10800    ) {
10801        self.manipulate_immutable_lines(window, cx, |lines| {
10802            let mut seen = HashSet::default();
10803            lines.retain(|line| seen.insert(line.to_lowercase()));
10804        })
10805    }
10806
10807    pub fn unique_lines_case_sensitive(
10808        &mut self,
10809        _: &UniqueLinesCaseSensitive,
10810        window: &mut Window,
10811        cx: &mut Context<Self>,
10812    ) {
10813        self.manipulate_immutable_lines(window, cx, |lines| {
10814            let mut seen = HashSet::default();
10815            lines.retain(|line| seen.insert(*line));
10816        })
10817    }
10818
10819    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10820        let snapshot = self.buffer.read(cx).snapshot(cx);
10821        for selection in self.selections.disjoint_anchors_arc().iter() {
10822            if snapshot
10823                .language_at(selection.start)
10824                .and_then(|lang| lang.config().wrap_characters.as_ref())
10825                .is_some()
10826            {
10827                return true;
10828            }
10829        }
10830        false
10831    }
10832
10833    fn wrap_selections_in_tag(
10834        &mut self,
10835        _: &WrapSelectionsInTag,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10840
10841        let snapshot = self.buffer.read(cx).snapshot(cx);
10842
10843        let mut edits = Vec::new();
10844        let mut boundaries = Vec::new();
10845
10846        for selection in self
10847            .selections
10848            .all_adjusted(&self.display_snapshot(cx))
10849            .iter()
10850        {
10851            let Some(wrap_config) = snapshot
10852                .language_at(selection.start)
10853                .and_then(|lang| lang.config().wrap_characters.clone())
10854            else {
10855                continue;
10856            };
10857
10858            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10859            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10860
10861            let start_before = snapshot.anchor_before(selection.start);
10862            let end_after = snapshot.anchor_after(selection.end);
10863
10864            edits.push((start_before..start_before, open_tag));
10865            edits.push((end_after..end_after, close_tag));
10866
10867            boundaries.push((
10868                start_before,
10869                end_after,
10870                wrap_config.start_prefix.len(),
10871                wrap_config.end_suffix.len(),
10872            ));
10873        }
10874
10875        if edits.is_empty() {
10876            return;
10877        }
10878
10879        self.transact(window, cx, |this, window, cx| {
10880            let buffer = this.buffer.update(cx, |buffer, cx| {
10881                buffer.edit(edits, None, cx);
10882                buffer.snapshot(cx)
10883            });
10884
10885            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10886            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10887                boundaries.into_iter()
10888            {
10889                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10890                let close_offset = end_after
10891                    .to_offset(&buffer)
10892                    .saturating_sub_usize(end_suffix_len);
10893                new_selections.push(open_offset..open_offset);
10894                new_selections.push(close_offset..close_offset);
10895            }
10896
10897            this.change_selections(Default::default(), window, cx, |s| {
10898                s.select_ranges(new_selections);
10899            });
10900
10901            this.request_autoscroll(Autoscroll::fit(), cx);
10902        });
10903    }
10904
10905    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10906        let Some(project) = self.project.clone() else {
10907            return;
10908        };
10909        self.reload(project, window, cx)
10910            .detach_and_notify_err(window, cx);
10911    }
10912
10913    pub fn restore_file(
10914        &mut self,
10915        _: &::git::RestoreFile,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10920        let mut buffer_ids = HashSet::default();
10921        let snapshot = self.buffer().read(cx).snapshot(cx);
10922        for selection in self
10923            .selections
10924            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10925        {
10926            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10927        }
10928
10929        let buffer = self.buffer().read(cx);
10930        let ranges = buffer_ids
10931            .into_iter()
10932            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10933            .collect::<Vec<_>>();
10934
10935        self.restore_hunks_in_ranges(ranges, window, cx);
10936    }
10937
10938    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10940        let selections = self
10941            .selections
10942            .all(&self.display_snapshot(cx))
10943            .into_iter()
10944            .map(|s| s.range())
10945            .collect();
10946        self.restore_hunks_in_ranges(selections, window, cx);
10947    }
10948
10949    pub fn restore_hunks_in_ranges(
10950        &mut self,
10951        ranges: Vec<Range<Point>>,
10952        window: &mut Window,
10953        cx: &mut Context<Editor>,
10954    ) {
10955        let mut revert_changes = HashMap::default();
10956        let chunk_by = self
10957            .snapshot(window, cx)
10958            .hunks_for_ranges(ranges)
10959            .into_iter()
10960            .chunk_by(|hunk| hunk.buffer_id);
10961        for (buffer_id, hunks) in &chunk_by {
10962            let hunks = hunks.collect::<Vec<_>>();
10963            for hunk in &hunks {
10964                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10965            }
10966            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10967        }
10968        drop(chunk_by);
10969        if !revert_changes.is_empty() {
10970            self.transact(window, cx, |editor, window, cx| {
10971                editor.restore(revert_changes, window, cx);
10972            });
10973        }
10974    }
10975
10976    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10977        if let Some(status) = self
10978            .addons
10979            .iter()
10980            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10981        {
10982            return Some(status);
10983        }
10984        self.project
10985            .as_ref()?
10986            .read(cx)
10987            .status_for_buffer_id(buffer_id, cx)
10988    }
10989
10990    pub fn open_active_item_in_terminal(
10991        &mut self,
10992        _: &OpenInTerminal,
10993        window: &mut Window,
10994        cx: &mut Context<Self>,
10995    ) {
10996        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10997            let project_path = buffer.read(cx).project_path(cx)?;
10998            let project = self.project()?.read(cx);
10999            let entry = project.entry_for_path(&project_path, cx)?;
11000            let parent = match &entry.canonical_path {
11001                Some(canonical_path) => canonical_path.to_path_buf(),
11002                None => project.absolute_path(&project_path, cx)?,
11003            }
11004            .parent()?
11005            .to_path_buf();
11006            Some(parent)
11007        }) {
11008            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11009        }
11010    }
11011
11012    fn set_breakpoint_context_menu(
11013        &mut self,
11014        display_row: DisplayRow,
11015        position: Option<Anchor>,
11016        clicked_point: gpui::Point<Pixels>,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        let source = self
11021            .buffer
11022            .read(cx)
11023            .snapshot(cx)
11024            .anchor_before(Point::new(display_row.0, 0u32));
11025
11026        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11027
11028        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11029            self,
11030            source,
11031            clicked_point,
11032            context_menu,
11033            window,
11034            cx,
11035        );
11036    }
11037
11038    fn add_edit_breakpoint_block(
11039        &mut self,
11040        anchor: Anchor,
11041        breakpoint: &Breakpoint,
11042        edit_action: BreakpointPromptEditAction,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        let weak_editor = cx.weak_entity();
11047        let bp_prompt = cx.new(|cx| {
11048            BreakpointPromptEditor::new(
11049                weak_editor,
11050                anchor,
11051                breakpoint.clone(),
11052                edit_action,
11053                window,
11054                cx,
11055            )
11056        });
11057
11058        let height = bp_prompt.update(cx, |this, cx| {
11059            this.prompt
11060                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11061        });
11062        let cloned_prompt = bp_prompt.clone();
11063        let blocks = vec![BlockProperties {
11064            style: BlockStyle::Sticky,
11065            placement: BlockPlacement::Above(anchor),
11066            height: Some(height),
11067            render: Arc::new(move |cx| {
11068                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11069                cloned_prompt.clone().into_any_element()
11070            }),
11071            priority: 0,
11072        }];
11073
11074        let focus_handle = bp_prompt.focus_handle(cx);
11075        window.focus(&focus_handle);
11076
11077        let block_ids = self.insert_blocks(blocks, None, cx);
11078        bp_prompt.update(cx, |prompt, _| {
11079            prompt.add_block_ids(block_ids);
11080        });
11081    }
11082
11083    pub(crate) fn breakpoint_at_row(
11084        &self,
11085        row: u32,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) -> Option<(Anchor, Breakpoint)> {
11089        let snapshot = self.snapshot(window, cx);
11090        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11091
11092        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11093    }
11094
11095    pub(crate) fn breakpoint_at_anchor(
11096        &self,
11097        breakpoint_position: Anchor,
11098        snapshot: &EditorSnapshot,
11099        cx: &mut Context<Self>,
11100    ) -> Option<(Anchor, Breakpoint)> {
11101        let buffer = self
11102            .buffer
11103            .read(cx)
11104            .buffer_for_anchor(breakpoint_position, cx)?;
11105
11106        let enclosing_excerpt = breakpoint_position.excerpt_id;
11107        let buffer_snapshot = buffer.read(cx).snapshot();
11108
11109        let row = buffer_snapshot
11110            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11111            .row;
11112
11113        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11114        let anchor_end = snapshot
11115            .buffer_snapshot()
11116            .anchor_after(Point::new(row, line_len));
11117
11118        self.breakpoint_store
11119            .as_ref()?
11120            .read_with(cx, |breakpoint_store, cx| {
11121                breakpoint_store
11122                    .breakpoints(
11123                        &buffer,
11124                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11125                        &buffer_snapshot,
11126                        cx,
11127                    )
11128                    .next()
11129                    .and_then(|(bp, _)| {
11130                        let breakpoint_row = buffer_snapshot
11131                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11132                            .row;
11133
11134                        if breakpoint_row == row {
11135                            snapshot
11136                                .buffer_snapshot()
11137                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11138                                .map(|position| (position, bp.bp.clone()))
11139                        } else {
11140                            None
11141                        }
11142                    })
11143            })
11144    }
11145
11146    pub fn edit_log_breakpoint(
11147        &mut self,
11148        _: &EditLogBreakpoint,
11149        window: &mut Window,
11150        cx: &mut Context<Self>,
11151    ) {
11152        if self.breakpoint_store.is_none() {
11153            return;
11154        }
11155
11156        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11157            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11158                message: None,
11159                state: BreakpointState::Enabled,
11160                condition: None,
11161                hit_condition: None,
11162            });
11163
11164            self.add_edit_breakpoint_block(
11165                anchor,
11166                &breakpoint,
11167                BreakpointPromptEditAction::Log,
11168                window,
11169                cx,
11170            );
11171        }
11172    }
11173
11174    fn breakpoints_at_cursors(
11175        &self,
11176        window: &mut Window,
11177        cx: &mut Context<Self>,
11178    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11179        let snapshot = self.snapshot(window, cx);
11180        let cursors = self
11181            .selections
11182            .disjoint_anchors_arc()
11183            .iter()
11184            .map(|selection| {
11185                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11186
11187                let breakpoint_position = self
11188                    .breakpoint_at_row(cursor_position.row, window, cx)
11189                    .map(|bp| bp.0)
11190                    .unwrap_or_else(|| {
11191                        snapshot
11192                            .display_snapshot
11193                            .buffer_snapshot()
11194                            .anchor_after(Point::new(cursor_position.row, 0))
11195                    });
11196
11197                let breakpoint = self
11198                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11199                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11200
11201                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11202            })
11203            // 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.
11204            .collect::<HashMap<Anchor, _>>();
11205
11206        cursors.into_iter().collect()
11207    }
11208
11209    pub fn enable_breakpoint(
11210        &mut self,
11211        _: &crate::actions::EnableBreakpoint,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        if self.breakpoint_store.is_none() {
11216            return;
11217        }
11218
11219        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11220            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11221                continue;
11222            };
11223            self.edit_breakpoint_at_anchor(
11224                anchor,
11225                breakpoint,
11226                BreakpointEditAction::InvertState,
11227                cx,
11228            );
11229        }
11230    }
11231
11232    pub fn disable_breakpoint(
11233        &mut self,
11234        _: &crate::actions::DisableBreakpoint,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        if self.breakpoint_store.is_none() {
11239            return;
11240        }
11241
11242        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11243            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11244                continue;
11245            };
11246            self.edit_breakpoint_at_anchor(
11247                anchor,
11248                breakpoint,
11249                BreakpointEditAction::InvertState,
11250                cx,
11251            );
11252        }
11253    }
11254
11255    pub fn toggle_breakpoint(
11256        &mut self,
11257        _: &crate::actions::ToggleBreakpoint,
11258        window: &mut Window,
11259        cx: &mut Context<Self>,
11260    ) {
11261        if self.breakpoint_store.is_none() {
11262            return;
11263        }
11264
11265        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11266            if let Some(breakpoint) = breakpoint {
11267                self.edit_breakpoint_at_anchor(
11268                    anchor,
11269                    breakpoint,
11270                    BreakpointEditAction::Toggle,
11271                    cx,
11272                );
11273            } else {
11274                self.edit_breakpoint_at_anchor(
11275                    anchor,
11276                    Breakpoint::new_standard(),
11277                    BreakpointEditAction::Toggle,
11278                    cx,
11279                );
11280            }
11281        }
11282    }
11283
11284    pub fn edit_breakpoint_at_anchor(
11285        &mut self,
11286        breakpoint_position: Anchor,
11287        breakpoint: Breakpoint,
11288        edit_action: BreakpointEditAction,
11289        cx: &mut Context<Self>,
11290    ) {
11291        let Some(breakpoint_store) = &self.breakpoint_store else {
11292            return;
11293        };
11294
11295        let Some(buffer) = self
11296            .buffer
11297            .read(cx)
11298            .buffer_for_anchor(breakpoint_position, cx)
11299        else {
11300            return;
11301        };
11302
11303        breakpoint_store.update(cx, |breakpoint_store, cx| {
11304            breakpoint_store.toggle_breakpoint(
11305                buffer,
11306                BreakpointWithPosition {
11307                    position: breakpoint_position.text_anchor,
11308                    bp: breakpoint,
11309                },
11310                edit_action,
11311                cx,
11312            );
11313        });
11314
11315        cx.notify();
11316    }
11317
11318    #[cfg(any(test, feature = "test-support"))]
11319    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11320        self.breakpoint_store.clone()
11321    }
11322
11323    pub fn prepare_restore_change(
11324        &self,
11325        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11326        hunk: &MultiBufferDiffHunk,
11327        cx: &mut App,
11328    ) -> Option<()> {
11329        if hunk.is_created_file() {
11330            return None;
11331        }
11332        let buffer = self.buffer.read(cx);
11333        let diff = buffer.diff_for(hunk.buffer_id)?;
11334        let buffer = buffer.buffer(hunk.buffer_id)?;
11335        let buffer = buffer.read(cx);
11336        let original_text = diff
11337            .read(cx)
11338            .base_text()
11339            .as_rope()
11340            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11341        let buffer_snapshot = buffer.snapshot();
11342        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11343        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11344            probe
11345                .0
11346                .start
11347                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11348                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11349        }) {
11350            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11351            Some(())
11352        } else {
11353            None
11354        }
11355    }
11356
11357    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11358        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11359    }
11360
11361    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11362        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11363    }
11364
11365    fn manipulate_lines<M>(
11366        &mut self,
11367        window: &mut Window,
11368        cx: &mut Context<Self>,
11369        mut manipulate: M,
11370    ) where
11371        M: FnMut(&str) -> LineManipulationResult,
11372    {
11373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11374
11375        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11376        let buffer = self.buffer.read(cx).snapshot(cx);
11377
11378        let mut edits = Vec::new();
11379
11380        let selections = self.selections.all::<Point>(&display_map);
11381        let mut selections = selections.iter().peekable();
11382        let mut contiguous_row_selections = Vec::new();
11383        let mut new_selections = Vec::new();
11384        let mut added_lines = 0;
11385        let mut removed_lines = 0;
11386
11387        while let Some(selection) = selections.next() {
11388            let (start_row, end_row) = consume_contiguous_rows(
11389                &mut contiguous_row_selections,
11390                selection,
11391                &display_map,
11392                &mut selections,
11393            );
11394
11395            let start_point = Point::new(start_row.0, 0);
11396            let end_point = Point::new(
11397                end_row.previous_row().0,
11398                buffer.line_len(end_row.previous_row()),
11399            );
11400            let text = buffer
11401                .text_for_range(start_point..end_point)
11402                .collect::<String>();
11403
11404            let LineManipulationResult {
11405                new_text,
11406                line_count_before,
11407                line_count_after,
11408            } = manipulate(&text);
11409
11410            edits.push((start_point..end_point, new_text));
11411
11412            // Selections must change based on added and removed line count
11413            let start_row =
11414                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11415            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11416            new_selections.push(Selection {
11417                id: selection.id,
11418                start: start_row,
11419                end: end_row,
11420                goal: SelectionGoal::None,
11421                reversed: selection.reversed,
11422            });
11423
11424            if line_count_after > line_count_before {
11425                added_lines += line_count_after - line_count_before;
11426            } else if line_count_before > line_count_after {
11427                removed_lines += line_count_before - line_count_after;
11428            }
11429        }
11430
11431        self.transact(window, cx, |this, window, cx| {
11432            let buffer = this.buffer.update(cx, |buffer, cx| {
11433                buffer.edit(edits, None, cx);
11434                buffer.snapshot(cx)
11435            });
11436
11437            // Recalculate offsets on newly edited buffer
11438            let new_selections = new_selections
11439                .iter()
11440                .map(|s| {
11441                    let start_point = Point::new(s.start.0, 0);
11442                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11443                    Selection {
11444                        id: s.id,
11445                        start: buffer.point_to_offset(start_point),
11446                        end: buffer.point_to_offset(end_point),
11447                        goal: s.goal,
11448                        reversed: s.reversed,
11449                    }
11450                })
11451                .collect();
11452
11453            this.change_selections(Default::default(), window, cx, |s| {
11454                s.select(new_selections);
11455            });
11456
11457            this.request_autoscroll(Autoscroll::fit(), cx);
11458        });
11459    }
11460
11461    fn manipulate_immutable_lines<Fn>(
11462        &mut self,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465        mut callback: Fn,
11466    ) where
11467        Fn: FnMut(&mut Vec<&str>),
11468    {
11469        self.manipulate_lines(window, cx, |text| {
11470            let mut lines: Vec<&str> = text.split('\n').collect();
11471            let line_count_before = lines.len();
11472
11473            callback(&mut lines);
11474
11475            LineManipulationResult {
11476                new_text: lines.join("\n"),
11477                line_count_before,
11478                line_count_after: lines.len(),
11479            }
11480        });
11481    }
11482
11483    fn manipulate_mutable_lines<Fn>(
11484        &mut self,
11485        window: &mut Window,
11486        cx: &mut Context<Self>,
11487        mut callback: Fn,
11488    ) where
11489        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11490    {
11491        self.manipulate_lines(window, cx, |text| {
11492            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11493            let line_count_before = lines.len();
11494
11495            callback(&mut lines);
11496
11497            LineManipulationResult {
11498                new_text: lines.join("\n"),
11499                line_count_before,
11500                line_count_after: lines.len(),
11501            }
11502        });
11503    }
11504
11505    pub fn convert_indentation_to_spaces(
11506        &mut self,
11507        _: &ConvertIndentationToSpaces,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        let settings = self.buffer.read(cx).language_settings(cx);
11512        let tab_size = settings.tab_size.get() as usize;
11513
11514        self.manipulate_mutable_lines(window, cx, |lines| {
11515            // Allocates a reasonably sized scratch buffer once for the whole loop
11516            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11517            // Avoids recomputing spaces that could be inserted many times
11518            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11519                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11520                .collect();
11521
11522            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11523                let mut chars = line.as_ref().chars();
11524                let mut col = 0;
11525                let mut changed = false;
11526
11527                for ch in chars.by_ref() {
11528                    match ch {
11529                        ' ' => {
11530                            reindented_line.push(' ');
11531                            col += 1;
11532                        }
11533                        '\t' => {
11534                            // \t are converted to spaces depending on the current column
11535                            let spaces_len = tab_size - (col % tab_size);
11536                            reindented_line.extend(&space_cache[spaces_len - 1]);
11537                            col += spaces_len;
11538                            changed = true;
11539                        }
11540                        _ => {
11541                            // If we dont append before break, the character is consumed
11542                            reindented_line.push(ch);
11543                            break;
11544                        }
11545                    }
11546                }
11547
11548                if !changed {
11549                    reindented_line.clear();
11550                    continue;
11551                }
11552                // Append the rest of the line and replace old reference with new one
11553                reindented_line.extend(chars);
11554                *line = Cow::Owned(reindented_line.clone());
11555                reindented_line.clear();
11556            }
11557        });
11558    }
11559
11560    pub fn convert_indentation_to_tabs(
11561        &mut self,
11562        _: &ConvertIndentationToTabs,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        let settings = self.buffer.read(cx).language_settings(cx);
11567        let tab_size = settings.tab_size.get() as usize;
11568
11569        self.manipulate_mutable_lines(window, cx, |lines| {
11570            // Allocates a reasonably sized buffer once for the whole loop
11571            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11572            // Avoids recomputing spaces that could be inserted many times
11573            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11574                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11575                .collect();
11576
11577            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11578                let mut chars = line.chars();
11579                let mut spaces_count = 0;
11580                let mut first_non_indent_char = None;
11581                let mut changed = false;
11582
11583                for ch in chars.by_ref() {
11584                    match ch {
11585                        ' ' => {
11586                            // Keep track of spaces. Append \t when we reach tab_size
11587                            spaces_count += 1;
11588                            changed = true;
11589                            if spaces_count == tab_size {
11590                                reindented_line.push('\t');
11591                                spaces_count = 0;
11592                            }
11593                        }
11594                        '\t' => {
11595                            reindented_line.push('\t');
11596                            spaces_count = 0;
11597                        }
11598                        _ => {
11599                            // Dont append it yet, we might have remaining spaces
11600                            first_non_indent_char = Some(ch);
11601                            break;
11602                        }
11603                    }
11604                }
11605
11606                if !changed {
11607                    reindented_line.clear();
11608                    continue;
11609                }
11610                // Remaining spaces that didn't make a full tab stop
11611                if spaces_count > 0 {
11612                    reindented_line.extend(&space_cache[spaces_count - 1]);
11613                }
11614                // If we consume an extra character that was not indentation, add it back
11615                if let Some(extra_char) = first_non_indent_char {
11616                    reindented_line.push(extra_char);
11617                }
11618                // Append the rest of the line and replace old reference with new one
11619                reindented_line.extend(chars);
11620                *line = Cow::Owned(reindented_line.clone());
11621                reindented_line.clear();
11622            }
11623        });
11624    }
11625
11626    pub fn convert_to_upper_case(
11627        &mut self,
11628        _: &ConvertToUpperCase,
11629        window: &mut Window,
11630        cx: &mut Context<Self>,
11631    ) {
11632        self.manipulate_text(window, cx, |text| text.to_uppercase())
11633    }
11634
11635    pub fn convert_to_lower_case(
11636        &mut self,
11637        _: &ConvertToLowerCase,
11638        window: &mut Window,
11639        cx: &mut Context<Self>,
11640    ) {
11641        self.manipulate_text(window, cx, |text| text.to_lowercase())
11642    }
11643
11644    pub fn convert_to_title_case(
11645        &mut self,
11646        _: &ConvertToTitleCase,
11647        window: &mut Window,
11648        cx: &mut Context<Self>,
11649    ) {
11650        self.manipulate_text(window, cx, |text| {
11651            text.split('\n')
11652                .map(|line| line.to_case(Case::Title))
11653                .join("\n")
11654        })
11655    }
11656
11657    pub fn convert_to_snake_case(
11658        &mut self,
11659        _: &ConvertToSnakeCase,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11664    }
11665
11666    pub fn convert_to_kebab_case(
11667        &mut self,
11668        _: &ConvertToKebabCase,
11669        window: &mut Window,
11670        cx: &mut Context<Self>,
11671    ) {
11672        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11673    }
11674
11675    pub fn convert_to_upper_camel_case(
11676        &mut self,
11677        _: &ConvertToUpperCamelCase,
11678        window: &mut Window,
11679        cx: &mut Context<Self>,
11680    ) {
11681        self.manipulate_text(window, cx, |text| {
11682            text.split('\n')
11683                .map(|line| line.to_case(Case::UpperCamel))
11684                .join("\n")
11685        })
11686    }
11687
11688    pub fn convert_to_lower_camel_case(
11689        &mut self,
11690        _: &ConvertToLowerCamelCase,
11691        window: &mut Window,
11692        cx: &mut Context<Self>,
11693    ) {
11694        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11695    }
11696
11697    pub fn convert_to_opposite_case(
11698        &mut self,
11699        _: &ConvertToOppositeCase,
11700        window: &mut Window,
11701        cx: &mut Context<Self>,
11702    ) {
11703        self.manipulate_text(window, cx, |text| {
11704            text.chars()
11705                .fold(String::with_capacity(text.len()), |mut t, c| {
11706                    if c.is_uppercase() {
11707                        t.extend(c.to_lowercase());
11708                    } else {
11709                        t.extend(c.to_uppercase());
11710                    }
11711                    t
11712                })
11713        })
11714    }
11715
11716    pub fn convert_to_sentence_case(
11717        &mut self,
11718        _: &ConvertToSentenceCase,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11723    }
11724
11725    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11726        self.manipulate_text(window, cx, |text| {
11727            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11728            if has_upper_case_characters {
11729                text.to_lowercase()
11730            } else {
11731                text.to_uppercase()
11732            }
11733        })
11734    }
11735
11736    pub fn convert_to_rot13(
11737        &mut self,
11738        _: &ConvertToRot13,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.manipulate_text(window, cx, |text| {
11743            text.chars()
11744                .map(|c| match c {
11745                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11746                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11747                    _ => c,
11748                })
11749                .collect()
11750        })
11751    }
11752
11753    pub fn convert_to_rot47(
11754        &mut self,
11755        _: &ConvertToRot47,
11756        window: &mut Window,
11757        cx: &mut Context<Self>,
11758    ) {
11759        self.manipulate_text(window, cx, |text| {
11760            text.chars()
11761                .map(|c| {
11762                    let code_point = c as u32;
11763                    if code_point >= 33 && code_point <= 126 {
11764                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11765                    }
11766                    c
11767                })
11768                .collect()
11769        })
11770    }
11771
11772    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11773    where
11774        Fn: FnMut(&str) -> String,
11775    {
11776        let buffer = self.buffer.read(cx).snapshot(cx);
11777
11778        let mut new_selections = Vec::new();
11779        let mut edits = Vec::new();
11780        let mut selection_adjustment = 0isize;
11781
11782        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11783            let selection_is_empty = selection.is_empty();
11784
11785            let (start, end) = if selection_is_empty {
11786                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11787                (word_range.start, word_range.end)
11788            } else {
11789                (
11790                    buffer.point_to_offset(selection.start),
11791                    buffer.point_to_offset(selection.end),
11792                )
11793            };
11794
11795            let text = buffer.text_for_range(start..end).collect::<String>();
11796            let old_length = text.len() as isize;
11797            let text = callback(&text);
11798
11799            new_selections.push(Selection {
11800                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11801                end: MultiBufferOffset(
11802                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11803                ),
11804                goal: SelectionGoal::None,
11805                id: selection.id,
11806                reversed: selection.reversed,
11807            });
11808
11809            selection_adjustment += old_length - text.len() as isize;
11810
11811            edits.push((start..end, text));
11812        }
11813
11814        self.transact(window, cx, |this, window, cx| {
11815            this.buffer.update(cx, |buffer, cx| {
11816                buffer.edit(edits, None, cx);
11817            });
11818
11819            this.change_selections(Default::default(), window, cx, |s| {
11820                s.select(new_selections);
11821            });
11822
11823            this.request_autoscroll(Autoscroll::fit(), cx);
11824        });
11825    }
11826
11827    pub fn move_selection_on_drop(
11828        &mut self,
11829        selection: &Selection<Anchor>,
11830        target: DisplayPoint,
11831        is_cut: bool,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834    ) {
11835        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11836        let buffer = display_map.buffer_snapshot();
11837        let mut edits = Vec::new();
11838        let insert_point = display_map
11839            .clip_point(target, Bias::Left)
11840            .to_point(&display_map);
11841        let text = buffer
11842            .text_for_range(selection.start..selection.end)
11843            .collect::<String>();
11844        if is_cut {
11845            edits.push(((selection.start..selection.end), String::new()));
11846        }
11847        let insert_anchor = buffer.anchor_before(insert_point);
11848        edits.push(((insert_anchor..insert_anchor), text));
11849        let last_edit_start = insert_anchor.bias_left(buffer);
11850        let last_edit_end = insert_anchor.bias_right(buffer);
11851        self.transact(window, cx, |this, window, cx| {
11852            this.buffer.update(cx, |buffer, cx| {
11853                buffer.edit(edits, None, cx);
11854            });
11855            this.change_selections(Default::default(), window, cx, |s| {
11856                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11857            });
11858        });
11859    }
11860
11861    pub fn clear_selection_drag_state(&mut self) {
11862        self.selection_drag_state = SelectionDragState::None;
11863    }
11864
11865    pub fn duplicate(
11866        &mut self,
11867        upwards: bool,
11868        whole_lines: bool,
11869        window: &mut Window,
11870        cx: &mut Context<Self>,
11871    ) {
11872        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11873
11874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11875        let buffer = display_map.buffer_snapshot();
11876        let selections = self.selections.all::<Point>(&display_map);
11877
11878        let mut edits = Vec::new();
11879        let mut selections_iter = selections.iter().peekable();
11880        while let Some(selection) = selections_iter.next() {
11881            let mut rows = selection.spanned_rows(false, &display_map);
11882            // duplicate line-wise
11883            if whole_lines || selection.start == selection.end {
11884                // Avoid duplicating the same lines twice.
11885                while let Some(next_selection) = selections_iter.peek() {
11886                    let next_rows = next_selection.spanned_rows(false, &display_map);
11887                    if next_rows.start < rows.end {
11888                        rows.end = next_rows.end;
11889                        selections_iter.next().unwrap();
11890                    } else {
11891                        break;
11892                    }
11893                }
11894
11895                // Copy the text from the selected row region and splice it either at the start
11896                // or end of the region.
11897                let start = Point::new(rows.start.0, 0);
11898                let end = Point::new(
11899                    rows.end.previous_row().0,
11900                    buffer.line_len(rows.end.previous_row()),
11901                );
11902
11903                let mut text = buffer.text_for_range(start..end).collect::<String>();
11904
11905                let insert_location = if upwards {
11906                    // When duplicating upward, we need to insert before the current line.
11907                    // If we're on the last line and it doesn't end with a newline,
11908                    // we need to add a newline before the duplicated content.
11909                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11910                        && buffer.max_point().column > 0
11911                        && !text.ends_with('\n');
11912
11913                    if needs_leading_newline {
11914                        text.insert(0, '\n');
11915                        end
11916                    } else {
11917                        text.push('\n');
11918                        Point::new(rows.start.0, 0)
11919                    }
11920                } else {
11921                    text.push('\n');
11922                    start
11923                };
11924                edits.push((insert_location..insert_location, text));
11925            } else {
11926                // duplicate character-wise
11927                let start = selection.start;
11928                let end = selection.end;
11929                let text = buffer.text_for_range(start..end).collect::<String>();
11930                edits.push((selection.end..selection.end, text));
11931            }
11932        }
11933
11934        self.transact(window, cx, |this, window, cx| {
11935            this.buffer.update(cx, |buffer, cx| {
11936                buffer.edit(edits, None, cx);
11937            });
11938
11939            // When duplicating upward with whole lines, move the cursor to the duplicated line
11940            if upwards && whole_lines {
11941                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11942
11943                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11944                    let mut new_ranges = Vec::new();
11945                    let selections = s.all::<Point>(&display_map);
11946                    let mut selections_iter = selections.iter().peekable();
11947
11948                    while let Some(first_selection) = selections_iter.next() {
11949                        // Group contiguous selections together to find the total row span
11950                        let mut group_selections = vec![first_selection];
11951                        let mut rows = first_selection.spanned_rows(false, &display_map);
11952
11953                        while let Some(next_selection) = selections_iter.peek() {
11954                            let next_rows = next_selection.spanned_rows(false, &display_map);
11955                            if next_rows.start < rows.end {
11956                                rows.end = next_rows.end;
11957                                group_selections.push(selections_iter.next().unwrap());
11958                            } else {
11959                                break;
11960                            }
11961                        }
11962
11963                        let row_count = rows.end.0 - rows.start.0;
11964
11965                        // Move all selections in this group up by the total number of duplicated rows
11966                        for selection in group_selections {
11967                            let new_start = Point::new(
11968                                selection.start.row.saturating_sub(row_count),
11969                                selection.start.column,
11970                            );
11971
11972                            let new_end = Point::new(
11973                                selection.end.row.saturating_sub(row_count),
11974                                selection.end.column,
11975                            );
11976
11977                            new_ranges.push(new_start..new_end);
11978                        }
11979                    }
11980
11981                    s.select_ranges(new_ranges);
11982                });
11983            }
11984
11985            this.request_autoscroll(Autoscroll::fit(), cx);
11986        });
11987    }
11988
11989    pub fn duplicate_line_up(
11990        &mut self,
11991        _: &DuplicateLineUp,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.duplicate(true, true, window, cx);
11996    }
11997
11998    pub fn duplicate_line_down(
11999        &mut self,
12000        _: &DuplicateLineDown,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.duplicate(false, true, window, cx);
12005    }
12006
12007    pub fn duplicate_selection(
12008        &mut self,
12009        _: &DuplicateSelection,
12010        window: &mut Window,
12011        cx: &mut Context<Self>,
12012    ) {
12013        self.duplicate(false, false, window, cx);
12014    }
12015
12016    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12018        if self.mode.is_single_line() {
12019            cx.propagate();
12020            return;
12021        }
12022
12023        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12024        let buffer = self.buffer.read(cx).snapshot(cx);
12025
12026        let mut edits = Vec::new();
12027        let mut unfold_ranges = Vec::new();
12028        let mut refold_creases = Vec::new();
12029
12030        let selections = self.selections.all::<Point>(&display_map);
12031        let mut selections = selections.iter().peekable();
12032        let mut contiguous_row_selections = Vec::new();
12033        let mut new_selections = Vec::new();
12034
12035        while let Some(selection) = selections.next() {
12036            // Find all the selections that span a contiguous row range
12037            let (start_row, end_row) = consume_contiguous_rows(
12038                &mut contiguous_row_selections,
12039                selection,
12040                &display_map,
12041                &mut selections,
12042            );
12043
12044            // Move the text spanned by the row range to be before the line preceding the row range
12045            if start_row.0 > 0 {
12046                let range_to_move = Point::new(
12047                    start_row.previous_row().0,
12048                    buffer.line_len(start_row.previous_row()),
12049                )
12050                    ..Point::new(
12051                        end_row.previous_row().0,
12052                        buffer.line_len(end_row.previous_row()),
12053                    );
12054                let insertion_point = display_map
12055                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12056                    .0;
12057
12058                // Don't move lines across excerpts
12059                if buffer
12060                    .excerpt_containing(insertion_point..range_to_move.end)
12061                    .is_some()
12062                {
12063                    let text = buffer
12064                        .text_for_range(range_to_move.clone())
12065                        .flat_map(|s| s.chars())
12066                        .skip(1)
12067                        .chain(['\n'])
12068                        .collect::<String>();
12069
12070                    edits.push((
12071                        buffer.anchor_after(range_to_move.start)
12072                            ..buffer.anchor_before(range_to_move.end),
12073                        String::new(),
12074                    ));
12075                    let insertion_anchor = buffer.anchor_after(insertion_point);
12076                    edits.push((insertion_anchor..insertion_anchor, text));
12077
12078                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12079
12080                    // Move selections up
12081                    new_selections.extend(contiguous_row_selections.drain(..).map(
12082                        |mut selection| {
12083                            selection.start.row -= row_delta;
12084                            selection.end.row -= row_delta;
12085                            selection
12086                        },
12087                    ));
12088
12089                    // Move folds up
12090                    unfold_ranges.push(range_to_move.clone());
12091                    for fold in display_map.folds_in_range(
12092                        buffer.anchor_before(range_to_move.start)
12093                            ..buffer.anchor_after(range_to_move.end),
12094                    ) {
12095                        let mut start = fold.range.start.to_point(&buffer);
12096                        let mut end = fold.range.end.to_point(&buffer);
12097                        start.row -= row_delta;
12098                        end.row -= row_delta;
12099                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12100                    }
12101                }
12102            }
12103
12104            // If we didn't move line(s), preserve the existing selections
12105            new_selections.append(&mut contiguous_row_selections);
12106        }
12107
12108        self.transact(window, cx, |this, window, cx| {
12109            this.unfold_ranges(&unfold_ranges, true, true, cx);
12110            this.buffer.update(cx, |buffer, cx| {
12111                for (range, text) in edits {
12112                    buffer.edit([(range, text)], None, cx);
12113                }
12114            });
12115            this.fold_creases(refold_creases, true, window, cx);
12116            this.change_selections(Default::default(), window, cx, |s| {
12117                s.select(new_selections);
12118            })
12119        });
12120    }
12121
12122    pub fn move_line_down(
12123        &mut self,
12124        _: &MoveLineDown,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12129        if self.mode.is_single_line() {
12130            cx.propagate();
12131            return;
12132        }
12133
12134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12135        let buffer = self.buffer.read(cx).snapshot(cx);
12136
12137        let mut edits = Vec::new();
12138        let mut unfold_ranges = Vec::new();
12139        let mut refold_creases = Vec::new();
12140
12141        let selections = self.selections.all::<Point>(&display_map);
12142        let mut selections = selections.iter().peekable();
12143        let mut contiguous_row_selections = Vec::new();
12144        let mut new_selections = Vec::new();
12145
12146        while let Some(selection) = selections.next() {
12147            // Find all the selections that span a contiguous row range
12148            let (start_row, end_row) = consume_contiguous_rows(
12149                &mut contiguous_row_selections,
12150                selection,
12151                &display_map,
12152                &mut selections,
12153            );
12154
12155            // Move the text spanned by the row range to be after the last line of the row range
12156            if end_row.0 <= buffer.max_point().row {
12157                let range_to_move =
12158                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12159                let insertion_point = display_map
12160                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12161                    .0;
12162
12163                // Don't move lines across excerpt boundaries
12164                if buffer
12165                    .excerpt_containing(range_to_move.start..insertion_point)
12166                    .is_some()
12167                {
12168                    let mut text = String::from("\n");
12169                    text.extend(buffer.text_for_range(range_to_move.clone()));
12170                    text.pop(); // Drop trailing newline
12171                    edits.push((
12172                        buffer.anchor_after(range_to_move.start)
12173                            ..buffer.anchor_before(range_to_move.end),
12174                        String::new(),
12175                    ));
12176                    let insertion_anchor = buffer.anchor_after(insertion_point);
12177                    edits.push((insertion_anchor..insertion_anchor, text));
12178
12179                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12180
12181                    // Move selections down
12182                    new_selections.extend(contiguous_row_selections.drain(..).map(
12183                        |mut selection| {
12184                            selection.start.row += row_delta;
12185                            selection.end.row += row_delta;
12186                            selection
12187                        },
12188                    ));
12189
12190                    // Move folds down
12191                    unfold_ranges.push(range_to_move.clone());
12192                    for fold in display_map.folds_in_range(
12193                        buffer.anchor_before(range_to_move.start)
12194                            ..buffer.anchor_after(range_to_move.end),
12195                    ) {
12196                        let mut start = fold.range.start.to_point(&buffer);
12197                        let mut end = fold.range.end.to_point(&buffer);
12198                        start.row += row_delta;
12199                        end.row += row_delta;
12200                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12201                    }
12202                }
12203            }
12204
12205            // If we didn't move line(s), preserve the existing selections
12206            new_selections.append(&mut contiguous_row_selections);
12207        }
12208
12209        self.transact(window, cx, |this, window, cx| {
12210            this.unfold_ranges(&unfold_ranges, true, true, cx);
12211            this.buffer.update(cx, |buffer, cx| {
12212                for (range, text) in edits {
12213                    buffer.edit([(range, text)], None, cx);
12214                }
12215            });
12216            this.fold_creases(refold_creases, true, window, cx);
12217            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12218        });
12219    }
12220
12221    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12222        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12223        let text_layout_details = &self.text_layout_details(window);
12224        self.transact(window, cx, |this, window, cx| {
12225            let edits = this.change_selections(Default::default(), window, cx, |s| {
12226                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12227                s.move_with(|display_map, selection| {
12228                    if !selection.is_empty() {
12229                        return;
12230                    }
12231
12232                    let mut head = selection.head();
12233                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12234                    if head.column() == display_map.line_len(head.row()) {
12235                        transpose_offset = display_map
12236                            .buffer_snapshot()
12237                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12238                    }
12239
12240                    if transpose_offset == MultiBufferOffset(0) {
12241                        return;
12242                    }
12243
12244                    *head.column_mut() += 1;
12245                    head = display_map.clip_point(head, Bias::Right);
12246                    let goal = SelectionGoal::HorizontalPosition(
12247                        display_map
12248                            .x_for_display_point(head, text_layout_details)
12249                            .into(),
12250                    );
12251                    selection.collapse_to(head, goal);
12252
12253                    let transpose_start = display_map
12254                        .buffer_snapshot()
12255                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12256                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12257                        let transpose_end = display_map
12258                            .buffer_snapshot()
12259                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12260                        if let Some(ch) = display_map
12261                            .buffer_snapshot()
12262                            .chars_at(transpose_start)
12263                            .next()
12264                        {
12265                            edits.push((transpose_start..transpose_offset, String::new()));
12266                            edits.push((transpose_end..transpose_end, ch.to_string()));
12267                        }
12268                    }
12269                });
12270                edits
12271            });
12272            this.buffer
12273                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12274            let selections = this
12275                .selections
12276                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12277            this.change_selections(Default::default(), window, cx, |s| {
12278                s.select(selections);
12279            });
12280        });
12281    }
12282
12283    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12285        if self.mode.is_single_line() {
12286            cx.propagate();
12287            return;
12288        }
12289
12290        self.rewrap_impl(RewrapOptions::default(), cx)
12291    }
12292
12293    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12294        let buffer = self.buffer.read(cx).snapshot(cx);
12295        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12296
12297        #[derive(Clone, Debug, PartialEq)]
12298        enum CommentFormat {
12299            /// single line comment, with prefix for line
12300            Line(String),
12301            /// single line within a block comment, with prefix for line
12302            BlockLine(String),
12303            /// a single line of a block comment that includes the initial delimiter
12304            BlockCommentWithStart(BlockCommentConfig),
12305            /// a single line of a block comment that includes the ending delimiter
12306            BlockCommentWithEnd(BlockCommentConfig),
12307        }
12308
12309        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12310        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12311            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12312                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12313                .peekable();
12314
12315            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12316                row
12317            } else {
12318                return Vec::new();
12319            };
12320
12321            let language_settings = buffer.language_settings_at(selection.head(), cx);
12322            let language_scope = buffer.language_scope_at(selection.head());
12323
12324            let indent_and_prefix_for_row =
12325                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12326                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12327                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12328                        &language_scope
12329                    {
12330                        let indent_end = Point::new(row, indent.len);
12331                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12332                        let line_text_after_indent = buffer
12333                            .text_for_range(indent_end..line_end)
12334                            .collect::<String>();
12335
12336                        let is_within_comment_override = buffer
12337                            .language_scope_at(indent_end)
12338                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12339                        let comment_delimiters = if is_within_comment_override {
12340                            // we are within a comment syntax node, but we don't
12341                            // yet know what kind of comment: block, doc or line
12342                            match (
12343                                language_scope.documentation_comment(),
12344                                language_scope.block_comment(),
12345                            ) {
12346                                (Some(config), _) | (_, Some(config))
12347                                    if buffer.contains_str_at(indent_end, &config.start) =>
12348                                {
12349                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12350                                }
12351                                (Some(config), _) | (_, Some(config))
12352                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12353                                {
12354                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12355                                }
12356                                (Some(config), _) | (_, Some(config))
12357                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12358                                {
12359                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12360                                }
12361                                (_, _) => language_scope
12362                                    .line_comment_prefixes()
12363                                    .iter()
12364                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12365                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12366                            }
12367                        } else {
12368                            // we not in an overridden comment node, but we may
12369                            // be within a non-overridden line comment node
12370                            language_scope
12371                                .line_comment_prefixes()
12372                                .iter()
12373                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12374                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12375                        };
12376
12377                        let rewrap_prefix = language_scope
12378                            .rewrap_prefixes()
12379                            .iter()
12380                            .find_map(|prefix_regex| {
12381                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12382                                    if mat.start() == 0 {
12383                                        Some(mat.as_str().to_string())
12384                                    } else {
12385                                        None
12386                                    }
12387                                })
12388                            })
12389                            .flatten();
12390                        (comment_delimiters, rewrap_prefix)
12391                    } else {
12392                        (None, None)
12393                    };
12394                    (indent, comment_prefix, rewrap_prefix)
12395                };
12396
12397            let mut ranges = Vec::new();
12398            let from_empty_selection = selection.is_empty();
12399
12400            let mut current_range_start = first_row;
12401            let mut prev_row = first_row;
12402            let (
12403                mut current_range_indent,
12404                mut current_range_comment_delimiters,
12405                mut current_range_rewrap_prefix,
12406            ) = indent_and_prefix_for_row(first_row);
12407
12408            for row in non_blank_rows_iter.skip(1) {
12409                let has_paragraph_break = row > prev_row + 1;
12410
12411                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12412                    indent_and_prefix_for_row(row);
12413
12414                let has_indent_change = row_indent != current_range_indent;
12415                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12416
12417                let has_boundary_change = has_comment_change
12418                    || row_rewrap_prefix.is_some()
12419                    || (has_indent_change && current_range_comment_delimiters.is_some());
12420
12421                if has_paragraph_break || has_boundary_change {
12422                    ranges.push((
12423                        language_settings.clone(),
12424                        Point::new(current_range_start, 0)
12425                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12426                        current_range_indent,
12427                        current_range_comment_delimiters.clone(),
12428                        current_range_rewrap_prefix.clone(),
12429                        from_empty_selection,
12430                    ));
12431                    current_range_start = row;
12432                    current_range_indent = row_indent;
12433                    current_range_comment_delimiters = row_comment_delimiters;
12434                    current_range_rewrap_prefix = row_rewrap_prefix;
12435                }
12436                prev_row = row;
12437            }
12438
12439            ranges.push((
12440                language_settings.clone(),
12441                Point::new(current_range_start, 0)
12442                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12443                current_range_indent,
12444                current_range_comment_delimiters,
12445                current_range_rewrap_prefix,
12446                from_empty_selection,
12447            ));
12448
12449            ranges
12450        });
12451
12452        let mut edits = Vec::new();
12453        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12454
12455        for (
12456            language_settings,
12457            wrap_range,
12458            mut indent_size,
12459            comment_prefix,
12460            rewrap_prefix,
12461            from_empty_selection,
12462        ) in wrap_ranges
12463        {
12464            let mut start_row = wrap_range.start.row;
12465            let mut end_row = wrap_range.end.row;
12466
12467            // Skip selections that overlap with a range that has already been rewrapped.
12468            let selection_range = start_row..end_row;
12469            if rewrapped_row_ranges
12470                .iter()
12471                .any(|range| range.overlaps(&selection_range))
12472            {
12473                continue;
12474            }
12475
12476            let tab_size = language_settings.tab_size;
12477
12478            let (line_prefix, inside_comment) = match &comment_prefix {
12479                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12480                    (Some(prefix.as_str()), true)
12481                }
12482                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12483                    (Some(prefix.as_ref()), true)
12484                }
12485                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12486                    start: _,
12487                    end: _,
12488                    prefix,
12489                    tab_size,
12490                })) => {
12491                    indent_size.len += tab_size;
12492                    (Some(prefix.as_ref()), true)
12493                }
12494                None => (None, false),
12495            };
12496            let indent_prefix = indent_size.chars().collect::<String>();
12497            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12498
12499            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12500                RewrapBehavior::InComments => inside_comment,
12501                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12502                RewrapBehavior::Anywhere => true,
12503            };
12504
12505            let should_rewrap = options.override_language_settings
12506                || allow_rewrap_based_on_language
12507                || self.hard_wrap.is_some();
12508            if !should_rewrap {
12509                continue;
12510            }
12511
12512            if from_empty_selection {
12513                'expand_upwards: while start_row > 0 {
12514                    let prev_row = start_row - 1;
12515                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12516                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12517                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12518                    {
12519                        start_row = prev_row;
12520                    } else {
12521                        break 'expand_upwards;
12522                    }
12523                }
12524
12525                'expand_downwards: while end_row < buffer.max_point().row {
12526                    let next_row = end_row + 1;
12527                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12528                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12529                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12530                    {
12531                        end_row = next_row;
12532                    } else {
12533                        break 'expand_downwards;
12534                    }
12535                }
12536            }
12537
12538            let start = Point::new(start_row, 0);
12539            let start_offset = ToOffset::to_offset(&start, &buffer);
12540            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12541            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12542            let mut first_line_delimiter = None;
12543            let mut last_line_delimiter = None;
12544            let Some(lines_without_prefixes) = selection_text
12545                .lines()
12546                .enumerate()
12547                .map(|(ix, line)| {
12548                    let line_trimmed = line.trim_start();
12549                    if rewrap_prefix.is_some() && ix > 0 {
12550                        Ok(line_trimmed)
12551                    } else if let Some(
12552                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12553                            start,
12554                            prefix,
12555                            end,
12556                            tab_size,
12557                        })
12558                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12559                            start,
12560                            prefix,
12561                            end,
12562                            tab_size,
12563                        }),
12564                    ) = &comment_prefix
12565                    {
12566                        let line_trimmed = line_trimmed
12567                            .strip_prefix(start.as_ref())
12568                            .map(|s| {
12569                                let mut indent_size = indent_size;
12570                                indent_size.len -= tab_size;
12571                                let indent_prefix: String = indent_size.chars().collect();
12572                                first_line_delimiter = Some((indent_prefix, start));
12573                                s.trim_start()
12574                            })
12575                            .unwrap_or(line_trimmed);
12576                        let line_trimmed = line_trimmed
12577                            .strip_suffix(end.as_ref())
12578                            .map(|s| {
12579                                last_line_delimiter = Some(end);
12580                                s.trim_end()
12581                            })
12582                            .unwrap_or(line_trimmed);
12583                        let line_trimmed = line_trimmed
12584                            .strip_prefix(prefix.as_ref())
12585                            .unwrap_or(line_trimmed);
12586                        Ok(line_trimmed)
12587                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12588                        line_trimmed.strip_prefix(prefix).with_context(|| {
12589                            format!("line did not start with prefix {prefix:?}: {line:?}")
12590                        })
12591                    } else {
12592                        line_trimmed
12593                            .strip_prefix(&line_prefix.trim_start())
12594                            .with_context(|| {
12595                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12596                            })
12597                    }
12598                })
12599                .collect::<Result<Vec<_>, _>>()
12600                .log_err()
12601            else {
12602                continue;
12603            };
12604
12605            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12606                buffer
12607                    .language_settings_at(Point::new(start_row, 0), cx)
12608                    .preferred_line_length as usize
12609            });
12610
12611            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12612                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12613            } else {
12614                line_prefix.clone()
12615            };
12616
12617            let wrapped_text = {
12618                let mut wrapped_text = wrap_with_prefix(
12619                    line_prefix,
12620                    subsequent_lines_prefix,
12621                    lines_without_prefixes.join("\n"),
12622                    wrap_column,
12623                    tab_size,
12624                    options.preserve_existing_whitespace,
12625                );
12626
12627                if let Some((indent, delimiter)) = first_line_delimiter {
12628                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12629                }
12630                if let Some(last_line) = last_line_delimiter {
12631                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12632                }
12633
12634                wrapped_text
12635            };
12636
12637            // TODO: should always use char-based diff while still supporting cursor behavior that
12638            // matches vim.
12639            let mut diff_options = DiffOptions::default();
12640            if options.override_language_settings {
12641                diff_options.max_word_diff_len = 0;
12642                diff_options.max_word_diff_line_count = 0;
12643            } else {
12644                diff_options.max_word_diff_len = usize::MAX;
12645                diff_options.max_word_diff_line_count = usize::MAX;
12646            }
12647
12648            for (old_range, new_text) in
12649                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12650            {
12651                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12652                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12653                edits.push((edit_start..edit_end, new_text));
12654            }
12655
12656            rewrapped_row_ranges.push(start_row..=end_row);
12657        }
12658
12659        self.buffer
12660            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12661    }
12662
12663    pub fn cut_common(
12664        &mut self,
12665        cut_no_selection_line: bool,
12666        window: &mut Window,
12667        cx: &mut Context<Self>,
12668    ) -> ClipboardItem {
12669        let mut text = String::new();
12670        let buffer = self.buffer.read(cx).snapshot(cx);
12671        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12672        let mut clipboard_selections = Vec::with_capacity(selections.len());
12673        {
12674            let max_point = buffer.max_point();
12675            let mut is_first = true;
12676            let mut prev_selection_was_entire_line = false;
12677            for selection in &mut selections {
12678                let is_entire_line =
12679                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12680                if is_entire_line {
12681                    selection.start = Point::new(selection.start.row, 0);
12682                    if !selection.is_empty() && selection.end.column == 0 {
12683                        selection.end = cmp::min(max_point, selection.end);
12684                    } else {
12685                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12686                    }
12687                    selection.goal = SelectionGoal::None;
12688                }
12689                if is_first {
12690                    is_first = false;
12691                } else if !prev_selection_was_entire_line {
12692                    text += "\n";
12693                }
12694                prev_selection_was_entire_line = is_entire_line;
12695                let mut len = 0;
12696                for chunk in buffer.text_for_range(selection.start..selection.end) {
12697                    text.push_str(chunk);
12698                    len += chunk.len();
12699                }
12700                clipboard_selections.push(ClipboardSelection {
12701                    len,
12702                    is_entire_line,
12703                    first_line_indent: buffer
12704                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12705                        .len,
12706                });
12707            }
12708        }
12709
12710        self.transact(window, cx, |this, window, cx| {
12711            this.change_selections(Default::default(), window, cx, |s| {
12712                s.select(selections);
12713            });
12714            this.insert("", window, cx);
12715        });
12716        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12717    }
12718
12719    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12720        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12721        let item = self.cut_common(true, window, cx);
12722        cx.write_to_clipboard(item);
12723    }
12724
12725    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12727        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12728            s.move_with(|snapshot, sel| {
12729                if sel.is_empty() {
12730                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12731                }
12732                if sel.is_empty() {
12733                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12734                }
12735            });
12736        });
12737        let item = self.cut_common(false, window, cx);
12738        cx.set_global(KillRing(item))
12739    }
12740
12741    pub fn kill_ring_yank(
12742        &mut self,
12743        _: &KillRingYank,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12748        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12749            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12750                (kill_ring.text().to_string(), kill_ring.metadata_json())
12751            } else {
12752                return;
12753            }
12754        } else {
12755            return;
12756        };
12757        self.do_paste(&text, metadata, false, window, cx);
12758    }
12759
12760    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12761        self.do_copy(true, cx);
12762    }
12763
12764    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12765        self.do_copy(false, cx);
12766    }
12767
12768    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12769        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12770        let buffer = self.buffer.read(cx).read(cx);
12771        let mut text = String::new();
12772
12773        let mut clipboard_selections = Vec::with_capacity(selections.len());
12774        {
12775            let max_point = buffer.max_point();
12776            let mut is_first = true;
12777            let mut prev_selection_was_entire_line = false;
12778            for selection in &selections {
12779                let mut start = selection.start;
12780                let mut end = selection.end;
12781                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12782                let mut add_trailing_newline = false;
12783                if is_entire_line {
12784                    start = Point::new(start.row, 0);
12785                    let next_line_start = Point::new(end.row + 1, 0);
12786                    if next_line_start <= max_point {
12787                        end = next_line_start;
12788                    } else {
12789                        // We're on the last line without a trailing newline.
12790                        // Copy to the end of the line and add a newline afterwards.
12791                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12792                        add_trailing_newline = true;
12793                    }
12794                }
12795
12796                let mut trimmed_selections = Vec::new();
12797                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12798                    let row = MultiBufferRow(start.row);
12799                    let first_indent = buffer.indent_size_for_line(row);
12800                    if first_indent.len == 0 || start.column > first_indent.len {
12801                        trimmed_selections.push(start..end);
12802                    } else {
12803                        trimmed_selections.push(
12804                            Point::new(row.0, first_indent.len)
12805                                ..Point::new(row.0, buffer.line_len(row)),
12806                        );
12807                        for row in start.row + 1..=end.row {
12808                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12809                            if row == end.row {
12810                                line_len = end.column;
12811                            }
12812                            if line_len == 0 {
12813                                trimmed_selections
12814                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12815                                continue;
12816                            }
12817                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12818                            if row_indent_size.len >= first_indent.len {
12819                                trimmed_selections.push(
12820                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12821                                );
12822                            } else {
12823                                trimmed_selections.clear();
12824                                trimmed_selections.push(start..end);
12825                                break;
12826                            }
12827                        }
12828                    }
12829                } else {
12830                    trimmed_selections.push(start..end);
12831                }
12832
12833                for trimmed_range in trimmed_selections {
12834                    if is_first {
12835                        is_first = false;
12836                    } else if !prev_selection_was_entire_line {
12837                        text += "\n";
12838                    }
12839                    prev_selection_was_entire_line = is_entire_line;
12840                    let mut len = 0;
12841                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12842                        text.push_str(chunk);
12843                        len += chunk.len();
12844                    }
12845                    if add_trailing_newline {
12846                        text.push('\n');
12847                        len += 1;
12848                    }
12849                    clipboard_selections.push(ClipboardSelection {
12850                        len,
12851                        is_entire_line,
12852                        first_line_indent: buffer
12853                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12854                            .len,
12855                    });
12856                }
12857            }
12858        }
12859
12860        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12861            text,
12862            clipboard_selections,
12863        ));
12864    }
12865
12866    pub fn do_paste(
12867        &mut self,
12868        text: &String,
12869        clipboard_selections: Option<Vec<ClipboardSelection>>,
12870        handle_entire_lines: bool,
12871        window: &mut Window,
12872        cx: &mut Context<Self>,
12873    ) {
12874        if self.read_only(cx) {
12875            return;
12876        }
12877
12878        let clipboard_text = Cow::Borrowed(text.as_str());
12879
12880        self.transact(window, cx, |this, window, cx| {
12881            let had_active_edit_prediction = this.has_active_edit_prediction();
12882            let display_map = this.display_snapshot(cx);
12883            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12884            let cursor_offset = this
12885                .selections
12886                .last::<MultiBufferOffset>(&display_map)
12887                .head();
12888
12889            if let Some(mut clipboard_selections) = clipboard_selections {
12890                let all_selections_were_entire_line =
12891                    clipboard_selections.iter().all(|s| s.is_entire_line);
12892                let first_selection_indent_column =
12893                    clipboard_selections.first().map(|s| s.first_line_indent);
12894                if clipboard_selections.len() != old_selections.len() {
12895                    clipboard_selections.drain(..);
12896                }
12897                let mut auto_indent_on_paste = true;
12898
12899                this.buffer.update(cx, |buffer, cx| {
12900                    let snapshot = buffer.read(cx);
12901                    auto_indent_on_paste = snapshot
12902                        .language_settings_at(cursor_offset, cx)
12903                        .auto_indent_on_paste;
12904
12905                    let mut start_offset = 0;
12906                    let mut edits = Vec::new();
12907                    let mut original_indent_columns = Vec::new();
12908                    for (ix, selection) in old_selections.iter().enumerate() {
12909                        let to_insert;
12910                        let entire_line;
12911                        let original_indent_column;
12912                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12913                            let end_offset = start_offset + clipboard_selection.len;
12914                            to_insert = &clipboard_text[start_offset..end_offset];
12915                            entire_line = clipboard_selection.is_entire_line;
12916                            start_offset = if entire_line {
12917                                end_offset
12918                            } else {
12919                                end_offset + 1
12920                            };
12921                            original_indent_column = Some(clipboard_selection.first_line_indent);
12922                        } else {
12923                            to_insert = &*clipboard_text;
12924                            entire_line = all_selections_were_entire_line;
12925                            original_indent_column = first_selection_indent_column
12926                        }
12927
12928                        let (range, to_insert) =
12929                            if selection.is_empty() && handle_entire_lines && entire_line {
12930                                // If the corresponding selection was empty when this slice of the
12931                                // clipboard text was written, then the entire line containing the
12932                                // selection was copied. If this selection is also currently empty,
12933                                // then paste the line before the current line of the buffer.
12934                                let column = selection.start.to_point(&snapshot).column as usize;
12935                                let line_start = selection.start - column;
12936                                (line_start..line_start, Cow::Borrowed(to_insert))
12937                            } else {
12938                                let language = snapshot.language_at(selection.head());
12939                                let range = selection.range();
12940                                if let Some(language) = language
12941                                    && language.name() == "Markdown".into()
12942                                {
12943                                    edit_for_markdown_paste(
12944                                        &snapshot,
12945                                        range,
12946                                        to_insert,
12947                                        url::Url::parse(to_insert).ok(),
12948                                    )
12949                                } else {
12950                                    (range, Cow::Borrowed(to_insert))
12951                                }
12952                            };
12953
12954                        edits.push((range, to_insert));
12955                        original_indent_columns.push(original_indent_column);
12956                    }
12957                    drop(snapshot);
12958
12959                    buffer.edit(
12960                        edits,
12961                        if auto_indent_on_paste {
12962                            Some(AutoindentMode::Block {
12963                                original_indent_columns,
12964                            })
12965                        } else {
12966                            None
12967                        },
12968                        cx,
12969                    );
12970                });
12971
12972                let selections = this
12973                    .selections
12974                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12975                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12976            } else {
12977                let url = url::Url::parse(&clipboard_text).ok();
12978
12979                let auto_indent_mode = if !clipboard_text.is_empty() {
12980                    Some(AutoindentMode::Block {
12981                        original_indent_columns: Vec::new(),
12982                    })
12983                } else {
12984                    None
12985                };
12986
12987                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12988                    let snapshot = buffer.snapshot(cx);
12989
12990                    let anchors = old_selections
12991                        .iter()
12992                        .map(|s| {
12993                            let anchor = snapshot.anchor_after(s.head());
12994                            s.map(|_| anchor)
12995                        })
12996                        .collect::<Vec<_>>();
12997
12998                    let mut edits = Vec::new();
12999
13000                    for selection in old_selections.iter() {
13001                        let language = snapshot.language_at(selection.head());
13002                        let range = selection.range();
13003
13004                        let (edit_range, edit_text) = if let Some(language) = language
13005                            && language.name() == "Markdown".into()
13006                        {
13007                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13008                        } else {
13009                            (range, clipboard_text.clone())
13010                        };
13011
13012                        edits.push((edit_range, edit_text));
13013                    }
13014
13015                    drop(snapshot);
13016                    buffer.edit(edits, auto_indent_mode, cx);
13017
13018                    anchors
13019                });
13020
13021                this.change_selections(Default::default(), window, cx, |s| {
13022                    s.select_anchors(selection_anchors);
13023                });
13024            }
13025
13026            //   🤔                 |    ..     | show_in_menu |
13027            // | ..                  |   true        true
13028            // | had_edit_prediction |   false       true
13029
13030            let trigger_in_words =
13031                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13032
13033            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13034        });
13035    }
13036
13037    pub fn diff_clipboard_with_selection(
13038        &mut self,
13039        _: &DiffClipboardWithSelection,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        let selections = self
13044            .selections
13045            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13046
13047        if selections.is_empty() {
13048            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13049            return;
13050        };
13051
13052        let clipboard_text = match cx.read_from_clipboard() {
13053            Some(item) => match item.entries().first() {
13054                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13055                _ => None,
13056            },
13057            None => None,
13058        };
13059
13060        let Some(clipboard_text) = clipboard_text else {
13061            log::warn!("Clipboard doesn't contain text.");
13062            return;
13063        };
13064
13065        window.dispatch_action(
13066            Box::new(DiffClipboardWithSelectionData {
13067                clipboard_text,
13068                editor: cx.entity(),
13069            }),
13070            cx,
13071        );
13072    }
13073
13074    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13076        if let Some(item) = cx.read_from_clipboard() {
13077            let entries = item.entries();
13078
13079            match entries.first() {
13080                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13081                // of all the pasted entries.
13082                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13083                    .do_paste(
13084                        clipboard_string.text(),
13085                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13086                        true,
13087                        window,
13088                        cx,
13089                    ),
13090                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13091            }
13092        }
13093    }
13094
13095    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13096        if self.read_only(cx) {
13097            return;
13098        }
13099
13100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13101
13102        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13103            if let Some((selections, _)) =
13104                self.selection_history.transaction(transaction_id).cloned()
13105            {
13106                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13107                    s.select_anchors(selections.to_vec());
13108                });
13109            } else {
13110                log::error!(
13111                    "No entry in selection_history found for undo. \
13112                     This may correspond to a bug where undo does not update the selection. \
13113                     If this is occurring, please add details to \
13114                     https://github.com/zed-industries/zed/issues/22692"
13115                );
13116            }
13117            self.request_autoscroll(Autoscroll::fit(), cx);
13118            self.unmark_text(window, cx);
13119            self.refresh_edit_prediction(true, false, window, cx);
13120            cx.emit(EditorEvent::Edited { transaction_id });
13121            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13122        }
13123    }
13124
13125    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13126        if self.read_only(cx) {
13127            return;
13128        }
13129
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13131
13132        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13133            if let Some((_, Some(selections))) =
13134                self.selection_history.transaction(transaction_id).cloned()
13135            {
13136                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13137                    s.select_anchors(selections.to_vec());
13138                });
13139            } else {
13140                log::error!(
13141                    "No entry in selection_history found for redo. \
13142                     This may correspond to a bug where undo does not update the selection. \
13143                     If this is occurring, please add details to \
13144                     https://github.com/zed-industries/zed/issues/22692"
13145                );
13146            }
13147            self.request_autoscroll(Autoscroll::fit(), cx);
13148            self.unmark_text(window, cx);
13149            self.refresh_edit_prediction(true, false, window, cx);
13150            cx.emit(EditorEvent::Edited { transaction_id });
13151        }
13152    }
13153
13154    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13155        self.buffer
13156            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13157    }
13158
13159    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13160        self.buffer
13161            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13162    }
13163
13164    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13166        self.change_selections(Default::default(), window, cx, |s| {
13167            s.move_with(|map, selection| {
13168                let cursor = if selection.is_empty() {
13169                    movement::left(map, selection.start)
13170                } else {
13171                    selection.start
13172                };
13173                selection.collapse_to(cursor, SelectionGoal::None);
13174            });
13175        })
13176    }
13177
13178    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13182        })
13183    }
13184
13185    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13187        self.change_selections(Default::default(), window, cx, |s| {
13188            s.move_with(|map, selection| {
13189                let cursor = if selection.is_empty() {
13190                    movement::right(map, selection.end)
13191                } else {
13192                    selection.end
13193                };
13194                selection.collapse_to(cursor, SelectionGoal::None)
13195            });
13196        })
13197    }
13198
13199    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13201        self.change_selections(Default::default(), window, cx, |s| {
13202            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13203        });
13204    }
13205
13206    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13207        if self.take_rename(true, window, cx).is_some() {
13208            return;
13209        }
13210
13211        if self.mode.is_single_line() {
13212            cx.propagate();
13213            return;
13214        }
13215
13216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13217
13218        let text_layout_details = &self.text_layout_details(window);
13219        let selection_count = self.selections.count();
13220        let first_selection = self.selections.first_anchor();
13221
13222        self.change_selections(Default::default(), window, cx, |s| {
13223            s.move_with(|map, selection| {
13224                if !selection.is_empty() {
13225                    selection.goal = SelectionGoal::None;
13226                }
13227                let (cursor, goal) = movement::up(
13228                    map,
13229                    selection.start,
13230                    selection.goal,
13231                    false,
13232                    text_layout_details,
13233                );
13234                selection.collapse_to(cursor, goal);
13235            });
13236        });
13237
13238        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13239        {
13240            cx.propagate();
13241        }
13242    }
13243
13244    pub fn move_up_by_lines(
13245        &mut self,
13246        action: &MoveUpByLines,
13247        window: &mut Window,
13248        cx: &mut Context<Self>,
13249    ) {
13250        if self.take_rename(true, window, cx).is_some() {
13251            return;
13252        }
13253
13254        if self.mode.is_single_line() {
13255            cx.propagate();
13256            return;
13257        }
13258
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260
13261        let text_layout_details = &self.text_layout_details(window);
13262
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_with(|map, selection| {
13265                if !selection.is_empty() {
13266                    selection.goal = SelectionGoal::None;
13267                }
13268                let (cursor, goal) = movement::up_by_rows(
13269                    map,
13270                    selection.start,
13271                    action.lines,
13272                    selection.goal,
13273                    false,
13274                    text_layout_details,
13275                );
13276                selection.collapse_to(cursor, goal);
13277            });
13278        })
13279    }
13280
13281    pub fn move_down_by_lines(
13282        &mut self,
13283        action: &MoveDownByLines,
13284        window: &mut Window,
13285        cx: &mut Context<Self>,
13286    ) {
13287        if self.take_rename(true, window, cx).is_some() {
13288            return;
13289        }
13290
13291        if self.mode.is_single_line() {
13292            cx.propagate();
13293            return;
13294        }
13295
13296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13297
13298        let text_layout_details = &self.text_layout_details(window);
13299
13300        self.change_selections(Default::default(), window, cx, |s| {
13301            s.move_with(|map, selection| {
13302                if !selection.is_empty() {
13303                    selection.goal = SelectionGoal::None;
13304                }
13305                let (cursor, goal) = movement::down_by_rows(
13306                    map,
13307                    selection.start,
13308                    action.lines,
13309                    selection.goal,
13310                    false,
13311                    text_layout_details,
13312                );
13313                selection.collapse_to(cursor, goal);
13314            });
13315        })
13316    }
13317
13318    pub fn select_down_by_lines(
13319        &mut self,
13320        action: &SelectDownByLines,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        let text_layout_details = &self.text_layout_details(window);
13326        self.change_selections(Default::default(), window, cx, |s| {
13327            s.move_heads_with(|map, head, goal| {
13328                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13329            })
13330        })
13331    }
13332
13333    pub fn select_up_by_lines(
13334        &mut self,
13335        action: &SelectUpByLines,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13340        let text_layout_details = &self.text_layout_details(window);
13341        self.change_selections(Default::default(), window, cx, |s| {
13342            s.move_heads_with(|map, head, goal| {
13343                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13344            })
13345        })
13346    }
13347
13348    pub fn select_page_up(
13349        &mut self,
13350        _: &SelectPageUp,
13351        window: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        let Some(row_count) = self.visible_row_count() else {
13355            return;
13356        };
13357
13358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13359
13360        let text_layout_details = &self.text_layout_details(window);
13361
13362        self.change_selections(Default::default(), window, cx, |s| {
13363            s.move_heads_with(|map, head, goal| {
13364                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13365            })
13366        })
13367    }
13368
13369    pub fn move_page_up(
13370        &mut self,
13371        action: &MovePageUp,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if self.take_rename(true, window, cx).is_some() {
13376            return;
13377        }
13378
13379        if self
13380            .context_menu
13381            .borrow_mut()
13382            .as_mut()
13383            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13384            .unwrap_or(false)
13385        {
13386            return;
13387        }
13388
13389        if matches!(self.mode, EditorMode::SingleLine) {
13390            cx.propagate();
13391            return;
13392        }
13393
13394        let Some(row_count) = self.visible_row_count() else {
13395            return;
13396        };
13397
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399
13400        let effects = if action.center_cursor {
13401            SelectionEffects::scroll(Autoscroll::center())
13402        } else {
13403            SelectionEffects::default()
13404        };
13405
13406        let text_layout_details = &self.text_layout_details(window);
13407
13408        self.change_selections(effects, window, cx, |s| {
13409            s.move_with(|map, selection| {
13410                if !selection.is_empty() {
13411                    selection.goal = SelectionGoal::None;
13412                }
13413                let (cursor, goal) = movement::up_by_rows(
13414                    map,
13415                    selection.end,
13416                    row_count,
13417                    selection.goal,
13418                    false,
13419                    text_layout_details,
13420                );
13421                selection.collapse_to(cursor, goal);
13422            });
13423        });
13424    }
13425
13426    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13428        let text_layout_details = &self.text_layout_details(window);
13429        self.change_selections(Default::default(), window, cx, |s| {
13430            s.move_heads_with(|map, head, goal| {
13431                movement::up(map, head, goal, false, text_layout_details)
13432            })
13433        })
13434    }
13435
13436    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13437        self.take_rename(true, window, cx);
13438
13439        if self.mode.is_single_line() {
13440            cx.propagate();
13441            return;
13442        }
13443
13444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13445
13446        let text_layout_details = &self.text_layout_details(window);
13447        let selection_count = self.selections.count();
13448        let first_selection = self.selections.first_anchor();
13449
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.move_with(|map, selection| {
13452                if !selection.is_empty() {
13453                    selection.goal = SelectionGoal::None;
13454                }
13455                let (cursor, goal) = movement::down(
13456                    map,
13457                    selection.end,
13458                    selection.goal,
13459                    false,
13460                    text_layout_details,
13461                );
13462                selection.collapse_to(cursor, goal);
13463            });
13464        });
13465
13466        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13467        {
13468            cx.propagate();
13469        }
13470    }
13471
13472    pub fn select_page_down(
13473        &mut self,
13474        _: &SelectPageDown,
13475        window: &mut Window,
13476        cx: &mut Context<Self>,
13477    ) {
13478        let Some(row_count) = self.visible_row_count() else {
13479            return;
13480        };
13481
13482        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13483
13484        let text_layout_details = &self.text_layout_details(window);
13485
13486        self.change_selections(Default::default(), window, cx, |s| {
13487            s.move_heads_with(|map, head, goal| {
13488                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13489            })
13490        })
13491    }
13492
13493    pub fn move_page_down(
13494        &mut self,
13495        action: &MovePageDown,
13496        window: &mut Window,
13497        cx: &mut Context<Self>,
13498    ) {
13499        if self.take_rename(true, window, cx).is_some() {
13500            return;
13501        }
13502
13503        if self
13504            .context_menu
13505            .borrow_mut()
13506            .as_mut()
13507            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13508            .unwrap_or(false)
13509        {
13510            return;
13511        }
13512
13513        if matches!(self.mode, EditorMode::SingleLine) {
13514            cx.propagate();
13515            return;
13516        }
13517
13518        let Some(row_count) = self.visible_row_count() else {
13519            return;
13520        };
13521
13522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13523
13524        let effects = if action.center_cursor {
13525            SelectionEffects::scroll(Autoscroll::center())
13526        } else {
13527            SelectionEffects::default()
13528        };
13529
13530        let text_layout_details = &self.text_layout_details(window);
13531        self.change_selections(effects, window, cx, |s| {
13532            s.move_with(|map, selection| {
13533                if !selection.is_empty() {
13534                    selection.goal = SelectionGoal::None;
13535                }
13536                let (cursor, goal) = movement::down_by_rows(
13537                    map,
13538                    selection.end,
13539                    row_count,
13540                    selection.goal,
13541                    false,
13542                    text_layout_details,
13543                );
13544                selection.collapse_to(cursor, goal);
13545            });
13546        });
13547    }
13548
13549    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        let text_layout_details = &self.text_layout_details(window);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_heads_with(|map, head, goal| {
13554                movement::down(map, head, goal, false, text_layout_details)
13555            })
13556        });
13557    }
13558
13559    pub fn context_menu_first(
13560        &mut self,
13561        _: &ContextMenuFirst,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13566            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13567        }
13568    }
13569
13570    pub fn context_menu_prev(
13571        &mut self,
13572        _: &ContextMenuPrevious,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13577            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13578        }
13579    }
13580
13581    pub fn context_menu_next(
13582        &mut self,
13583        _: &ContextMenuNext,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13588            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13589        }
13590    }
13591
13592    pub fn context_menu_last(
13593        &mut self,
13594        _: &ContextMenuLast,
13595        window: &mut Window,
13596        cx: &mut Context<Self>,
13597    ) {
13598        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13599            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13600        }
13601    }
13602
13603    pub fn signature_help_prev(
13604        &mut self,
13605        _: &SignatureHelpPrevious,
13606        _: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        if let Some(popover) = self.signature_help_state.popover_mut() {
13610            if popover.current_signature == 0 {
13611                popover.current_signature = popover.signatures.len() - 1;
13612            } else {
13613                popover.current_signature -= 1;
13614            }
13615            cx.notify();
13616        }
13617    }
13618
13619    pub fn signature_help_next(
13620        &mut self,
13621        _: &SignatureHelpNext,
13622        _: &mut Window,
13623        cx: &mut Context<Self>,
13624    ) {
13625        if let Some(popover) = self.signature_help_state.popover_mut() {
13626            if popover.current_signature + 1 == popover.signatures.len() {
13627                popover.current_signature = 0;
13628            } else {
13629                popover.current_signature += 1;
13630            }
13631            cx.notify();
13632        }
13633    }
13634
13635    pub fn move_to_previous_word_start(
13636        &mut self,
13637        _: &MoveToPreviousWordStart,
13638        window: &mut Window,
13639        cx: &mut Context<Self>,
13640    ) {
13641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13642        self.change_selections(Default::default(), window, cx, |s| {
13643            s.move_cursors_with(|map, head, _| {
13644                (
13645                    movement::previous_word_start(map, head),
13646                    SelectionGoal::None,
13647                )
13648            });
13649        })
13650    }
13651
13652    pub fn move_to_previous_subword_start(
13653        &mut self,
13654        _: &MoveToPreviousSubwordStart,
13655        window: &mut Window,
13656        cx: &mut Context<Self>,
13657    ) {
13658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13659        self.change_selections(Default::default(), window, cx, |s| {
13660            s.move_cursors_with(|map, head, _| {
13661                (
13662                    movement::previous_subword_start(map, head),
13663                    SelectionGoal::None,
13664                )
13665            });
13666        })
13667    }
13668
13669    pub fn select_to_previous_word_start(
13670        &mut self,
13671        _: &SelectToPreviousWordStart,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13676        self.change_selections(Default::default(), window, cx, |s| {
13677            s.move_heads_with(|map, head, _| {
13678                (
13679                    movement::previous_word_start(map, head),
13680                    SelectionGoal::None,
13681                )
13682            });
13683        })
13684    }
13685
13686    pub fn select_to_previous_subword_start(
13687        &mut self,
13688        _: &SelectToPreviousSubwordStart,
13689        window: &mut Window,
13690        cx: &mut Context<Self>,
13691    ) {
13692        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13693        self.change_selections(Default::default(), window, cx, |s| {
13694            s.move_heads_with(|map, head, _| {
13695                (
13696                    movement::previous_subword_start(map, head),
13697                    SelectionGoal::None,
13698                )
13699            });
13700        })
13701    }
13702
13703    pub fn delete_to_previous_word_start(
13704        &mut self,
13705        action: &DeleteToPreviousWordStart,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13710        self.transact(window, cx, |this, window, cx| {
13711            this.select_autoclose_pair(window, cx);
13712            this.change_selections(Default::default(), window, cx, |s| {
13713                s.move_with(|map, selection| {
13714                    if selection.is_empty() {
13715                        let mut cursor = if action.ignore_newlines {
13716                            movement::previous_word_start(map, selection.head())
13717                        } else {
13718                            movement::previous_word_start_or_newline(map, selection.head())
13719                        };
13720                        cursor = movement::adjust_greedy_deletion(
13721                            map,
13722                            selection.head(),
13723                            cursor,
13724                            action.ignore_brackets,
13725                        );
13726                        selection.set_head(cursor, SelectionGoal::None);
13727                    }
13728                });
13729            });
13730            this.insert("", window, cx);
13731        });
13732    }
13733
13734    pub fn delete_to_previous_subword_start(
13735        &mut self,
13736        _: &DeleteToPreviousSubwordStart,
13737        window: &mut Window,
13738        cx: &mut Context<Self>,
13739    ) {
13740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13741        self.transact(window, cx, |this, window, cx| {
13742            this.select_autoclose_pair(window, cx);
13743            this.change_selections(Default::default(), window, cx, |s| {
13744                s.move_with(|map, selection| {
13745                    if selection.is_empty() {
13746                        let mut cursor = movement::previous_subword_start(map, selection.head());
13747                        cursor =
13748                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13749                        selection.set_head(cursor, SelectionGoal::None);
13750                    }
13751                });
13752            });
13753            this.insert("", window, cx);
13754        });
13755    }
13756
13757    pub fn move_to_next_word_end(
13758        &mut self,
13759        _: &MoveToNextWordEnd,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13764        self.change_selections(Default::default(), window, cx, |s| {
13765            s.move_cursors_with(|map, head, _| {
13766                (movement::next_word_end(map, head), SelectionGoal::None)
13767            });
13768        })
13769    }
13770
13771    pub fn move_to_next_subword_end(
13772        &mut self,
13773        _: &MoveToNextSubwordEnd,
13774        window: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_cursors_with(|map, head, _| {
13780                (movement::next_subword_end(map, head), SelectionGoal::None)
13781            });
13782        })
13783    }
13784
13785    pub fn select_to_next_word_end(
13786        &mut self,
13787        _: &SelectToNextWordEnd,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13792        self.change_selections(Default::default(), window, cx, |s| {
13793            s.move_heads_with(|map, head, _| {
13794                (movement::next_word_end(map, head), SelectionGoal::None)
13795            });
13796        })
13797    }
13798
13799    pub fn select_to_next_subword_end(
13800        &mut self,
13801        _: &SelectToNextSubwordEnd,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13806        self.change_selections(Default::default(), window, cx, |s| {
13807            s.move_heads_with(|map, head, _| {
13808                (movement::next_subword_end(map, head), SelectionGoal::None)
13809            });
13810        })
13811    }
13812
13813    pub fn delete_to_next_word_end(
13814        &mut self,
13815        action: &DeleteToNextWordEnd,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13820        self.transact(window, cx, |this, window, cx| {
13821            this.change_selections(Default::default(), window, cx, |s| {
13822                s.move_with(|map, selection| {
13823                    if selection.is_empty() {
13824                        let mut cursor = if action.ignore_newlines {
13825                            movement::next_word_end(map, selection.head())
13826                        } else {
13827                            movement::next_word_end_or_newline(map, selection.head())
13828                        };
13829                        cursor = movement::adjust_greedy_deletion(
13830                            map,
13831                            selection.head(),
13832                            cursor,
13833                            action.ignore_brackets,
13834                        );
13835                        selection.set_head(cursor, SelectionGoal::None);
13836                    }
13837                });
13838            });
13839            this.insert("", window, cx);
13840        });
13841    }
13842
13843    pub fn delete_to_next_subword_end(
13844        &mut self,
13845        _: &DeleteToNextSubwordEnd,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13850        self.transact(window, cx, |this, window, cx| {
13851            this.change_selections(Default::default(), window, cx, |s| {
13852                s.move_with(|map, selection| {
13853                    if selection.is_empty() {
13854                        let mut cursor = movement::next_subword_end(map, selection.head());
13855                        cursor =
13856                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13857                        selection.set_head(cursor, SelectionGoal::None);
13858                    }
13859                });
13860            });
13861            this.insert("", window, cx);
13862        });
13863    }
13864
13865    pub fn move_to_beginning_of_line(
13866        &mut self,
13867        action: &MoveToBeginningOfLine,
13868        window: &mut Window,
13869        cx: &mut Context<Self>,
13870    ) {
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.move_cursors_with(|map, head, _| {
13874                (
13875                    movement::indented_line_beginning(
13876                        map,
13877                        head,
13878                        action.stop_at_soft_wraps,
13879                        action.stop_at_indent,
13880                    ),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn select_to_beginning_of_line(
13888        &mut self,
13889        action: &SelectToBeginningOfLine,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        self.change_selections(Default::default(), window, cx, |s| {
13895            s.move_heads_with(|map, head, _| {
13896                (
13897                    movement::indented_line_beginning(
13898                        map,
13899                        head,
13900                        action.stop_at_soft_wraps,
13901                        action.stop_at_indent,
13902                    ),
13903                    SelectionGoal::None,
13904                )
13905            });
13906        });
13907    }
13908
13909    pub fn delete_to_beginning_of_line(
13910        &mut self,
13911        action: &DeleteToBeginningOfLine,
13912        window: &mut Window,
13913        cx: &mut Context<Self>,
13914    ) {
13915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13916        self.transact(window, cx, |this, window, cx| {
13917            this.change_selections(Default::default(), window, cx, |s| {
13918                s.move_with(|_, selection| {
13919                    selection.reversed = true;
13920                });
13921            });
13922
13923            this.select_to_beginning_of_line(
13924                &SelectToBeginningOfLine {
13925                    stop_at_soft_wraps: false,
13926                    stop_at_indent: action.stop_at_indent,
13927                },
13928                window,
13929                cx,
13930            );
13931            this.backspace(&Backspace, window, cx);
13932        });
13933    }
13934
13935    pub fn move_to_end_of_line(
13936        &mut self,
13937        action: &MoveToEndOfLine,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13942        self.change_selections(Default::default(), window, cx, |s| {
13943            s.move_cursors_with(|map, head, _| {
13944                (
13945                    movement::line_end(map, head, action.stop_at_soft_wraps),
13946                    SelectionGoal::None,
13947                )
13948            });
13949        })
13950    }
13951
13952    pub fn select_to_end_of_line(
13953        &mut self,
13954        action: &SelectToEndOfLine,
13955        window: &mut Window,
13956        cx: &mut Context<Self>,
13957    ) {
13958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13959        self.change_selections(Default::default(), window, cx, |s| {
13960            s.move_heads_with(|map, head, _| {
13961                (
13962                    movement::line_end(map, head, action.stop_at_soft_wraps),
13963                    SelectionGoal::None,
13964                )
13965            });
13966        })
13967    }
13968
13969    pub fn delete_to_end_of_line(
13970        &mut self,
13971        _: &DeleteToEndOfLine,
13972        window: &mut Window,
13973        cx: &mut Context<Self>,
13974    ) {
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13976        self.transact(window, cx, |this, window, cx| {
13977            this.select_to_end_of_line(
13978                &SelectToEndOfLine {
13979                    stop_at_soft_wraps: false,
13980                },
13981                window,
13982                cx,
13983            );
13984            this.delete(&Delete, window, cx);
13985        });
13986    }
13987
13988    pub fn cut_to_end_of_line(
13989        &mut self,
13990        action: &CutToEndOfLine,
13991        window: &mut Window,
13992        cx: &mut Context<Self>,
13993    ) {
13994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13995        self.transact(window, cx, |this, window, cx| {
13996            this.select_to_end_of_line(
13997                &SelectToEndOfLine {
13998                    stop_at_soft_wraps: false,
13999                },
14000                window,
14001                cx,
14002            );
14003            if !action.stop_at_newlines {
14004                this.change_selections(Default::default(), window, cx, |s| {
14005                    s.move_with(|_, sel| {
14006                        if sel.is_empty() {
14007                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14008                        }
14009                    });
14010                });
14011            }
14012            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14013            let item = this.cut_common(false, window, cx);
14014            cx.write_to_clipboard(item);
14015        });
14016    }
14017
14018    pub fn move_to_start_of_paragraph(
14019        &mut self,
14020        _: &MoveToStartOfParagraph,
14021        window: &mut Window,
14022        cx: &mut Context<Self>,
14023    ) {
14024        if matches!(self.mode, EditorMode::SingleLine) {
14025            cx.propagate();
14026            return;
14027        }
14028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14029        self.change_selections(Default::default(), window, cx, |s| {
14030            s.move_with(|map, selection| {
14031                selection.collapse_to(
14032                    movement::start_of_paragraph(map, selection.head(), 1),
14033                    SelectionGoal::None,
14034                )
14035            });
14036        })
14037    }
14038
14039    pub fn move_to_end_of_paragraph(
14040        &mut self,
14041        _: &MoveToEndOfParagraph,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) {
14045        if matches!(self.mode, EditorMode::SingleLine) {
14046            cx.propagate();
14047            return;
14048        }
14049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14050        self.change_selections(Default::default(), window, cx, |s| {
14051            s.move_with(|map, selection| {
14052                selection.collapse_to(
14053                    movement::end_of_paragraph(map, selection.head(), 1),
14054                    SelectionGoal::None,
14055                )
14056            });
14057        })
14058    }
14059
14060    pub fn select_to_start_of_paragraph(
14061        &mut self,
14062        _: &SelectToStartOfParagraph,
14063        window: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) {
14066        if matches!(self.mode, EditorMode::SingleLine) {
14067            cx.propagate();
14068            return;
14069        }
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.move_heads_with(|map, head, _| {
14073                (
14074                    movement::start_of_paragraph(map, head, 1),
14075                    SelectionGoal::None,
14076                )
14077            });
14078        })
14079    }
14080
14081    pub fn select_to_end_of_paragraph(
14082        &mut self,
14083        _: &SelectToEndOfParagraph,
14084        window: &mut Window,
14085        cx: &mut Context<Self>,
14086    ) {
14087        if matches!(self.mode, EditorMode::SingleLine) {
14088            cx.propagate();
14089            return;
14090        }
14091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14092        self.change_selections(Default::default(), window, cx, |s| {
14093            s.move_heads_with(|map, head, _| {
14094                (
14095                    movement::end_of_paragraph(map, head, 1),
14096                    SelectionGoal::None,
14097                )
14098            });
14099        })
14100    }
14101
14102    pub fn move_to_start_of_excerpt(
14103        &mut self,
14104        _: &MoveToStartOfExcerpt,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) {
14108        if matches!(self.mode, EditorMode::SingleLine) {
14109            cx.propagate();
14110            return;
14111        }
14112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14113        self.change_selections(Default::default(), window, cx, |s| {
14114            s.move_with(|map, selection| {
14115                selection.collapse_to(
14116                    movement::start_of_excerpt(
14117                        map,
14118                        selection.head(),
14119                        workspace::searchable::Direction::Prev,
14120                    ),
14121                    SelectionGoal::None,
14122                )
14123            });
14124        })
14125    }
14126
14127    pub fn move_to_start_of_next_excerpt(
14128        &mut self,
14129        _: &MoveToStartOfNextExcerpt,
14130        window: &mut Window,
14131        cx: &mut Context<Self>,
14132    ) {
14133        if matches!(self.mode, EditorMode::SingleLine) {
14134            cx.propagate();
14135            return;
14136        }
14137
14138        self.change_selections(Default::default(), window, cx, |s| {
14139            s.move_with(|map, selection| {
14140                selection.collapse_to(
14141                    movement::start_of_excerpt(
14142                        map,
14143                        selection.head(),
14144                        workspace::searchable::Direction::Next,
14145                    ),
14146                    SelectionGoal::None,
14147                )
14148            });
14149        })
14150    }
14151
14152    pub fn move_to_end_of_excerpt(
14153        &mut self,
14154        _: &MoveToEndOfExcerpt,
14155        window: &mut Window,
14156        cx: &mut Context<Self>,
14157    ) {
14158        if matches!(self.mode, EditorMode::SingleLine) {
14159            cx.propagate();
14160            return;
14161        }
14162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14163        self.change_selections(Default::default(), window, cx, |s| {
14164            s.move_with(|map, selection| {
14165                selection.collapse_to(
14166                    movement::end_of_excerpt(
14167                        map,
14168                        selection.head(),
14169                        workspace::searchable::Direction::Next,
14170                    ),
14171                    SelectionGoal::None,
14172                )
14173            });
14174        })
14175    }
14176
14177    pub fn move_to_end_of_previous_excerpt(
14178        &mut self,
14179        _: &MoveToEndOfPreviousExcerpt,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        if matches!(self.mode, EditorMode::SingleLine) {
14184            cx.propagate();
14185            return;
14186        }
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188        self.change_selections(Default::default(), window, cx, |s| {
14189            s.move_with(|map, selection| {
14190                selection.collapse_to(
14191                    movement::end_of_excerpt(
14192                        map,
14193                        selection.head(),
14194                        workspace::searchable::Direction::Prev,
14195                    ),
14196                    SelectionGoal::None,
14197                )
14198            });
14199        })
14200    }
14201
14202    pub fn select_to_start_of_excerpt(
14203        &mut self,
14204        _: &SelectToStartOfExcerpt,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) {
14208        if matches!(self.mode, EditorMode::SingleLine) {
14209            cx.propagate();
14210            return;
14211        }
14212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14213        self.change_selections(Default::default(), window, cx, |s| {
14214            s.move_heads_with(|map, head, _| {
14215                (
14216                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14217                    SelectionGoal::None,
14218                )
14219            });
14220        })
14221    }
14222
14223    pub fn select_to_start_of_next_excerpt(
14224        &mut self,
14225        _: &SelectToStartOfNextExcerpt,
14226        window: &mut Window,
14227        cx: &mut Context<Self>,
14228    ) {
14229        if matches!(self.mode, EditorMode::SingleLine) {
14230            cx.propagate();
14231            return;
14232        }
14233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14234        self.change_selections(Default::default(), window, cx, |s| {
14235            s.move_heads_with(|map, head, _| {
14236                (
14237                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14238                    SelectionGoal::None,
14239                )
14240            });
14241        })
14242    }
14243
14244    pub fn select_to_end_of_excerpt(
14245        &mut self,
14246        _: &SelectToEndOfExcerpt,
14247        window: &mut Window,
14248        cx: &mut Context<Self>,
14249    ) {
14250        if matches!(self.mode, EditorMode::SingleLine) {
14251            cx.propagate();
14252            return;
14253        }
14254        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14255        self.change_selections(Default::default(), window, cx, |s| {
14256            s.move_heads_with(|map, head, _| {
14257                (
14258                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14259                    SelectionGoal::None,
14260                )
14261            });
14262        })
14263    }
14264
14265    pub fn select_to_end_of_previous_excerpt(
14266        &mut self,
14267        _: &SelectToEndOfPreviousExcerpt,
14268        window: &mut Window,
14269        cx: &mut Context<Self>,
14270    ) {
14271        if matches!(self.mode, EditorMode::SingleLine) {
14272            cx.propagate();
14273            return;
14274        }
14275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14276        self.change_selections(Default::default(), window, cx, |s| {
14277            s.move_heads_with(|map, head, _| {
14278                (
14279                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14280                    SelectionGoal::None,
14281                )
14282            });
14283        })
14284    }
14285
14286    pub fn move_to_beginning(
14287        &mut self,
14288        _: &MoveToBeginning,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) {
14292        if matches!(self.mode, EditorMode::SingleLine) {
14293            cx.propagate();
14294            return;
14295        }
14296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14297        self.change_selections(Default::default(), window, cx, |s| {
14298            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14299        });
14300    }
14301
14302    pub fn select_to_beginning(
14303        &mut self,
14304        _: &SelectToBeginning,
14305        window: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14309        selection.set_head(Point::zero(), SelectionGoal::None);
14310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14311        self.change_selections(Default::default(), window, cx, |s| {
14312            s.select(vec![selection]);
14313        });
14314    }
14315
14316    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14317        if matches!(self.mode, EditorMode::SingleLine) {
14318            cx.propagate();
14319            return;
14320        }
14321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14322        let cursor = self.buffer.read(cx).read(cx).len();
14323        self.change_selections(Default::default(), window, cx, |s| {
14324            s.select_ranges(vec![cursor..cursor])
14325        });
14326    }
14327
14328    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14329        self.nav_history = nav_history;
14330    }
14331
14332    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14333        self.nav_history.as_ref()
14334    }
14335
14336    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14337        self.push_to_nav_history(
14338            self.selections.newest_anchor().head(),
14339            None,
14340            false,
14341            true,
14342            cx,
14343        );
14344    }
14345
14346    fn push_to_nav_history(
14347        &mut self,
14348        cursor_anchor: Anchor,
14349        new_position: Option<Point>,
14350        is_deactivate: bool,
14351        always: bool,
14352        cx: &mut Context<Self>,
14353    ) {
14354        if let Some(nav_history) = self.nav_history.as_mut() {
14355            let buffer = self.buffer.read(cx).read(cx);
14356            let cursor_position = cursor_anchor.to_point(&buffer);
14357            let scroll_state = self.scroll_manager.anchor();
14358            let scroll_top_row = scroll_state.top_row(&buffer);
14359            drop(buffer);
14360
14361            if let Some(new_position) = new_position {
14362                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14363                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14364                    return;
14365                }
14366            }
14367
14368            nav_history.push(
14369                Some(NavigationData {
14370                    cursor_anchor,
14371                    cursor_position,
14372                    scroll_anchor: scroll_state,
14373                    scroll_top_row,
14374                }),
14375                cx,
14376            );
14377            cx.emit(EditorEvent::PushedToNavHistory {
14378                anchor: cursor_anchor,
14379                is_deactivate,
14380            })
14381        }
14382    }
14383
14384    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14386        let buffer = self.buffer.read(cx).snapshot(cx);
14387        let mut selection = self
14388            .selections
14389            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14390        selection.set_head(buffer.len(), SelectionGoal::None);
14391        self.change_selections(Default::default(), window, cx, |s| {
14392            s.select(vec![selection]);
14393        });
14394    }
14395
14396    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14398        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14399            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14400        });
14401    }
14402
14403    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14406        let mut selections = self.selections.all::<Point>(&display_map);
14407        let max_point = display_map.buffer_snapshot().max_point();
14408        for selection in &mut selections {
14409            let rows = selection.spanned_rows(true, &display_map);
14410            selection.start = Point::new(rows.start.0, 0);
14411            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14412            selection.reversed = false;
14413        }
14414        self.change_selections(Default::default(), window, cx, |s| {
14415            s.select(selections);
14416        });
14417    }
14418
14419    pub fn split_selection_into_lines(
14420        &mut self,
14421        action: &SplitSelectionIntoLines,
14422        window: &mut Window,
14423        cx: &mut Context<Self>,
14424    ) {
14425        let selections = self
14426            .selections
14427            .all::<Point>(&self.display_snapshot(cx))
14428            .into_iter()
14429            .map(|selection| selection.start..selection.end)
14430            .collect::<Vec<_>>();
14431        self.unfold_ranges(&selections, true, true, cx);
14432
14433        let mut new_selection_ranges = Vec::new();
14434        {
14435            let buffer = self.buffer.read(cx).read(cx);
14436            for selection in selections {
14437                for row in selection.start.row..selection.end.row {
14438                    let line_start = Point::new(row, 0);
14439                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14440
14441                    if action.keep_selections {
14442                        // Keep the selection range for each line
14443                        let selection_start = if row == selection.start.row {
14444                            selection.start
14445                        } else {
14446                            line_start
14447                        };
14448                        new_selection_ranges.push(selection_start..line_end);
14449                    } else {
14450                        // Collapse to cursor at end of line
14451                        new_selection_ranges.push(line_end..line_end);
14452                    }
14453                }
14454
14455                let is_multiline_selection = selection.start.row != selection.end.row;
14456                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14457                // so this action feels more ergonomic when paired with other selection operations
14458                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14459                if !should_skip_last {
14460                    if action.keep_selections {
14461                        if is_multiline_selection {
14462                            let line_start = Point::new(selection.end.row, 0);
14463                            new_selection_ranges.push(line_start..selection.end);
14464                        } else {
14465                            new_selection_ranges.push(selection.start..selection.end);
14466                        }
14467                    } else {
14468                        new_selection_ranges.push(selection.end..selection.end);
14469                    }
14470                }
14471            }
14472        }
14473        self.change_selections(Default::default(), window, cx, |s| {
14474            s.select_ranges(new_selection_ranges);
14475        });
14476    }
14477
14478    pub fn add_selection_above(
14479        &mut self,
14480        action: &AddSelectionAbove,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        self.add_selection(true, action.skip_soft_wrap, window, cx);
14485    }
14486
14487    pub fn add_selection_below(
14488        &mut self,
14489        action: &AddSelectionBelow,
14490        window: &mut Window,
14491        cx: &mut Context<Self>,
14492    ) {
14493        self.add_selection(false, action.skip_soft_wrap, window, cx);
14494    }
14495
14496    fn add_selection(
14497        &mut self,
14498        above: bool,
14499        skip_soft_wrap: bool,
14500        window: &mut Window,
14501        cx: &mut Context<Self>,
14502    ) {
14503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14504
14505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14506        let all_selections = self.selections.all::<Point>(&display_map);
14507        let text_layout_details = self.text_layout_details(window);
14508
14509        let (mut columnar_selections, new_selections_to_columnarize) = {
14510            if let Some(state) = self.add_selections_state.as_ref() {
14511                let columnar_selection_ids: HashSet<_> = state
14512                    .groups
14513                    .iter()
14514                    .flat_map(|group| group.stack.iter())
14515                    .copied()
14516                    .collect();
14517
14518                all_selections
14519                    .into_iter()
14520                    .partition(|s| columnar_selection_ids.contains(&s.id))
14521            } else {
14522                (Vec::new(), all_selections)
14523            }
14524        };
14525
14526        let mut state = self
14527            .add_selections_state
14528            .take()
14529            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14530
14531        for selection in new_selections_to_columnarize {
14532            let range = selection.display_range(&display_map).sorted();
14533            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14534            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14535            let positions = start_x.min(end_x)..start_x.max(end_x);
14536            let mut stack = Vec::new();
14537            for row in range.start.row().0..=range.end.row().0 {
14538                if let Some(selection) = self.selections.build_columnar_selection(
14539                    &display_map,
14540                    DisplayRow(row),
14541                    &positions,
14542                    selection.reversed,
14543                    &text_layout_details,
14544                ) {
14545                    stack.push(selection.id);
14546                    columnar_selections.push(selection);
14547                }
14548            }
14549            if !stack.is_empty() {
14550                if above {
14551                    stack.reverse();
14552                }
14553                state.groups.push(AddSelectionsGroup { above, stack });
14554            }
14555        }
14556
14557        let mut final_selections = Vec::new();
14558        let end_row = if above {
14559            DisplayRow(0)
14560        } else {
14561            display_map.max_point().row()
14562        };
14563
14564        let mut last_added_item_per_group = HashMap::default();
14565        for group in state.groups.iter_mut() {
14566            if let Some(last_id) = group.stack.last() {
14567                last_added_item_per_group.insert(*last_id, group);
14568            }
14569        }
14570
14571        for selection in columnar_selections {
14572            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14573                if above == group.above {
14574                    let range = selection.display_range(&display_map).sorted();
14575                    debug_assert_eq!(range.start.row(), range.end.row());
14576                    let mut row = range.start.row();
14577                    let positions =
14578                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14579                            Pixels::from(start)..Pixels::from(end)
14580                        } else {
14581                            let start_x =
14582                                display_map.x_for_display_point(range.start, &text_layout_details);
14583                            let end_x =
14584                                display_map.x_for_display_point(range.end, &text_layout_details);
14585                            start_x.min(end_x)..start_x.max(end_x)
14586                        };
14587
14588                    let mut maybe_new_selection = None;
14589                    let direction = if above { -1 } else { 1 };
14590
14591                    while row != end_row {
14592                        if skip_soft_wrap {
14593                            row = display_map
14594                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14595                                .row();
14596                        } else if above {
14597                            row.0 -= 1;
14598                        } else {
14599                            row.0 += 1;
14600                        }
14601
14602                        if let Some(new_selection) = self.selections.build_columnar_selection(
14603                            &display_map,
14604                            row,
14605                            &positions,
14606                            selection.reversed,
14607                            &text_layout_details,
14608                        ) {
14609                            maybe_new_selection = Some(new_selection);
14610                            break;
14611                        }
14612                    }
14613
14614                    if let Some(new_selection) = maybe_new_selection {
14615                        group.stack.push(new_selection.id);
14616                        if above {
14617                            final_selections.push(new_selection);
14618                            final_selections.push(selection);
14619                        } else {
14620                            final_selections.push(selection);
14621                            final_selections.push(new_selection);
14622                        }
14623                    } else {
14624                        final_selections.push(selection);
14625                    }
14626                } else {
14627                    group.stack.pop();
14628                }
14629            } else {
14630                final_selections.push(selection);
14631            }
14632        }
14633
14634        self.change_selections(Default::default(), window, cx, |s| {
14635            s.select(final_selections);
14636        });
14637
14638        let final_selection_ids: HashSet<_> = self
14639            .selections
14640            .all::<Point>(&display_map)
14641            .iter()
14642            .map(|s| s.id)
14643            .collect();
14644        state.groups.retain_mut(|group| {
14645            // selections might get merged above so we remove invalid items from stacks
14646            group.stack.retain(|id| final_selection_ids.contains(id));
14647
14648            // single selection in stack can be treated as initial state
14649            group.stack.len() > 1
14650        });
14651
14652        if !state.groups.is_empty() {
14653            self.add_selections_state = Some(state);
14654        }
14655    }
14656
14657    fn select_match_ranges(
14658        &mut self,
14659        range: Range<MultiBufferOffset>,
14660        reversed: bool,
14661        replace_newest: bool,
14662        auto_scroll: Option<Autoscroll>,
14663        window: &mut Window,
14664        cx: &mut Context<Editor>,
14665    ) {
14666        self.unfold_ranges(
14667            std::slice::from_ref(&range),
14668            false,
14669            auto_scroll.is_some(),
14670            cx,
14671        );
14672        let effects = if let Some(scroll) = auto_scroll {
14673            SelectionEffects::scroll(scroll)
14674        } else {
14675            SelectionEffects::no_scroll()
14676        };
14677        self.change_selections(effects, window, cx, |s| {
14678            if replace_newest {
14679                s.delete(s.newest_anchor().id);
14680            }
14681            if reversed {
14682                s.insert_range(range.end..range.start);
14683            } else {
14684                s.insert_range(range);
14685            }
14686        });
14687    }
14688
14689    pub fn select_next_match_internal(
14690        &mut self,
14691        display_map: &DisplaySnapshot,
14692        replace_newest: bool,
14693        autoscroll: Option<Autoscroll>,
14694        window: &mut Window,
14695        cx: &mut Context<Self>,
14696    ) -> Result<()> {
14697        let buffer = display_map.buffer_snapshot();
14698        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14699        if let Some(mut select_next_state) = self.select_next_state.take() {
14700            let query = &select_next_state.query;
14701            if !select_next_state.done {
14702                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14703                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14704                let mut next_selected_range = None;
14705
14706                let bytes_after_last_selection =
14707                    buffer.bytes_in_range(last_selection.end..buffer.len());
14708                let bytes_before_first_selection =
14709                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14710                let query_matches = query
14711                    .stream_find_iter(bytes_after_last_selection)
14712                    .map(|result| (last_selection.end, result))
14713                    .chain(
14714                        query
14715                            .stream_find_iter(bytes_before_first_selection)
14716                            .map(|result| (MultiBufferOffset(0), result)),
14717                    );
14718
14719                for (start_offset, query_match) in query_matches {
14720                    let query_match = query_match.unwrap(); // can only fail due to I/O
14721                    let offset_range =
14722                        start_offset + query_match.start()..start_offset + query_match.end();
14723
14724                    if !select_next_state.wordwise
14725                        || (!buffer.is_inside_word(offset_range.start, None)
14726                            && !buffer.is_inside_word(offset_range.end, None))
14727                    {
14728                        let idx = selections
14729                            .partition_point(|selection| selection.end <= offset_range.start);
14730                        let overlaps = selections
14731                            .get(idx)
14732                            .map_or(false, |selection| selection.start < offset_range.end);
14733
14734                        if !overlaps {
14735                            next_selected_range = Some(offset_range);
14736                            break;
14737                        }
14738                    }
14739                }
14740
14741                if let Some(next_selected_range) = next_selected_range {
14742                    self.select_match_ranges(
14743                        next_selected_range,
14744                        last_selection.reversed,
14745                        replace_newest,
14746                        autoscroll,
14747                        window,
14748                        cx,
14749                    );
14750                } else {
14751                    select_next_state.done = true;
14752                }
14753            }
14754
14755            self.select_next_state = Some(select_next_state);
14756        } else {
14757            let mut only_carets = true;
14758            let mut same_text_selected = true;
14759            let mut selected_text = None;
14760
14761            let mut selections_iter = selections.iter().peekable();
14762            while let Some(selection) = selections_iter.next() {
14763                if selection.start != selection.end {
14764                    only_carets = false;
14765                }
14766
14767                if same_text_selected {
14768                    if selected_text.is_none() {
14769                        selected_text =
14770                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14771                    }
14772
14773                    if let Some(next_selection) = selections_iter.peek() {
14774                        if next_selection.len() == selection.len() {
14775                            let next_selected_text = buffer
14776                                .text_for_range(next_selection.range())
14777                                .collect::<String>();
14778                            if Some(next_selected_text) != selected_text {
14779                                same_text_selected = false;
14780                                selected_text = None;
14781                            }
14782                        } else {
14783                            same_text_selected = false;
14784                            selected_text = None;
14785                        }
14786                    }
14787                }
14788            }
14789
14790            if only_carets {
14791                for selection in &mut selections {
14792                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14793                    selection.start = word_range.start;
14794                    selection.end = word_range.end;
14795                    selection.goal = SelectionGoal::None;
14796                    selection.reversed = false;
14797                    self.select_match_ranges(
14798                        selection.start..selection.end,
14799                        selection.reversed,
14800                        replace_newest,
14801                        autoscroll,
14802                        window,
14803                        cx,
14804                    );
14805                }
14806
14807                if selections.len() == 1 {
14808                    let selection = selections
14809                        .last()
14810                        .expect("ensured that there's only one selection");
14811                    let query = buffer
14812                        .text_for_range(selection.start..selection.end)
14813                        .collect::<String>();
14814                    let is_empty = query.is_empty();
14815                    let select_state = SelectNextState {
14816                        query: self.build_query(&[query], cx)?,
14817                        wordwise: true,
14818                        done: is_empty,
14819                    };
14820                    self.select_next_state = Some(select_state);
14821                } else {
14822                    self.select_next_state = None;
14823                }
14824            } else if let Some(selected_text) = selected_text {
14825                self.select_next_state = Some(SelectNextState {
14826                    query: self.build_query(&[selected_text], cx)?,
14827                    wordwise: false,
14828                    done: false,
14829                });
14830                self.select_next_match_internal(
14831                    display_map,
14832                    replace_newest,
14833                    autoscroll,
14834                    window,
14835                    cx,
14836                )?;
14837            }
14838        }
14839        Ok(())
14840    }
14841
14842    pub fn select_all_matches(
14843        &mut self,
14844        _action: &SelectAllMatches,
14845        window: &mut Window,
14846        cx: &mut Context<Self>,
14847    ) -> Result<()> {
14848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14849
14850        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14851
14852        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14853        let Some(select_next_state) = self.select_next_state.as_mut() else {
14854            return Ok(());
14855        };
14856        if select_next_state.done {
14857            return Ok(());
14858        }
14859
14860        let mut new_selections = Vec::new();
14861
14862        let reversed = self
14863            .selections
14864            .oldest::<MultiBufferOffset>(&display_map)
14865            .reversed;
14866        let buffer = display_map.buffer_snapshot();
14867        let query_matches = select_next_state
14868            .query
14869            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14870
14871        for query_match in query_matches.into_iter() {
14872            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14873            let offset_range = if reversed {
14874                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14875            } else {
14876                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14877            };
14878
14879            if !select_next_state.wordwise
14880                || (!buffer.is_inside_word(offset_range.start, None)
14881                    && !buffer.is_inside_word(offset_range.end, None))
14882            {
14883                new_selections.push(offset_range.start..offset_range.end);
14884            }
14885        }
14886
14887        select_next_state.done = true;
14888
14889        if new_selections.is_empty() {
14890            log::error!("bug: new_selections is empty in select_all_matches");
14891            return Ok(());
14892        }
14893
14894        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14895        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14896            selections.select_ranges(new_selections)
14897        });
14898
14899        Ok(())
14900    }
14901
14902    pub fn select_next(
14903        &mut self,
14904        action: &SelectNext,
14905        window: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) -> Result<()> {
14908        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14909        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14910        self.select_next_match_internal(
14911            &display_map,
14912            action.replace_newest,
14913            Some(Autoscroll::newest()),
14914            window,
14915            cx,
14916        )?;
14917        Ok(())
14918    }
14919
14920    pub fn select_previous(
14921        &mut self,
14922        action: &SelectPrevious,
14923        window: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) -> Result<()> {
14926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14928        let buffer = display_map.buffer_snapshot();
14929        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14930        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14931            let query = &select_prev_state.query;
14932            if !select_prev_state.done {
14933                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14934                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14935                let mut next_selected_range = None;
14936                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14937                let bytes_before_last_selection =
14938                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14939                let bytes_after_first_selection =
14940                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14941                let query_matches = query
14942                    .stream_find_iter(bytes_before_last_selection)
14943                    .map(|result| (last_selection.start, result))
14944                    .chain(
14945                        query
14946                            .stream_find_iter(bytes_after_first_selection)
14947                            .map(|result| (buffer.len(), result)),
14948                    );
14949                for (end_offset, query_match) in query_matches {
14950                    let query_match = query_match.unwrap(); // can only fail due to I/O
14951                    let offset_range =
14952                        end_offset - query_match.end()..end_offset - query_match.start();
14953
14954                    if !select_prev_state.wordwise
14955                        || (!buffer.is_inside_word(offset_range.start, None)
14956                            && !buffer.is_inside_word(offset_range.end, None))
14957                    {
14958                        next_selected_range = Some(offset_range);
14959                        break;
14960                    }
14961                }
14962
14963                if let Some(next_selected_range) = next_selected_range {
14964                    self.select_match_ranges(
14965                        next_selected_range,
14966                        last_selection.reversed,
14967                        action.replace_newest,
14968                        Some(Autoscroll::newest()),
14969                        window,
14970                        cx,
14971                    );
14972                } else {
14973                    select_prev_state.done = true;
14974                }
14975            }
14976
14977            self.select_prev_state = Some(select_prev_state);
14978        } else {
14979            let mut only_carets = true;
14980            let mut same_text_selected = true;
14981            let mut selected_text = None;
14982
14983            let mut selections_iter = selections.iter().peekable();
14984            while let Some(selection) = selections_iter.next() {
14985                if selection.start != selection.end {
14986                    only_carets = false;
14987                }
14988
14989                if same_text_selected {
14990                    if selected_text.is_none() {
14991                        selected_text =
14992                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14993                    }
14994
14995                    if let Some(next_selection) = selections_iter.peek() {
14996                        if next_selection.len() == selection.len() {
14997                            let next_selected_text = buffer
14998                                .text_for_range(next_selection.range())
14999                                .collect::<String>();
15000                            if Some(next_selected_text) != selected_text {
15001                                same_text_selected = false;
15002                                selected_text = None;
15003                            }
15004                        } else {
15005                            same_text_selected = false;
15006                            selected_text = None;
15007                        }
15008                    }
15009                }
15010            }
15011
15012            if only_carets {
15013                for selection in &mut selections {
15014                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15015                    selection.start = word_range.start;
15016                    selection.end = word_range.end;
15017                    selection.goal = SelectionGoal::None;
15018                    selection.reversed = false;
15019                    self.select_match_ranges(
15020                        selection.start..selection.end,
15021                        selection.reversed,
15022                        action.replace_newest,
15023                        Some(Autoscroll::newest()),
15024                        window,
15025                        cx,
15026                    );
15027                }
15028                if selections.len() == 1 {
15029                    let selection = selections
15030                        .last()
15031                        .expect("ensured that there's only one selection");
15032                    let query = buffer
15033                        .text_for_range(selection.start..selection.end)
15034                        .collect::<String>();
15035                    let is_empty = query.is_empty();
15036                    let select_state = SelectNextState {
15037                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15038                        wordwise: true,
15039                        done: is_empty,
15040                    };
15041                    self.select_prev_state = Some(select_state);
15042                } else {
15043                    self.select_prev_state = None;
15044                }
15045            } else if let Some(selected_text) = selected_text {
15046                self.select_prev_state = Some(SelectNextState {
15047                    query: self
15048                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15049                    wordwise: false,
15050                    done: false,
15051                });
15052                self.select_previous(action, window, cx)?;
15053            }
15054        }
15055        Ok(())
15056    }
15057
15058    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15059    /// setting the case sensitivity based on the global
15060    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15061    /// editor's settings.
15062    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15063    where
15064        I: IntoIterator<Item = P>,
15065        P: AsRef<[u8]>,
15066    {
15067        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15068            || EditorSettings::get_global(cx).search.case_sensitive,
15069            |value| value,
15070        );
15071
15072        let mut builder = AhoCorasickBuilder::new();
15073        builder.ascii_case_insensitive(!case_sensitive);
15074        builder.build(patterns)
15075    }
15076
15077    pub fn find_next_match(
15078        &mut self,
15079        _: &FindNextMatch,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) -> Result<()> {
15083        let selections = self.selections.disjoint_anchors_arc();
15084        match selections.first() {
15085            Some(first) if selections.len() >= 2 => {
15086                self.change_selections(Default::default(), window, cx, |s| {
15087                    s.select_ranges([first.range()]);
15088                });
15089            }
15090            _ => self.select_next(
15091                &SelectNext {
15092                    replace_newest: true,
15093                },
15094                window,
15095                cx,
15096            )?,
15097        }
15098        Ok(())
15099    }
15100
15101    pub fn find_previous_match(
15102        &mut self,
15103        _: &FindPreviousMatch,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) -> Result<()> {
15107        let selections = self.selections.disjoint_anchors_arc();
15108        match selections.last() {
15109            Some(last) if selections.len() >= 2 => {
15110                self.change_selections(Default::default(), window, cx, |s| {
15111                    s.select_ranges([last.range()]);
15112                });
15113            }
15114            _ => self.select_previous(
15115                &SelectPrevious {
15116                    replace_newest: true,
15117                },
15118                window,
15119                cx,
15120            )?,
15121        }
15122        Ok(())
15123    }
15124
15125    pub fn toggle_comments(
15126        &mut self,
15127        action: &ToggleComments,
15128        window: &mut Window,
15129        cx: &mut Context<Self>,
15130    ) {
15131        if self.read_only(cx) {
15132            return;
15133        }
15134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15135        let text_layout_details = &self.text_layout_details(window);
15136        self.transact(window, cx, |this, window, cx| {
15137            let mut selections = this
15138                .selections
15139                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15140            let mut edits = Vec::new();
15141            let mut selection_edit_ranges = Vec::new();
15142            let mut last_toggled_row = None;
15143            let snapshot = this.buffer.read(cx).read(cx);
15144            let empty_str: Arc<str> = Arc::default();
15145            let mut suffixes_inserted = Vec::new();
15146            let ignore_indent = action.ignore_indent;
15147
15148            fn comment_prefix_range(
15149                snapshot: &MultiBufferSnapshot,
15150                row: MultiBufferRow,
15151                comment_prefix: &str,
15152                comment_prefix_whitespace: &str,
15153                ignore_indent: bool,
15154            ) -> Range<Point> {
15155                let indent_size = if ignore_indent {
15156                    0
15157                } else {
15158                    snapshot.indent_size_for_line(row).len
15159                };
15160
15161                let start = Point::new(row.0, indent_size);
15162
15163                let mut line_bytes = snapshot
15164                    .bytes_in_range(start..snapshot.max_point())
15165                    .flatten()
15166                    .copied();
15167
15168                // If this line currently begins with the line comment prefix, then record
15169                // the range containing the prefix.
15170                if line_bytes
15171                    .by_ref()
15172                    .take(comment_prefix.len())
15173                    .eq(comment_prefix.bytes())
15174                {
15175                    // Include any whitespace that matches the comment prefix.
15176                    let matching_whitespace_len = line_bytes
15177                        .zip(comment_prefix_whitespace.bytes())
15178                        .take_while(|(a, b)| a == b)
15179                        .count() as u32;
15180                    let end = Point::new(
15181                        start.row,
15182                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15183                    );
15184                    start..end
15185                } else {
15186                    start..start
15187                }
15188            }
15189
15190            fn comment_suffix_range(
15191                snapshot: &MultiBufferSnapshot,
15192                row: MultiBufferRow,
15193                comment_suffix: &str,
15194                comment_suffix_has_leading_space: bool,
15195            ) -> Range<Point> {
15196                let end = Point::new(row.0, snapshot.line_len(row));
15197                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15198
15199                let mut line_end_bytes = snapshot
15200                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15201                    .flatten()
15202                    .copied();
15203
15204                let leading_space_len = if suffix_start_column > 0
15205                    && line_end_bytes.next() == Some(b' ')
15206                    && comment_suffix_has_leading_space
15207                {
15208                    1
15209                } else {
15210                    0
15211                };
15212
15213                // If this line currently begins with the line comment prefix, then record
15214                // the range containing the prefix.
15215                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15216                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15217                    start..end
15218                } else {
15219                    end..end
15220                }
15221            }
15222
15223            // TODO: Handle selections that cross excerpts
15224            for selection in &mut selections {
15225                let start_column = snapshot
15226                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15227                    .len;
15228                let language = if let Some(language) =
15229                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15230                {
15231                    language
15232                } else {
15233                    continue;
15234                };
15235
15236                selection_edit_ranges.clear();
15237
15238                // If multiple selections contain a given row, avoid processing that
15239                // row more than once.
15240                let mut start_row = MultiBufferRow(selection.start.row);
15241                if last_toggled_row == Some(start_row) {
15242                    start_row = start_row.next_row();
15243                }
15244                let end_row =
15245                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15246                        MultiBufferRow(selection.end.row - 1)
15247                    } else {
15248                        MultiBufferRow(selection.end.row)
15249                    };
15250                last_toggled_row = Some(end_row);
15251
15252                if start_row > end_row {
15253                    continue;
15254                }
15255
15256                // If the language has line comments, toggle those.
15257                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15258
15259                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15260                if ignore_indent {
15261                    full_comment_prefixes = full_comment_prefixes
15262                        .into_iter()
15263                        .map(|s| Arc::from(s.trim_end()))
15264                        .collect();
15265                }
15266
15267                if !full_comment_prefixes.is_empty() {
15268                    let first_prefix = full_comment_prefixes
15269                        .first()
15270                        .expect("prefixes is non-empty");
15271                    let prefix_trimmed_lengths = full_comment_prefixes
15272                        .iter()
15273                        .map(|p| p.trim_end_matches(' ').len())
15274                        .collect::<SmallVec<[usize; 4]>>();
15275
15276                    let mut all_selection_lines_are_comments = true;
15277
15278                    for row in start_row.0..=end_row.0 {
15279                        let row = MultiBufferRow(row);
15280                        if start_row < end_row && snapshot.is_line_blank(row) {
15281                            continue;
15282                        }
15283
15284                        let prefix_range = full_comment_prefixes
15285                            .iter()
15286                            .zip(prefix_trimmed_lengths.iter().copied())
15287                            .map(|(prefix, trimmed_prefix_len)| {
15288                                comment_prefix_range(
15289                                    snapshot.deref(),
15290                                    row,
15291                                    &prefix[..trimmed_prefix_len],
15292                                    &prefix[trimmed_prefix_len..],
15293                                    ignore_indent,
15294                                )
15295                            })
15296                            .max_by_key(|range| range.end.column - range.start.column)
15297                            .expect("prefixes is non-empty");
15298
15299                        if prefix_range.is_empty() {
15300                            all_selection_lines_are_comments = false;
15301                        }
15302
15303                        selection_edit_ranges.push(prefix_range);
15304                    }
15305
15306                    if all_selection_lines_are_comments {
15307                        edits.extend(
15308                            selection_edit_ranges
15309                                .iter()
15310                                .cloned()
15311                                .map(|range| (range, empty_str.clone())),
15312                        );
15313                    } else {
15314                        let min_column = selection_edit_ranges
15315                            .iter()
15316                            .map(|range| range.start.column)
15317                            .min()
15318                            .unwrap_or(0);
15319                        edits.extend(selection_edit_ranges.iter().map(|range| {
15320                            let position = Point::new(range.start.row, min_column);
15321                            (position..position, first_prefix.clone())
15322                        }));
15323                    }
15324                } else if let Some(BlockCommentConfig {
15325                    start: full_comment_prefix,
15326                    end: comment_suffix,
15327                    ..
15328                }) = language.block_comment()
15329                {
15330                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15331                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15332                    let prefix_range = comment_prefix_range(
15333                        snapshot.deref(),
15334                        start_row,
15335                        comment_prefix,
15336                        comment_prefix_whitespace,
15337                        ignore_indent,
15338                    );
15339                    let suffix_range = comment_suffix_range(
15340                        snapshot.deref(),
15341                        end_row,
15342                        comment_suffix.trim_start_matches(' '),
15343                        comment_suffix.starts_with(' '),
15344                    );
15345
15346                    if prefix_range.is_empty() || suffix_range.is_empty() {
15347                        edits.push((
15348                            prefix_range.start..prefix_range.start,
15349                            full_comment_prefix.clone(),
15350                        ));
15351                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15352                        suffixes_inserted.push((end_row, comment_suffix.len()));
15353                    } else {
15354                        edits.push((prefix_range, empty_str.clone()));
15355                        edits.push((suffix_range, empty_str.clone()));
15356                    }
15357                } else {
15358                    continue;
15359                }
15360            }
15361
15362            drop(snapshot);
15363            this.buffer.update(cx, |buffer, cx| {
15364                buffer.edit(edits, None, cx);
15365            });
15366
15367            // Adjust selections so that they end before any comment suffixes that
15368            // were inserted.
15369            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15370            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15371            let snapshot = this.buffer.read(cx).read(cx);
15372            for selection in &mut selections {
15373                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15374                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15375                        Ordering::Less => {
15376                            suffixes_inserted.next();
15377                            continue;
15378                        }
15379                        Ordering::Greater => break,
15380                        Ordering::Equal => {
15381                            if selection.end.column == snapshot.line_len(row) {
15382                                if selection.is_empty() {
15383                                    selection.start.column -= suffix_len as u32;
15384                                }
15385                                selection.end.column -= suffix_len as u32;
15386                            }
15387                            break;
15388                        }
15389                    }
15390                }
15391            }
15392
15393            drop(snapshot);
15394            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15395
15396            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15397            let selections_on_single_row = selections.windows(2).all(|selections| {
15398                selections[0].start.row == selections[1].start.row
15399                    && selections[0].end.row == selections[1].end.row
15400                    && selections[0].start.row == selections[0].end.row
15401            });
15402            let selections_selecting = selections
15403                .iter()
15404                .any(|selection| selection.start != selection.end);
15405            let advance_downwards = action.advance_downwards
15406                && selections_on_single_row
15407                && !selections_selecting
15408                && !matches!(this.mode, EditorMode::SingleLine);
15409
15410            if advance_downwards {
15411                let snapshot = this.buffer.read(cx).snapshot(cx);
15412
15413                this.change_selections(Default::default(), window, cx, |s| {
15414                    s.move_cursors_with(|display_snapshot, display_point, _| {
15415                        let mut point = display_point.to_point(display_snapshot);
15416                        point.row += 1;
15417                        point = snapshot.clip_point(point, Bias::Left);
15418                        let display_point = point.to_display_point(display_snapshot);
15419                        let goal = SelectionGoal::HorizontalPosition(
15420                            display_snapshot
15421                                .x_for_display_point(display_point, text_layout_details)
15422                                .into(),
15423                        );
15424                        (display_point, goal)
15425                    })
15426                });
15427            }
15428        });
15429    }
15430
15431    pub fn select_enclosing_symbol(
15432        &mut self,
15433        _: &SelectEnclosingSymbol,
15434        window: &mut Window,
15435        cx: &mut Context<Self>,
15436    ) {
15437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15438
15439        let buffer = self.buffer.read(cx).snapshot(cx);
15440        let old_selections = self
15441            .selections
15442            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15443            .into_boxed_slice();
15444
15445        fn update_selection(
15446            selection: &Selection<MultiBufferOffset>,
15447            buffer_snap: &MultiBufferSnapshot,
15448        ) -> Option<Selection<MultiBufferOffset>> {
15449            let cursor = selection.head();
15450            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15451            for symbol in symbols.iter().rev() {
15452                let start = symbol.range.start.to_offset(buffer_snap);
15453                let end = symbol.range.end.to_offset(buffer_snap);
15454                let new_range = start..end;
15455                if start < selection.start || end > selection.end {
15456                    return Some(Selection {
15457                        id: selection.id,
15458                        start: new_range.start,
15459                        end: new_range.end,
15460                        goal: SelectionGoal::None,
15461                        reversed: selection.reversed,
15462                    });
15463                }
15464            }
15465            None
15466        }
15467
15468        let mut selected_larger_symbol = false;
15469        let new_selections = old_selections
15470            .iter()
15471            .map(|selection| match update_selection(selection, &buffer) {
15472                Some(new_selection) => {
15473                    if new_selection.range() != selection.range() {
15474                        selected_larger_symbol = true;
15475                    }
15476                    new_selection
15477                }
15478                None => selection.clone(),
15479            })
15480            .collect::<Vec<_>>();
15481
15482        if selected_larger_symbol {
15483            self.change_selections(Default::default(), window, cx, |s| {
15484                s.select(new_selections);
15485            });
15486        }
15487    }
15488
15489    pub fn select_larger_syntax_node(
15490        &mut self,
15491        _: &SelectLargerSyntaxNode,
15492        window: &mut Window,
15493        cx: &mut Context<Self>,
15494    ) {
15495        let Some(visible_row_count) = self.visible_row_count() else {
15496            return;
15497        };
15498        let old_selections: Box<[_]> = self
15499            .selections
15500            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15501            .into();
15502        if old_selections.is_empty() {
15503            return;
15504        }
15505
15506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15507
15508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15509        let buffer = self.buffer.read(cx).snapshot(cx);
15510
15511        let mut selected_larger_node = false;
15512        let mut new_selections = old_selections
15513            .iter()
15514            .map(|selection| {
15515                let old_range = selection.start..selection.end;
15516
15517                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15518                    // manually select word at selection
15519                    if ["string_content", "inline"].contains(&node.kind()) {
15520                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15521                        // ignore if word is already selected
15522                        if !word_range.is_empty() && old_range != word_range {
15523                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15524                            // only select word if start and end point belongs to same word
15525                            if word_range == last_word_range {
15526                                selected_larger_node = true;
15527                                return Selection {
15528                                    id: selection.id,
15529                                    start: word_range.start,
15530                                    end: word_range.end,
15531                                    goal: SelectionGoal::None,
15532                                    reversed: selection.reversed,
15533                                };
15534                            }
15535                        }
15536                    }
15537                }
15538
15539                let mut new_range = old_range.clone();
15540                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15541                    new_range = range;
15542                    if !node.is_named() {
15543                        continue;
15544                    }
15545                    if !display_map.intersects_fold(new_range.start)
15546                        && !display_map.intersects_fold(new_range.end)
15547                    {
15548                        break;
15549                    }
15550                }
15551
15552                selected_larger_node |= new_range != old_range;
15553                Selection {
15554                    id: selection.id,
15555                    start: new_range.start,
15556                    end: new_range.end,
15557                    goal: SelectionGoal::None,
15558                    reversed: selection.reversed,
15559                }
15560            })
15561            .collect::<Vec<_>>();
15562
15563        if !selected_larger_node {
15564            return; // don't put this call in the history
15565        }
15566
15567        // scroll based on transformation done to the last selection created by the user
15568        let (last_old, last_new) = old_selections
15569            .last()
15570            .zip(new_selections.last().cloned())
15571            .expect("old_selections isn't empty");
15572
15573        // revert selection
15574        let is_selection_reversed = {
15575            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15576            new_selections.last_mut().expect("checked above").reversed =
15577                should_newest_selection_be_reversed;
15578            should_newest_selection_be_reversed
15579        };
15580
15581        if selected_larger_node {
15582            self.select_syntax_node_history.disable_clearing = true;
15583            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15584                s.select(new_selections.clone());
15585            });
15586            self.select_syntax_node_history.disable_clearing = false;
15587        }
15588
15589        let start_row = last_new.start.to_display_point(&display_map).row().0;
15590        let end_row = last_new.end.to_display_point(&display_map).row().0;
15591        let selection_height = end_row - start_row + 1;
15592        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15593
15594        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15595        let scroll_behavior = if fits_on_the_screen {
15596            self.request_autoscroll(Autoscroll::fit(), cx);
15597            SelectSyntaxNodeScrollBehavior::FitSelection
15598        } else if is_selection_reversed {
15599            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15600            SelectSyntaxNodeScrollBehavior::CursorTop
15601        } else {
15602            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15603            SelectSyntaxNodeScrollBehavior::CursorBottom
15604        };
15605
15606        self.select_syntax_node_history.push((
15607            old_selections,
15608            scroll_behavior,
15609            is_selection_reversed,
15610        ));
15611    }
15612
15613    pub fn select_smaller_syntax_node(
15614        &mut self,
15615        _: &SelectSmallerSyntaxNode,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) {
15619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15620
15621        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15622            self.select_syntax_node_history.pop()
15623        {
15624            if let Some(selection) = selections.last_mut() {
15625                selection.reversed = is_selection_reversed;
15626            }
15627
15628            self.select_syntax_node_history.disable_clearing = true;
15629            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15630                s.select(selections.to_vec());
15631            });
15632            self.select_syntax_node_history.disable_clearing = false;
15633
15634            match scroll_behavior {
15635                SelectSyntaxNodeScrollBehavior::CursorTop => {
15636                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15637                }
15638                SelectSyntaxNodeScrollBehavior::FitSelection => {
15639                    self.request_autoscroll(Autoscroll::fit(), cx);
15640                }
15641                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15642                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15643                }
15644            }
15645        }
15646    }
15647
15648    pub fn unwrap_syntax_node(
15649        &mut self,
15650        _: &UnwrapSyntaxNode,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) {
15654        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15655
15656        let buffer = self.buffer.read(cx).snapshot(cx);
15657        let selections = self
15658            .selections
15659            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15660            .into_iter()
15661            // subtracting the offset requires sorting
15662            .sorted_by_key(|i| i.start);
15663
15664        let full_edits = selections
15665            .into_iter()
15666            .filter_map(|selection| {
15667                let child = if selection.is_empty()
15668                    && let Some((_, ancestor_range)) =
15669                        buffer.syntax_ancestor(selection.start..selection.end)
15670                {
15671                    ancestor_range
15672                } else {
15673                    selection.range()
15674                };
15675
15676                let mut parent = child.clone();
15677                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15678                    parent = ancestor_range;
15679                    if parent.start < child.start || parent.end > child.end {
15680                        break;
15681                    }
15682                }
15683
15684                if parent == child {
15685                    return None;
15686                }
15687                let text = buffer.text_for_range(child).collect::<String>();
15688                Some((selection.id, parent, text))
15689            })
15690            .collect::<Vec<_>>();
15691        if full_edits.is_empty() {
15692            return;
15693        }
15694
15695        self.transact(window, cx, |this, window, cx| {
15696            this.buffer.update(cx, |buffer, cx| {
15697                buffer.edit(
15698                    full_edits
15699                        .iter()
15700                        .map(|(_, p, t)| (p.clone(), t.clone()))
15701                        .collect::<Vec<_>>(),
15702                    None,
15703                    cx,
15704                );
15705            });
15706            this.change_selections(Default::default(), window, cx, |s| {
15707                let mut offset = 0;
15708                let mut selections = vec![];
15709                for (id, parent, text) in full_edits {
15710                    let start = parent.start - offset;
15711                    offset += (parent.end - parent.start) - text.len();
15712                    selections.push(Selection {
15713                        id,
15714                        start,
15715                        end: start + text.len(),
15716                        reversed: false,
15717                        goal: Default::default(),
15718                    });
15719                }
15720                s.select(selections);
15721            });
15722        });
15723    }
15724
15725    pub fn select_next_syntax_node(
15726        &mut self,
15727        _: &SelectNextSyntaxNode,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) {
15731        let old_selections: Box<[_]> = self
15732            .selections
15733            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15734            .into();
15735        if old_selections.is_empty() {
15736            return;
15737        }
15738
15739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15740
15741        let buffer = self.buffer.read(cx).snapshot(cx);
15742        let mut selected_sibling = false;
15743
15744        let new_selections = old_selections
15745            .iter()
15746            .map(|selection| {
15747                let old_range = selection.start..selection.end;
15748
15749                let old_range =
15750                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15751                let excerpt = buffer.excerpt_containing(old_range.clone());
15752
15753                if let Some(mut excerpt) = excerpt
15754                    && let Some(node) = excerpt
15755                        .buffer()
15756                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15757                {
15758                    let new_range = excerpt.map_range_from_buffer(
15759                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15760                    );
15761                    selected_sibling = true;
15762                    Selection {
15763                        id: selection.id,
15764                        start: new_range.start,
15765                        end: new_range.end,
15766                        goal: SelectionGoal::None,
15767                        reversed: selection.reversed,
15768                    }
15769                } else {
15770                    selection.clone()
15771                }
15772            })
15773            .collect::<Vec<_>>();
15774
15775        if selected_sibling {
15776            self.change_selections(
15777                SelectionEffects::scroll(Autoscroll::fit()),
15778                window,
15779                cx,
15780                |s| {
15781                    s.select(new_selections);
15782                },
15783            );
15784        }
15785    }
15786
15787    pub fn select_prev_syntax_node(
15788        &mut self,
15789        _: &SelectPreviousSyntaxNode,
15790        window: &mut Window,
15791        cx: &mut Context<Self>,
15792    ) {
15793        let old_selections: Box<[_]> = self
15794            .selections
15795            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15796            .into();
15797        if old_selections.is_empty() {
15798            return;
15799        }
15800
15801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15802
15803        let buffer = self.buffer.read(cx).snapshot(cx);
15804        let mut selected_sibling = false;
15805
15806        let new_selections = old_selections
15807            .iter()
15808            .map(|selection| {
15809                let old_range = selection.start..selection.end;
15810                let old_range =
15811                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15812                let excerpt = buffer.excerpt_containing(old_range.clone());
15813
15814                if let Some(mut excerpt) = excerpt
15815                    && let Some(node) = excerpt
15816                        .buffer()
15817                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15818                {
15819                    let new_range = excerpt.map_range_from_buffer(
15820                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15821                    );
15822                    selected_sibling = true;
15823                    Selection {
15824                        id: selection.id,
15825                        start: new_range.start,
15826                        end: new_range.end,
15827                        goal: SelectionGoal::None,
15828                        reversed: selection.reversed,
15829                    }
15830                } else {
15831                    selection.clone()
15832                }
15833            })
15834            .collect::<Vec<_>>();
15835
15836        if selected_sibling {
15837            self.change_selections(
15838                SelectionEffects::scroll(Autoscroll::fit()),
15839                window,
15840                cx,
15841                |s| {
15842                    s.select(new_selections);
15843                },
15844            );
15845        }
15846    }
15847
15848    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15849        if !EditorSettings::get_global(cx).gutter.runnables {
15850            self.clear_tasks();
15851            return Task::ready(());
15852        }
15853        let project = self.project().map(Entity::downgrade);
15854        let task_sources = self.lsp_task_sources(cx);
15855        let multi_buffer = self.buffer.downgrade();
15856        cx.spawn_in(window, async move |editor, cx| {
15857            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15858            let Some(project) = project.and_then(|p| p.upgrade()) else {
15859                return;
15860            };
15861            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15862                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15863            }) else {
15864                return;
15865            };
15866
15867            let hide_runnables = project
15868                .update(cx, |project, _| project.is_via_collab())
15869                .unwrap_or(true);
15870            if hide_runnables {
15871                return;
15872            }
15873            let new_rows =
15874                cx.background_spawn({
15875                    let snapshot = display_snapshot.clone();
15876                    async move {
15877                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15878                    }
15879                })
15880                    .await;
15881            let Ok(lsp_tasks) =
15882                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15883            else {
15884                return;
15885            };
15886            let lsp_tasks = lsp_tasks.await;
15887
15888            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15889                lsp_tasks
15890                    .into_iter()
15891                    .flat_map(|(kind, tasks)| {
15892                        tasks.into_iter().filter_map(move |(location, task)| {
15893                            Some((kind.clone(), location?, task))
15894                        })
15895                    })
15896                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15897                        let buffer = location.target.buffer;
15898                        let buffer_snapshot = buffer.read(cx).snapshot();
15899                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15900                            |(excerpt_id, snapshot, _)| {
15901                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15902                                    display_snapshot
15903                                        .buffer_snapshot()
15904                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15905                                } else {
15906                                    None
15907                                }
15908                            },
15909                        );
15910                        if let Some(offset) = offset {
15911                            let task_buffer_range =
15912                                location.target.range.to_point(&buffer_snapshot);
15913                            let context_buffer_range =
15914                                task_buffer_range.to_offset(&buffer_snapshot);
15915                            let context_range = BufferOffset(context_buffer_range.start)
15916                                ..BufferOffset(context_buffer_range.end);
15917
15918                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15919                                .or_insert_with(|| RunnableTasks {
15920                                    templates: Vec::new(),
15921                                    offset,
15922                                    column: task_buffer_range.start.column,
15923                                    extra_variables: HashMap::default(),
15924                                    context_range,
15925                                })
15926                                .templates
15927                                .push((kind, task.original_task().clone()));
15928                        }
15929
15930                        acc
15931                    })
15932            }) else {
15933                return;
15934            };
15935
15936            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15937                buffer.language_settings(cx).tasks.prefer_lsp
15938            }) else {
15939                return;
15940            };
15941
15942            let rows = Self::runnable_rows(
15943                project,
15944                display_snapshot,
15945                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15946                new_rows,
15947                cx.clone(),
15948            )
15949            .await;
15950            editor
15951                .update(cx, |editor, _| {
15952                    editor.clear_tasks();
15953                    for (key, mut value) in rows {
15954                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15955                            value.templates.extend(lsp_tasks.templates);
15956                        }
15957
15958                        editor.insert_tasks(key, value);
15959                    }
15960                    for (key, value) in lsp_tasks_by_rows {
15961                        editor.insert_tasks(key, value);
15962                    }
15963                })
15964                .ok();
15965        })
15966    }
15967    fn fetch_runnable_ranges(
15968        snapshot: &DisplaySnapshot,
15969        range: Range<Anchor>,
15970    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15971        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15972    }
15973
15974    fn runnable_rows(
15975        project: Entity<Project>,
15976        snapshot: DisplaySnapshot,
15977        prefer_lsp: bool,
15978        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15979        cx: AsyncWindowContext,
15980    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15981        cx.spawn(async move |cx| {
15982            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15983            for (run_range, mut runnable) in runnable_ranges {
15984                let Some(tasks) = cx
15985                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15986                    .ok()
15987                else {
15988                    continue;
15989                };
15990                let mut tasks = tasks.await;
15991
15992                if prefer_lsp {
15993                    tasks.retain(|(task_kind, _)| {
15994                        !matches!(task_kind, TaskSourceKind::Language { .. })
15995                    });
15996                }
15997                if tasks.is_empty() {
15998                    continue;
15999                }
16000
16001                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16002                let Some(row) = snapshot
16003                    .buffer_snapshot()
16004                    .buffer_line_for_row(MultiBufferRow(point.row))
16005                    .map(|(_, range)| range.start.row)
16006                else {
16007                    continue;
16008                };
16009
16010                let context_range =
16011                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16012                runnable_rows.push((
16013                    (runnable.buffer_id, row),
16014                    RunnableTasks {
16015                        templates: tasks,
16016                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16017                        context_range,
16018                        column: point.column,
16019                        extra_variables: runnable.extra_captures,
16020                    },
16021                ));
16022            }
16023            runnable_rows
16024        })
16025    }
16026
16027    fn templates_with_tags(
16028        project: &Entity<Project>,
16029        runnable: &mut Runnable,
16030        cx: &mut App,
16031    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16032        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16033            let (worktree_id, file) = project
16034                .buffer_for_id(runnable.buffer, cx)
16035                .and_then(|buffer| buffer.read(cx).file())
16036                .map(|file| (file.worktree_id(cx), file.clone()))
16037                .unzip();
16038
16039            (
16040                project.task_store().read(cx).task_inventory().cloned(),
16041                worktree_id,
16042                file,
16043            )
16044        });
16045
16046        let tags = mem::take(&mut runnable.tags);
16047        let language = runnable.language.clone();
16048        cx.spawn(async move |cx| {
16049            let mut templates_with_tags = Vec::new();
16050            if let Some(inventory) = inventory {
16051                for RunnableTag(tag) in tags {
16052                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16053                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16054                    }) else {
16055                        return templates_with_tags;
16056                    };
16057                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16058                        move |(_, template)| {
16059                            template.tags.iter().any(|source_tag| source_tag == &tag)
16060                        },
16061                    ));
16062                }
16063            }
16064            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16065
16066            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16067                // Strongest source wins; if we have worktree tag binding, prefer that to
16068                // global and language bindings;
16069                // if we have a global binding, prefer that to language binding.
16070                let first_mismatch = templates_with_tags
16071                    .iter()
16072                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16073                if let Some(index) = first_mismatch {
16074                    templates_with_tags.truncate(index);
16075                }
16076            }
16077
16078            templates_with_tags
16079        })
16080    }
16081
16082    pub fn move_to_enclosing_bracket(
16083        &mut self,
16084        _: &MoveToEnclosingBracket,
16085        window: &mut Window,
16086        cx: &mut Context<Self>,
16087    ) {
16088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16089        self.change_selections(Default::default(), window, cx, |s| {
16090            s.move_offsets_with(|snapshot, selection| {
16091                let Some(enclosing_bracket_ranges) =
16092                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16093                else {
16094                    return;
16095                };
16096
16097                let mut best_length = usize::MAX;
16098                let mut best_inside = false;
16099                let mut best_in_bracket_range = false;
16100                let mut best_destination = None;
16101                for (open, close) in enclosing_bracket_ranges {
16102                    let close = close.to_inclusive();
16103                    let length = *close.end() - open.start;
16104                    let inside = selection.start >= open.end && selection.end <= *close.start();
16105                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16106                        || close.contains(&selection.head());
16107
16108                    // If best is next to a bracket and current isn't, skip
16109                    if !in_bracket_range && best_in_bracket_range {
16110                        continue;
16111                    }
16112
16113                    // Prefer smaller lengths unless best is inside and current isn't
16114                    if length > best_length && (best_inside || !inside) {
16115                        continue;
16116                    }
16117
16118                    best_length = length;
16119                    best_inside = inside;
16120                    best_in_bracket_range = in_bracket_range;
16121                    best_destination = Some(
16122                        if close.contains(&selection.start) && close.contains(&selection.end) {
16123                            if inside { open.end } else { open.start }
16124                        } else if inside {
16125                            *close.start()
16126                        } else {
16127                            *close.end()
16128                        },
16129                    );
16130                }
16131
16132                if let Some(destination) = best_destination {
16133                    selection.collapse_to(destination, SelectionGoal::None);
16134                }
16135            })
16136        });
16137    }
16138
16139    pub fn undo_selection(
16140        &mut self,
16141        _: &UndoSelection,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) {
16145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16146        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16147            self.selection_history.mode = SelectionHistoryMode::Undoing;
16148            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16149                this.end_selection(window, cx);
16150                this.change_selections(
16151                    SelectionEffects::scroll(Autoscroll::newest()),
16152                    window,
16153                    cx,
16154                    |s| s.select_anchors(entry.selections.to_vec()),
16155                );
16156            });
16157            self.selection_history.mode = SelectionHistoryMode::Normal;
16158
16159            self.select_next_state = entry.select_next_state;
16160            self.select_prev_state = entry.select_prev_state;
16161            self.add_selections_state = entry.add_selections_state;
16162        }
16163    }
16164
16165    pub fn redo_selection(
16166        &mut self,
16167        _: &RedoSelection,
16168        window: &mut Window,
16169        cx: &mut Context<Self>,
16170    ) {
16171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16172        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16173            self.selection_history.mode = SelectionHistoryMode::Redoing;
16174            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16175                this.end_selection(window, cx);
16176                this.change_selections(
16177                    SelectionEffects::scroll(Autoscroll::newest()),
16178                    window,
16179                    cx,
16180                    |s| s.select_anchors(entry.selections.to_vec()),
16181                );
16182            });
16183            self.selection_history.mode = SelectionHistoryMode::Normal;
16184
16185            self.select_next_state = entry.select_next_state;
16186            self.select_prev_state = entry.select_prev_state;
16187            self.add_selections_state = entry.add_selections_state;
16188        }
16189    }
16190
16191    pub fn expand_excerpts(
16192        &mut self,
16193        action: &ExpandExcerpts,
16194        _: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) {
16197        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16198    }
16199
16200    pub fn expand_excerpts_down(
16201        &mut self,
16202        action: &ExpandExcerptsDown,
16203        _: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) {
16206        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16207    }
16208
16209    pub fn expand_excerpts_up(
16210        &mut self,
16211        action: &ExpandExcerptsUp,
16212        _: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) {
16215        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16216    }
16217
16218    pub fn expand_excerpts_for_direction(
16219        &mut self,
16220        lines: u32,
16221        direction: ExpandExcerptDirection,
16222
16223        cx: &mut Context<Self>,
16224    ) {
16225        let selections = self.selections.disjoint_anchors_arc();
16226
16227        let lines = if lines == 0 {
16228            EditorSettings::get_global(cx).expand_excerpt_lines
16229        } else {
16230            lines
16231        };
16232
16233        self.buffer.update(cx, |buffer, cx| {
16234            let snapshot = buffer.snapshot(cx);
16235            let mut excerpt_ids = selections
16236                .iter()
16237                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16238                .collect::<Vec<_>>();
16239            excerpt_ids.sort();
16240            excerpt_ids.dedup();
16241            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16242        })
16243    }
16244
16245    pub fn expand_excerpt(
16246        &mut self,
16247        excerpt: ExcerptId,
16248        direction: ExpandExcerptDirection,
16249        window: &mut Window,
16250        cx: &mut Context<Self>,
16251    ) {
16252        let current_scroll_position = self.scroll_position(cx);
16253        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16254        let mut scroll = None;
16255
16256        if direction == ExpandExcerptDirection::Down {
16257            let multi_buffer = self.buffer.read(cx);
16258            let snapshot = multi_buffer.snapshot(cx);
16259            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16260                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16261                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16262            {
16263                let buffer_snapshot = buffer.read(cx).snapshot();
16264                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16265                let last_row = buffer_snapshot.max_point().row;
16266                let lines_below = last_row.saturating_sub(excerpt_end_row);
16267                if lines_below >= lines_to_expand {
16268                    scroll = Some(
16269                        current_scroll_position
16270                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16271                    );
16272                }
16273            }
16274        }
16275        if direction == ExpandExcerptDirection::Up
16276            && self
16277                .buffer
16278                .read(cx)
16279                .snapshot(cx)
16280                .excerpt_before(excerpt)
16281                .is_none()
16282        {
16283            scroll = Some(current_scroll_position);
16284        }
16285
16286        self.buffer.update(cx, |buffer, cx| {
16287            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16288        });
16289
16290        if let Some(new_scroll_position) = scroll {
16291            self.set_scroll_position(new_scroll_position, window, cx);
16292        }
16293    }
16294
16295    pub fn go_to_singleton_buffer_point(
16296        &mut self,
16297        point: Point,
16298        window: &mut Window,
16299        cx: &mut Context<Self>,
16300    ) {
16301        self.go_to_singleton_buffer_range(point..point, window, cx);
16302    }
16303
16304    pub fn go_to_singleton_buffer_range(
16305        &mut self,
16306        range: Range<Point>,
16307        window: &mut Window,
16308        cx: &mut Context<Self>,
16309    ) {
16310        let multibuffer = self.buffer().read(cx);
16311        let Some(buffer) = multibuffer.as_singleton() else {
16312            return;
16313        };
16314        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16315            return;
16316        };
16317        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16318            return;
16319        };
16320        self.change_selections(
16321            SelectionEffects::default().nav_history(true),
16322            window,
16323            cx,
16324            |s| s.select_anchor_ranges([start..end]),
16325        );
16326    }
16327
16328    pub fn go_to_diagnostic(
16329        &mut self,
16330        action: &GoToDiagnostic,
16331        window: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) {
16334        if !self.diagnostics_enabled() {
16335            return;
16336        }
16337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16338        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16339    }
16340
16341    pub fn go_to_prev_diagnostic(
16342        &mut self,
16343        action: &GoToPreviousDiagnostic,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        if !self.diagnostics_enabled() {
16348            return;
16349        }
16350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16351        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16352    }
16353
16354    pub fn go_to_diagnostic_impl(
16355        &mut self,
16356        direction: Direction,
16357        severity: GoToDiagnosticSeverityFilter,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) {
16361        let buffer = self.buffer.read(cx).snapshot(cx);
16362        let selection = self
16363            .selections
16364            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16365
16366        let mut active_group_id = None;
16367        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16368            && active_group.active_range.start.to_offset(&buffer) == selection.start
16369        {
16370            active_group_id = Some(active_group.group_id);
16371        }
16372
16373        fn filtered<'a>(
16374            severity: GoToDiagnosticSeverityFilter,
16375            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16376        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16377            diagnostics
16378                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16379                .filter(|entry| entry.range.start != entry.range.end)
16380                .filter(|entry| !entry.diagnostic.is_unnecessary)
16381        }
16382
16383        let before = filtered(
16384            severity,
16385            buffer
16386                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16387                .filter(|entry| entry.range.start <= selection.start),
16388        );
16389        let after = filtered(
16390            severity,
16391            buffer
16392                .diagnostics_in_range(selection.start..buffer.len())
16393                .filter(|entry| entry.range.start >= selection.start),
16394        );
16395
16396        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16397        if direction == Direction::Prev {
16398            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16399            {
16400                for diagnostic in prev_diagnostics.into_iter().rev() {
16401                    if diagnostic.range.start != selection.start
16402                        || active_group_id
16403                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16404                    {
16405                        found = Some(diagnostic);
16406                        break 'outer;
16407                    }
16408                }
16409            }
16410        } else {
16411            for diagnostic in after.chain(before) {
16412                if diagnostic.range.start != selection.start
16413                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16414                {
16415                    found = Some(diagnostic);
16416                    break;
16417                }
16418            }
16419        }
16420        let Some(next_diagnostic) = found else {
16421            return;
16422        };
16423
16424        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16425        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16426            return;
16427        };
16428        let snapshot = self.snapshot(window, cx);
16429        if snapshot.intersects_fold(next_diagnostic.range.start) {
16430            self.unfold_ranges(
16431                std::slice::from_ref(&next_diagnostic.range),
16432                true,
16433                false,
16434                cx,
16435            );
16436        }
16437        self.change_selections(Default::default(), window, cx, |s| {
16438            s.select_ranges(vec![
16439                next_diagnostic.range.start..next_diagnostic.range.start,
16440            ])
16441        });
16442        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16443        self.refresh_edit_prediction(false, true, window, cx);
16444    }
16445
16446    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16448        let snapshot = self.snapshot(window, cx);
16449        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16450        self.go_to_hunk_before_or_after_position(
16451            &snapshot,
16452            selection.head(),
16453            Direction::Next,
16454            window,
16455            cx,
16456        );
16457    }
16458
16459    pub fn go_to_hunk_before_or_after_position(
16460        &mut self,
16461        snapshot: &EditorSnapshot,
16462        position: Point,
16463        direction: Direction,
16464        window: &mut Window,
16465        cx: &mut Context<Editor>,
16466    ) {
16467        let row = if direction == Direction::Next {
16468            self.hunk_after_position(snapshot, position)
16469                .map(|hunk| hunk.row_range.start)
16470        } else {
16471            self.hunk_before_position(snapshot, position)
16472        };
16473
16474        if let Some(row) = row {
16475            let destination = Point::new(row.0, 0);
16476            let autoscroll = Autoscroll::center();
16477
16478            self.unfold_ranges(&[destination..destination], false, false, cx);
16479            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16480                s.select_ranges([destination..destination]);
16481            });
16482        }
16483    }
16484
16485    fn hunk_after_position(
16486        &mut self,
16487        snapshot: &EditorSnapshot,
16488        position: Point,
16489    ) -> Option<MultiBufferDiffHunk> {
16490        snapshot
16491            .buffer_snapshot()
16492            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16493            .find(|hunk| hunk.row_range.start.0 > position.row)
16494            .or_else(|| {
16495                snapshot
16496                    .buffer_snapshot()
16497                    .diff_hunks_in_range(Point::zero()..position)
16498                    .find(|hunk| hunk.row_range.end.0 < position.row)
16499            })
16500    }
16501
16502    fn go_to_prev_hunk(
16503        &mut self,
16504        _: &GoToPreviousHunk,
16505        window: &mut Window,
16506        cx: &mut Context<Self>,
16507    ) {
16508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16509        let snapshot = self.snapshot(window, cx);
16510        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16511        self.go_to_hunk_before_or_after_position(
16512            &snapshot,
16513            selection.head(),
16514            Direction::Prev,
16515            window,
16516            cx,
16517        );
16518    }
16519
16520    fn hunk_before_position(
16521        &mut self,
16522        snapshot: &EditorSnapshot,
16523        position: Point,
16524    ) -> Option<MultiBufferRow> {
16525        snapshot
16526            .buffer_snapshot()
16527            .diff_hunk_before(position)
16528            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16529    }
16530
16531    fn go_to_next_change(
16532        &mut self,
16533        _: &GoToNextChange,
16534        window: &mut Window,
16535        cx: &mut Context<Self>,
16536    ) {
16537        if let Some(selections) = self
16538            .change_list
16539            .next_change(1, Direction::Next)
16540            .map(|s| s.to_vec())
16541        {
16542            self.change_selections(Default::default(), window, cx, |s| {
16543                let map = s.display_snapshot();
16544                s.select_display_ranges(selections.iter().map(|a| {
16545                    let point = a.to_display_point(&map);
16546                    point..point
16547                }))
16548            })
16549        }
16550    }
16551
16552    fn go_to_previous_change(
16553        &mut self,
16554        _: &GoToPreviousChange,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) {
16558        if let Some(selections) = self
16559            .change_list
16560            .next_change(1, Direction::Prev)
16561            .map(|s| s.to_vec())
16562        {
16563            self.change_selections(Default::default(), window, cx, |s| {
16564                let map = s.display_snapshot();
16565                s.select_display_ranges(selections.iter().map(|a| {
16566                    let point = a.to_display_point(&map);
16567                    point..point
16568                }))
16569            })
16570        }
16571    }
16572
16573    pub fn go_to_next_document_highlight(
16574        &mut self,
16575        _: &GoToNextDocumentHighlight,
16576        window: &mut Window,
16577        cx: &mut Context<Self>,
16578    ) {
16579        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16580    }
16581
16582    pub fn go_to_prev_document_highlight(
16583        &mut self,
16584        _: &GoToPreviousDocumentHighlight,
16585        window: &mut Window,
16586        cx: &mut Context<Self>,
16587    ) {
16588        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16589    }
16590
16591    pub fn go_to_document_highlight_before_or_after_position(
16592        &mut self,
16593        direction: Direction,
16594        window: &mut Window,
16595        cx: &mut Context<Editor>,
16596    ) {
16597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16598        let snapshot = self.snapshot(window, cx);
16599        let buffer = &snapshot.buffer_snapshot();
16600        let position = self
16601            .selections
16602            .newest::<Point>(&snapshot.display_snapshot)
16603            .head();
16604        let anchor_position = buffer.anchor_after(position);
16605
16606        // Get all document highlights (both read and write)
16607        let mut all_highlights = Vec::new();
16608
16609        if let Some((_, read_highlights)) = self
16610            .background_highlights
16611            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16612        {
16613            all_highlights.extend(read_highlights.iter());
16614        }
16615
16616        if let Some((_, write_highlights)) = self
16617            .background_highlights
16618            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16619        {
16620            all_highlights.extend(write_highlights.iter());
16621        }
16622
16623        if all_highlights.is_empty() {
16624            return;
16625        }
16626
16627        // Sort highlights by position
16628        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16629
16630        let target_highlight = match direction {
16631            Direction::Next => {
16632                // Find the first highlight after the current position
16633                all_highlights
16634                    .iter()
16635                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16636            }
16637            Direction::Prev => {
16638                // Find the last highlight before the current position
16639                all_highlights
16640                    .iter()
16641                    .rev()
16642                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16643            }
16644        };
16645
16646        if let Some(highlight) = target_highlight {
16647            let destination = highlight.start.to_point(buffer);
16648            let autoscroll = Autoscroll::center();
16649
16650            self.unfold_ranges(&[destination..destination], false, false, cx);
16651            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16652                s.select_ranges([destination..destination]);
16653            });
16654        }
16655    }
16656
16657    fn go_to_line<T: 'static>(
16658        &mut self,
16659        position: Anchor,
16660        highlight_color: Option<Hsla>,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        let snapshot = self.snapshot(window, cx).display_snapshot;
16665        let position = position.to_point(&snapshot.buffer_snapshot());
16666        let start = snapshot
16667            .buffer_snapshot()
16668            .clip_point(Point::new(position.row, 0), Bias::Left);
16669        let end = start + Point::new(1, 0);
16670        let start = snapshot.buffer_snapshot().anchor_before(start);
16671        let end = snapshot.buffer_snapshot().anchor_before(end);
16672
16673        self.highlight_rows::<T>(
16674            start..end,
16675            highlight_color
16676                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16677            Default::default(),
16678            cx,
16679        );
16680
16681        if self.buffer.read(cx).is_singleton() {
16682            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16683        }
16684    }
16685
16686    pub fn go_to_definition(
16687        &mut self,
16688        _: &GoToDefinition,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) -> Task<Result<Navigated>> {
16692        let definition =
16693            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16694        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16695        cx.spawn_in(window, async move |editor, cx| {
16696            if definition.await? == Navigated::Yes {
16697                return Ok(Navigated::Yes);
16698            }
16699            match fallback_strategy {
16700                GoToDefinitionFallback::None => Ok(Navigated::No),
16701                GoToDefinitionFallback::FindAllReferences => {
16702                    match editor.update_in(cx, |editor, window, cx| {
16703                        editor.find_all_references(&FindAllReferences, window, cx)
16704                    })? {
16705                        Some(references) => references.await,
16706                        None => Ok(Navigated::No),
16707                    }
16708                }
16709            }
16710        })
16711    }
16712
16713    pub fn go_to_declaration(
16714        &mut self,
16715        _: &GoToDeclaration,
16716        window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) -> Task<Result<Navigated>> {
16719        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16720    }
16721
16722    pub fn go_to_declaration_split(
16723        &mut self,
16724        _: &GoToDeclaration,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) -> Task<Result<Navigated>> {
16728        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16729    }
16730
16731    pub fn go_to_implementation(
16732        &mut self,
16733        _: &GoToImplementation,
16734        window: &mut Window,
16735        cx: &mut Context<Self>,
16736    ) -> Task<Result<Navigated>> {
16737        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16738    }
16739
16740    pub fn go_to_implementation_split(
16741        &mut self,
16742        _: &GoToImplementationSplit,
16743        window: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) -> Task<Result<Navigated>> {
16746        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16747    }
16748
16749    pub fn go_to_type_definition(
16750        &mut self,
16751        _: &GoToTypeDefinition,
16752        window: &mut Window,
16753        cx: &mut Context<Self>,
16754    ) -> Task<Result<Navigated>> {
16755        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16756    }
16757
16758    pub fn go_to_definition_split(
16759        &mut self,
16760        _: &GoToDefinitionSplit,
16761        window: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) -> Task<Result<Navigated>> {
16764        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16765    }
16766
16767    pub fn go_to_type_definition_split(
16768        &mut self,
16769        _: &GoToTypeDefinitionSplit,
16770        window: &mut Window,
16771        cx: &mut Context<Self>,
16772    ) -> Task<Result<Navigated>> {
16773        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16774    }
16775
16776    fn go_to_definition_of_kind(
16777        &mut self,
16778        kind: GotoDefinitionKind,
16779        split: bool,
16780        window: &mut Window,
16781        cx: &mut Context<Self>,
16782    ) -> Task<Result<Navigated>> {
16783        let Some(provider) = self.semantics_provider.clone() else {
16784            return Task::ready(Ok(Navigated::No));
16785        };
16786        let head = self
16787            .selections
16788            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16789            .head();
16790        let buffer = self.buffer.read(cx);
16791        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16792            return Task::ready(Ok(Navigated::No));
16793        };
16794        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16795            return Task::ready(Ok(Navigated::No));
16796        };
16797
16798        cx.spawn_in(window, async move |editor, cx| {
16799            let Some(definitions) = definitions.await? else {
16800                return Ok(Navigated::No);
16801            };
16802            let navigated = editor
16803                .update_in(cx, |editor, window, cx| {
16804                    editor.navigate_to_hover_links(
16805                        Some(kind),
16806                        definitions
16807                            .into_iter()
16808                            .filter(|location| {
16809                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16810                            })
16811                            .map(HoverLink::Text)
16812                            .collect::<Vec<_>>(),
16813                        split,
16814                        window,
16815                        cx,
16816                    )
16817                })?
16818                .await?;
16819            anyhow::Ok(navigated)
16820        })
16821    }
16822
16823    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16824        let selection = self.selections.newest_anchor();
16825        let head = selection.head();
16826        let tail = selection.tail();
16827
16828        let Some((buffer, start_position)) =
16829            self.buffer.read(cx).text_anchor_for_position(head, cx)
16830        else {
16831            return;
16832        };
16833
16834        let end_position = if head != tail {
16835            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16836                return;
16837            };
16838            Some(pos)
16839        } else {
16840            None
16841        };
16842
16843        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16844            let url = if let Some(end_pos) = end_position {
16845                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16846            } else {
16847                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16848            };
16849
16850            if let Some(url) = url {
16851                cx.update(|window, cx| {
16852                    if parse_zed_link(&url, cx).is_some() {
16853                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16854                    } else {
16855                        cx.open_url(&url);
16856                    }
16857                })?;
16858            }
16859
16860            anyhow::Ok(())
16861        });
16862
16863        url_finder.detach();
16864    }
16865
16866    pub fn open_selected_filename(
16867        &mut self,
16868        _: &OpenSelectedFilename,
16869        window: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        let Some(workspace) = self.workspace() else {
16873            return;
16874        };
16875
16876        let position = self.selections.newest_anchor().head();
16877
16878        let Some((buffer, buffer_position)) =
16879            self.buffer.read(cx).text_anchor_for_position(position, cx)
16880        else {
16881            return;
16882        };
16883
16884        let project = self.project.clone();
16885
16886        cx.spawn_in(window, async move |_, cx| {
16887            let result = find_file(&buffer, project, buffer_position, cx).await;
16888
16889            if let Some((_, path)) = result {
16890                workspace
16891                    .update_in(cx, |workspace, window, cx| {
16892                        workspace.open_resolved_path(path, window, cx)
16893                    })?
16894                    .await?;
16895            }
16896            anyhow::Ok(())
16897        })
16898        .detach();
16899    }
16900
16901    pub(crate) fn navigate_to_hover_links(
16902        &mut self,
16903        kind: Option<GotoDefinitionKind>,
16904        definitions: Vec<HoverLink>,
16905        split: bool,
16906        window: &mut Window,
16907        cx: &mut Context<Editor>,
16908    ) -> Task<Result<Navigated>> {
16909        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16910        let mut first_url_or_file = None;
16911        let definitions: Vec<_> = definitions
16912            .into_iter()
16913            .filter_map(|def| match def {
16914                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16915                HoverLink::InlayHint(lsp_location, server_id) => {
16916                    let computation =
16917                        self.compute_target_location(lsp_location, server_id, window, cx);
16918                    Some(cx.background_spawn(computation))
16919                }
16920                HoverLink::Url(url) => {
16921                    first_url_or_file = Some(Either::Left(url));
16922                    None
16923                }
16924                HoverLink::File(path) => {
16925                    first_url_or_file = Some(Either::Right(path));
16926                    None
16927                }
16928            })
16929            .collect();
16930
16931        let workspace = self.workspace();
16932
16933        cx.spawn_in(window, async move |editor, cx| {
16934            let locations: Vec<Location> = future::join_all(definitions)
16935                .await
16936                .into_iter()
16937                .filter_map(|location| location.transpose())
16938                .collect::<Result<_>>()
16939                .context("location tasks")?;
16940            let mut locations = cx.update(|_, cx| {
16941                locations
16942                    .into_iter()
16943                    .map(|location| {
16944                        let buffer = location.buffer.read(cx);
16945                        (location.buffer, location.range.to_point(buffer))
16946                    })
16947                    .into_group_map()
16948            })?;
16949            let mut num_locations = 0;
16950            for ranges in locations.values_mut() {
16951                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16952                ranges.dedup();
16953                num_locations += ranges.len();
16954            }
16955
16956            if num_locations > 1 {
16957                let Some(workspace) = workspace else {
16958                    return Ok(Navigated::No);
16959                };
16960
16961                let tab_kind = match kind {
16962                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16963                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16964                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16965                    Some(GotoDefinitionKind::Type) => "Types",
16966                };
16967                let title = editor
16968                    .update_in(cx, |_, _, cx| {
16969                        let target = locations
16970                            .iter()
16971                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16972                            .map(|(buffer, location)| {
16973                                buffer
16974                                    .read(cx)
16975                                    .text_for_range(location.clone())
16976                                    .collect::<String>()
16977                            })
16978                            .filter(|text| !text.contains('\n'))
16979                            .unique()
16980                            .take(3)
16981                            .join(", ");
16982                        if target.is_empty() {
16983                            tab_kind.to_owned()
16984                        } else {
16985                            format!("{tab_kind} for {target}")
16986                        }
16987                    })
16988                    .context("buffer title")?;
16989
16990                let opened = workspace
16991                    .update_in(cx, |workspace, window, cx| {
16992                        Self::open_locations_in_multibuffer(
16993                            workspace,
16994                            locations,
16995                            title,
16996                            split,
16997                            MultibufferSelectionMode::First,
16998                            window,
16999                            cx,
17000                        )
17001                    })
17002                    .is_ok();
17003
17004                anyhow::Ok(Navigated::from_bool(opened))
17005            } else if num_locations == 0 {
17006                // If there is one url or file, open it directly
17007                match first_url_or_file {
17008                    Some(Either::Left(url)) => {
17009                        cx.update(|_, cx| cx.open_url(&url))?;
17010                        Ok(Navigated::Yes)
17011                    }
17012                    Some(Either::Right(path)) => {
17013                        let Some(workspace) = workspace else {
17014                            return Ok(Navigated::No);
17015                        };
17016
17017                        workspace
17018                            .update_in(cx, |workspace, window, cx| {
17019                                workspace.open_resolved_path(path, window, cx)
17020                            })?
17021                            .await?;
17022                        Ok(Navigated::Yes)
17023                    }
17024                    None => Ok(Navigated::No),
17025                }
17026            } else {
17027                let Some(workspace) = workspace else {
17028                    return Ok(Navigated::No);
17029                };
17030
17031                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17032                let target_range = target_ranges.first().unwrap().clone();
17033
17034                editor.update_in(cx, |editor, window, cx| {
17035                    let range = target_range.to_point(target_buffer.read(cx));
17036                    let range = editor.range_for_match(&range);
17037                    let range = collapse_multiline_range(range);
17038
17039                    if !split
17040                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17041                    {
17042                        editor.go_to_singleton_buffer_range(range, window, cx);
17043                    } else {
17044                        let pane = workspace.read(cx).active_pane().clone();
17045                        window.defer(cx, move |window, cx| {
17046                            let target_editor: Entity<Self> =
17047                                workspace.update(cx, |workspace, cx| {
17048                                    let pane = if split {
17049                                        workspace.adjacent_pane(window, cx)
17050                                    } else {
17051                                        workspace.active_pane().clone()
17052                                    };
17053
17054                                    workspace.open_project_item(
17055                                        pane,
17056                                        target_buffer.clone(),
17057                                        true,
17058                                        true,
17059                                        window,
17060                                        cx,
17061                                    )
17062                                });
17063                            target_editor.update(cx, |target_editor, cx| {
17064                                // When selecting a definition in a different buffer, disable the nav history
17065                                // to avoid creating a history entry at the previous cursor location.
17066                                pane.update(cx, |pane, _| pane.disable_history());
17067                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17068                                pane.update(cx, |pane, _| pane.enable_history());
17069                            });
17070                        });
17071                    }
17072                    Navigated::Yes
17073                })
17074            }
17075        })
17076    }
17077
17078    fn compute_target_location(
17079        &self,
17080        lsp_location: lsp::Location,
17081        server_id: LanguageServerId,
17082        window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) -> Task<anyhow::Result<Option<Location>>> {
17085        let Some(project) = self.project.clone() else {
17086            return Task::ready(Ok(None));
17087        };
17088
17089        cx.spawn_in(window, async move |editor, cx| {
17090            let location_task = editor.update(cx, |_, cx| {
17091                project.update(cx, |project, cx| {
17092                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17093                })
17094            })?;
17095            let location = Some({
17096                let target_buffer_handle = location_task.await.context("open local buffer")?;
17097                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17098                    let target_start = target_buffer
17099                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17100                    let target_end = target_buffer
17101                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17102                    target_buffer.anchor_after(target_start)
17103                        ..target_buffer.anchor_before(target_end)
17104                })?;
17105                Location {
17106                    buffer: target_buffer_handle,
17107                    range,
17108                }
17109            });
17110            Ok(location)
17111        })
17112    }
17113
17114    fn go_to_next_reference(
17115        &mut self,
17116        _: &GoToNextReference,
17117        window: &mut Window,
17118        cx: &mut Context<Self>,
17119    ) {
17120        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17121        if let Some(task) = task {
17122            task.detach();
17123        };
17124    }
17125
17126    fn go_to_prev_reference(
17127        &mut self,
17128        _: &GoToPreviousReference,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) {
17132        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17133        if let Some(task) = task {
17134            task.detach();
17135        };
17136    }
17137
17138    pub fn go_to_reference_before_or_after_position(
17139        &mut self,
17140        direction: Direction,
17141        count: usize,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Option<Task<Result<()>>> {
17145        let selection = self.selections.newest_anchor();
17146        let head = selection.head();
17147
17148        let multi_buffer = self.buffer.read(cx);
17149
17150        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17151        let workspace = self.workspace()?;
17152        let project = workspace.read(cx).project().clone();
17153        let references =
17154            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17155        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17156            let Some(locations) = references.await? else {
17157                return Ok(());
17158            };
17159
17160            if locations.is_empty() {
17161                // totally normal - the cursor may be on something which is not
17162                // a symbol (e.g. a keyword)
17163                log::info!("no references found under cursor");
17164                return Ok(());
17165            }
17166
17167            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17168
17169            let (locations, current_location_index) =
17170                multi_buffer.update(cx, |multi_buffer, cx| {
17171                    let mut locations = locations
17172                        .into_iter()
17173                        .filter_map(|loc| {
17174                            let start = multi_buffer.buffer_anchor_to_anchor(
17175                                &loc.buffer,
17176                                loc.range.start,
17177                                cx,
17178                            )?;
17179                            let end = multi_buffer.buffer_anchor_to_anchor(
17180                                &loc.buffer,
17181                                loc.range.end,
17182                                cx,
17183                            )?;
17184                            Some(start..end)
17185                        })
17186                        .collect::<Vec<_>>();
17187
17188                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17189                    // There is an O(n) implementation, but given this list will be
17190                    // small (usually <100 items), the extra O(log(n)) factor isn't
17191                    // worth the (surprisingly large amount of) extra complexity.
17192                    locations
17193                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17194
17195                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17196
17197                    let current_location_index = locations.iter().position(|loc| {
17198                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17199                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17200                    });
17201
17202                    (locations, current_location_index)
17203                })?;
17204
17205            let Some(current_location_index) = current_location_index else {
17206                // This indicates something has gone wrong, because we already
17207                // handle the "no references" case above
17208                log::error!(
17209                    "failed to find current reference under cursor. Total references: {}",
17210                    locations.len()
17211                );
17212                return Ok(());
17213            };
17214
17215            let destination_location_index = match direction {
17216                Direction::Next => (current_location_index + count) % locations.len(),
17217                Direction::Prev => {
17218                    (current_location_index + locations.len() - count % locations.len())
17219                        % locations.len()
17220                }
17221            };
17222
17223            // TODO(cameron): is this needed?
17224            // the thinking is to avoid "jumping to the current location" (avoid
17225            // polluting "jumplist" in vim terms)
17226            if current_location_index == destination_location_index {
17227                return Ok(());
17228            }
17229
17230            let Range { start, end } = locations[destination_location_index];
17231
17232            editor.update_in(cx, |editor, window, cx| {
17233                let effects = SelectionEffects::default();
17234
17235                editor.unfold_ranges(&[start..end], false, false, cx);
17236                editor.change_selections(effects, window, cx, |s| {
17237                    s.select_ranges([start..start]);
17238                });
17239            })?;
17240
17241            Ok(())
17242        }))
17243    }
17244
17245    pub fn find_all_references(
17246        &mut self,
17247        _: &FindAllReferences,
17248        window: &mut Window,
17249        cx: &mut Context<Self>,
17250    ) -> Option<Task<Result<Navigated>>> {
17251        let selection = self
17252            .selections
17253            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17254        let multi_buffer = self.buffer.read(cx);
17255        let head = selection.head();
17256
17257        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17258        let head_anchor = multi_buffer_snapshot.anchor_at(
17259            head,
17260            if head < selection.tail() {
17261                Bias::Right
17262            } else {
17263                Bias::Left
17264            },
17265        );
17266
17267        match self
17268            .find_all_references_task_sources
17269            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17270        {
17271            Ok(_) => {
17272                log::info!(
17273                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17274                );
17275                return None;
17276            }
17277            Err(i) => {
17278                self.find_all_references_task_sources.insert(i, head_anchor);
17279            }
17280        }
17281
17282        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17283        let workspace = self.workspace()?;
17284        let project = workspace.read(cx).project().clone();
17285        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17286        Some(cx.spawn_in(window, async move |editor, cx| {
17287            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17288                if let Ok(i) = editor
17289                    .find_all_references_task_sources
17290                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17291                {
17292                    editor.find_all_references_task_sources.remove(i);
17293                }
17294            });
17295
17296            let Some(locations) = references.await? else {
17297                return anyhow::Ok(Navigated::No);
17298            };
17299            let mut locations = cx.update(|_, cx| {
17300                locations
17301                    .into_iter()
17302                    .map(|location| {
17303                        let buffer = location.buffer.read(cx);
17304                        (location.buffer, location.range.to_point(buffer))
17305                    })
17306                    .into_group_map()
17307            })?;
17308            if locations.is_empty() {
17309                return anyhow::Ok(Navigated::No);
17310            }
17311            for ranges in locations.values_mut() {
17312                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17313                ranges.dedup();
17314            }
17315
17316            workspace.update_in(cx, |workspace, window, cx| {
17317                let target = locations
17318                    .iter()
17319                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17320                    .map(|(buffer, location)| {
17321                        buffer
17322                            .read(cx)
17323                            .text_for_range(location.clone())
17324                            .collect::<String>()
17325                    })
17326                    .filter(|text| !text.contains('\n'))
17327                    .unique()
17328                    .take(3)
17329                    .join(", ");
17330                let title = if target.is_empty() {
17331                    "References".to_owned()
17332                } else {
17333                    format!("References to {target}")
17334                };
17335                Self::open_locations_in_multibuffer(
17336                    workspace,
17337                    locations,
17338                    title,
17339                    false,
17340                    MultibufferSelectionMode::First,
17341                    window,
17342                    cx,
17343                );
17344                Navigated::Yes
17345            })
17346        }))
17347    }
17348
17349    /// Opens a multibuffer with the given project locations in it
17350    pub fn open_locations_in_multibuffer(
17351        workspace: &mut Workspace,
17352        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17353        title: String,
17354        split: bool,
17355        multibuffer_selection_mode: MultibufferSelectionMode,
17356        window: &mut Window,
17357        cx: &mut Context<Workspace>,
17358    ) {
17359        if locations.is_empty() {
17360            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17361            return;
17362        }
17363
17364        let capability = workspace.project().read(cx).capability();
17365        let mut ranges = <Vec<Range<Anchor>>>::new();
17366
17367        // a key to find existing multibuffer editors with the same set of locations
17368        // to prevent us from opening more and more multibuffer tabs for searches and the like
17369        let mut key = (title.clone(), vec![]);
17370        let excerpt_buffer = cx.new(|cx| {
17371            let key = &mut key.1;
17372            let mut multibuffer = MultiBuffer::new(capability);
17373            for (buffer, mut ranges_for_buffer) in locations {
17374                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17375                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17376                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17377                    PathKey::for_buffer(&buffer, cx),
17378                    buffer.clone(),
17379                    ranges_for_buffer,
17380                    multibuffer_context_lines(cx),
17381                    cx,
17382                );
17383                ranges.extend(new_ranges)
17384            }
17385
17386            multibuffer.with_title(title)
17387        });
17388        let existing = workspace.active_pane().update(cx, |pane, cx| {
17389            pane.items()
17390                .filter_map(|item| item.downcast::<Editor>())
17391                .find(|editor| {
17392                    editor
17393                        .read(cx)
17394                        .lookup_key
17395                        .as_ref()
17396                        .and_then(|it| {
17397                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17398                        })
17399                        .is_some_and(|it| *it == key)
17400                })
17401        });
17402        let editor = existing.unwrap_or_else(|| {
17403            cx.new(|cx| {
17404                let mut editor = Editor::for_multibuffer(
17405                    excerpt_buffer,
17406                    Some(workspace.project().clone()),
17407                    window,
17408                    cx,
17409                );
17410                editor.lookup_key = Some(Box::new(key));
17411                editor
17412            })
17413        });
17414        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17415            MultibufferSelectionMode::First => {
17416                if let Some(first_range) = ranges.first() {
17417                    editor.change_selections(
17418                        SelectionEffects::no_scroll(),
17419                        window,
17420                        cx,
17421                        |selections| {
17422                            selections.clear_disjoint();
17423                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17424                        },
17425                    );
17426                }
17427                editor.highlight_background::<Self>(
17428                    &ranges,
17429                    |theme| theme.colors().editor_highlighted_line_background,
17430                    cx,
17431                );
17432            }
17433            MultibufferSelectionMode::All => {
17434                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17435                    selections.clear_disjoint();
17436                    selections.select_anchor_ranges(ranges);
17437                });
17438            }
17439        });
17440
17441        let item = Box::new(editor);
17442        let item_id = item.item_id();
17443
17444        if split {
17445            let pane = workspace.adjacent_pane(window, cx);
17446            workspace.add_item(pane, item, None, true, true, window, cx);
17447        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17448            let (preview_item_id, preview_item_idx) =
17449                workspace.active_pane().read_with(cx, |pane, _| {
17450                    (pane.preview_item_id(), pane.preview_item_idx())
17451                });
17452
17453            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17454
17455            if let Some(preview_item_id) = preview_item_id {
17456                workspace.active_pane().update(cx, |pane, cx| {
17457                    pane.remove_item(preview_item_id, false, false, window, cx);
17458                });
17459            }
17460        } else {
17461            workspace.add_item_to_active_pane(item, None, true, window, cx);
17462        }
17463        workspace.active_pane().update(cx, |pane, cx| {
17464            pane.set_preview_item_id(Some(item_id), cx);
17465        });
17466    }
17467
17468    pub fn rename(
17469        &mut self,
17470        _: &Rename,
17471        window: &mut Window,
17472        cx: &mut Context<Self>,
17473    ) -> Option<Task<Result<()>>> {
17474        use language::ToOffset as _;
17475
17476        let provider = self.semantics_provider.clone()?;
17477        let selection = self.selections.newest_anchor().clone();
17478        let (cursor_buffer, cursor_buffer_position) = self
17479            .buffer
17480            .read(cx)
17481            .text_anchor_for_position(selection.head(), cx)?;
17482        let (tail_buffer, cursor_buffer_position_end) = self
17483            .buffer
17484            .read(cx)
17485            .text_anchor_for_position(selection.tail(), cx)?;
17486        if tail_buffer != cursor_buffer {
17487            return None;
17488        }
17489
17490        let snapshot = cursor_buffer.read(cx).snapshot();
17491        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17492        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17493        let prepare_rename = provider
17494            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17495            .unwrap_or_else(|| Task::ready(Ok(None)));
17496        drop(snapshot);
17497
17498        Some(cx.spawn_in(window, async move |this, cx| {
17499            let rename_range = if let Some(range) = prepare_rename.await? {
17500                Some(range)
17501            } else {
17502                this.update(cx, |this, cx| {
17503                    let buffer = this.buffer.read(cx).snapshot(cx);
17504                    let mut buffer_highlights = this
17505                        .document_highlights_for_position(selection.head(), &buffer)
17506                        .filter(|highlight| {
17507                            highlight.start.excerpt_id == selection.head().excerpt_id
17508                                && highlight.end.excerpt_id == selection.head().excerpt_id
17509                        });
17510                    buffer_highlights
17511                        .next()
17512                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17513                })?
17514            };
17515            if let Some(rename_range) = rename_range {
17516                this.update_in(cx, |this, window, cx| {
17517                    let snapshot = cursor_buffer.read(cx).snapshot();
17518                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17519                    let cursor_offset_in_rename_range =
17520                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17521                    let cursor_offset_in_rename_range_end =
17522                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17523
17524                    this.take_rename(false, window, cx);
17525                    let buffer = this.buffer.read(cx).read(cx);
17526                    let cursor_offset = selection.head().to_offset(&buffer);
17527                    let rename_start =
17528                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17529                    let rename_end = rename_start + rename_buffer_range.len();
17530                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17531                    let mut old_highlight_id = None;
17532                    let old_name: Arc<str> = buffer
17533                        .chunks(rename_start..rename_end, true)
17534                        .map(|chunk| {
17535                            if old_highlight_id.is_none() {
17536                                old_highlight_id = chunk.syntax_highlight_id;
17537                            }
17538                            chunk.text
17539                        })
17540                        .collect::<String>()
17541                        .into();
17542
17543                    drop(buffer);
17544
17545                    // Position the selection in the rename editor so that it matches the current selection.
17546                    this.show_local_selections = false;
17547                    let rename_editor = cx.new(|cx| {
17548                        let mut editor = Editor::single_line(window, cx);
17549                        editor.buffer.update(cx, |buffer, cx| {
17550                            buffer.edit(
17551                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17552                                None,
17553                                cx,
17554                            )
17555                        });
17556                        let cursor_offset_in_rename_range =
17557                            MultiBufferOffset(cursor_offset_in_rename_range);
17558                        let cursor_offset_in_rename_range_end =
17559                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17560                        let rename_selection_range = match cursor_offset_in_rename_range
17561                            .cmp(&cursor_offset_in_rename_range_end)
17562                        {
17563                            Ordering::Equal => {
17564                                editor.select_all(&SelectAll, window, cx);
17565                                return editor;
17566                            }
17567                            Ordering::Less => {
17568                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17569                            }
17570                            Ordering::Greater => {
17571                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17572                            }
17573                        };
17574                        if rename_selection_range.end.0 > old_name.len() {
17575                            editor.select_all(&SelectAll, window, cx);
17576                        } else {
17577                            editor.change_selections(Default::default(), window, cx, |s| {
17578                                s.select_ranges([rename_selection_range]);
17579                            });
17580                        }
17581                        editor
17582                    });
17583                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17584                        if e == &EditorEvent::Focused {
17585                            cx.emit(EditorEvent::FocusedIn)
17586                        }
17587                    })
17588                    .detach();
17589
17590                    let write_highlights =
17591                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17592                    let read_highlights =
17593                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17594                    let ranges = write_highlights
17595                        .iter()
17596                        .flat_map(|(_, ranges)| ranges.iter())
17597                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17598                        .cloned()
17599                        .collect();
17600
17601                    this.highlight_text::<Rename>(
17602                        ranges,
17603                        HighlightStyle {
17604                            fade_out: Some(0.6),
17605                            ..Default::default()
17606                        },
17607                        cx,
17608                    );
17609                    let rename_focus_handle = rename_editor.focus_handle(cx);
17610                    window.focus(&rename_focus_handle);
17611                    let block_id = this.insert_blocks(
17612                        [BlockProperties {
17613                            style: BlockStyle::Flex,
17614                            placement: BlockPlacement::Below(range.start),
17615                            height: Some(1),
17616                            render: Arc::new({
17617                                let rename_editor = rename_editor.clone();
17618                                move |cx: &mut BlockContext| {
17619                                    let mut text_style = cx.editor_style.text.clone();
17620                                    if let Some(highlight_style) = old_highlight_id
17621                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17622                                    {
17623                                        text_style = text_style.highlight(highlight_style);
17624                                    }
17625                                    div()
17626                                        .block_mouse_except_scroll()
17627                                        .pl(cx.anchor_x)
17628                                        .child(EditorElement::new(
17629                                            &rename_editor,
17630                                            EditorStyle {
17631                                                background: cx.theme().system().transparent,
17632                                                local_player: cx.editor_style.local_player,
17633                                                text: text_style,
17634                                                scrollbar_width: cx.editor_style.scrollbar_width,
17635                                                syntax: cx.editor_style.syntax.clone(),
17636                                                status: cx.editor_style.status.clone(),
17637                                                inlay_hints_style: HighlightStyle {
17638                                                    font_weight: Some(FontWeight::BOLD),
17639                                                    ..make_inlay_hints_style(cx.app)
17640                                                },
17641                                                edit_prediction_styles: make_suggestion_styles(
17642                                                    cx.app,
17643                                                ),
17644                                                ..EditorStyle::default()
17645                                            },
17646                                        ))
17647                                        .into_any_element()
17648                                }
17649                            }),
17650                            priority: 0,
17651                        }],
17652                        Some(Autoscroll::fit()),
17653                        cx,
17654                    )[0];
17655                    this.pending_rename = Some(RenameState {
17656                        range,
17657                        old_name,
17658                        editor: rename_editor,
17659                        block_id,
17660                    });
17661                })?;
17662            }
17663
17664            Ok(())
17665        }))
17666    }
17667
17668    pub fn confirm_rename(
17669        &mut self,
17670        _: &ConfirmRename,
17671        window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) -> Option<Task<Result<()>>> {
17674        let rename = self.take_rename(false, window, cx)?;
17675        let workspace = self.workspace()?.downgrade();
17676        let (buffer, start) = self
17677            .buffer
17678            .read(cx)
17679            .text_anchor_for_position(rename.range.start, cx)?;
17680        let (end_buffer, _) = self
17681            .buffer
17682            .read(cx)
17683            .text_anchor_for_position(rename.range.end, cx)?;
17684        if buffer != end_buffer {
17685            return None;
17686        }
17687
17688        let old_name = rename.old_name;
17689        let new_name = rename.editor.read(cx).text(cx);
17690
17691        let rename = self.semantics_provider.as_ref()?.perform_rename(
17692            &buffer,
17693            start,
17694            new_name.clone(),
17695            cx,
17696        )?;
17697
17698        Some(cx.spawn_in(window, async move |editor, cx| {
17699            let project_transaction = rename.await?;
17700            Self::open_project_transaction(
17701                &editor,
17702                workspace,
17703                project_transaction,
17704                format!("Rename: {}{}", old_name, new_name),
17705                cx,
17706            )
17707            .await?;
17708
17709            editor.update(cx, |editor, cx| {
17710                editor.refresh_document_highlights(cx);
17711            })?;
17712            Ok(())
17713        }))
17714    }
17715
17716    fn take_rename(
17717        &mut self,
17718        moving_cursor: bool,
17719        window: &mut Window,
17720        cx: &mut Context<Self>,
17721    ) -> Option<RenameState> {
17722        let rename = self.pending_rename.take()?;
17723        if rename.editor.focus_handle(cx).is_focused(window) {
17724            window.focus(&self.focus_handle);
17725        }
17726
17727        self.remove_blocks(
17728            [rename.block_id].into_iter().collect(),
17729            Some(Autoscroll::fit()),
17730            cx,
17731        );
17732        self.clear_highlights::<Rename>(cx);
17733        self.show_local_selections = true;
17734
17735        if moving_cursor {
17736            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17737                editor
17738                    .selections
17739                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17740                    .head()
17741            });
17742
17743            // Update the selection to match the position of the selection inside
17744            // the rename editor.
17745            let snapshot = self.buffer.read(cx).read(cx);
17746            let rename_range = rename.range.to_offset(&snapshot);
17747            let cursor_in_editor = snapshot
17748                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17749                .min(rename_range.end);
17750            drop(snapshot);
17751
17752            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17753                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17754            });
17755        } else {
17756            self.refresh_document_highlights(cx);
17757        }
17758
17759        Some(rename)
17760    }
17761
17762    pub fn pending_rename(&self) -> Option<&RenameState> {
17763        self.pending_rename.as_ref()
17764    }
17765
17766    fn format(
17767        &mut self,
17768        _: &Format,
17769        window: &mut Window,
17770        cx: &mut Context<Self>,
17771    ) -> Option<Task<Result<()>>> {
17772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17773
17774        let project = match &self.project {
17775            Some(project) => project.clone(),
17776            None => return None,
17777        };
17778
17779        Some(self.perform_format(
17780            project,
17781            FormatTrigger::Manual,
17782            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17783            window,
17784            cx,
17785        ))
17786    }
17787
17788    fn format_selections(
17789        &mut self,
17790        _: &FormatSelections,
17791        window: &mut Window,
17792        cx: &mut Context<Self>,
17793    ) -> Option<Task<Result<()>>> {
17794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17795
17796        let project = match &self.project {
17797            Some(project) => project.clone(),
17798            None => return None,
17799        };
17800
17801        let ranges = self
17802            .selections
17803            .all_adjusted(&self.display_snapshot(cx))
17804            .into_iter()
17805            .map(|selection| selection.range())
17806            .collect_vec();
17807
17808        Some(self.perform_format(
17809            project,
17810            FormatTrigger::Manual,
17811            FormatTarget::Ranges(ranges),
17812            window,
17813            cx,
17814        ))
17815    }
17816
17817    fn perform_format(
17818        &mut self,
17819        project: Entity<Project>,
17820        trigger: FormatTrigger,
17821        target: FormatTarget,
17822        window: &mut Window,
17823        cx: &mut Context<Self>,
17824    ) -> Task<Result<()>> {
17825        let buffer = self.buffer.clone();
17826        let (buffers, target) = match target {
17827            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17828            FormatTarget::Ranges(selection_ranges) => {
17829                let multi_buffer = buffer.read(cx);
17830                let snapshot = multi_buffer.read(cx);
17831                let mut buffers = HashSet::default();
17832                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17833                    BTreeMap::new();
17834                for selection_range in selection_ranges {
17835                    for (buffer, buffer_range, _) in
17836                        snapshot.range_to_buffer_ranges(selection_range)
17837                    {
17838                        let buffer_id = buffer.remote_id();
17839                        let start = buffer.anchor_before(buffer_range.start);
17840                        let end = buffer.anchor_after(buffer_range.end);
17841                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17842                        buffer_id_to_ranges
17843                            .entry(buffer_id)
17844                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17845                            .or_insert_with(|| vec![start..end]);
17846                    }
17847                }
17848                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17849            }
17850        };
17851
17852        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17853        let selections_prev = transaction_id_prev
17854            .and_then(|transaction_id_prev| {
17855                // default to selections as they were after the last edit, if we have them,
17856                // instead of how they are now.
17857                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17858                // will take you back to where you made the last edit, instead of staying where you scrolled
17859                self.selection_history
17860                    .transaction(transaction_id_prev)
17861                    .map(|t| t.0.clone())
17862            })
17863            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17864
17865        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17866        let format = project.update(cx, |project, cx| {
17867            project.format(buffers, target, true, trigger, cx)
17868        });
17869
17870        cx.spawn_in(window, async move |editor, cx| {
17871            let transaction = futures::select_biased! {
17872                transaction = format.log_err().fuse() => transaction,
17873                () = timeout => {
17874                    log::warn!("timed out waiting for formatting");
17875                    None
17876                }
17877            };
17878
17879            buffer
17880                .update(cx, |buffer, cx| {
17881                    if let Some(transaction) = transaction
17882                        && !buffer.is_singleton()
17883                    {
17884                        buffer.push_transaction(&transaction.0, cx);
17885                    }
17886                    cx.notify();
17887                })
17888                .ok();
17889
17890            if let Some(transaction_id_now) =
17891                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17892            {
17893                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17894                if has_new_transaction {
17895                    _ = editor.update(cx, |editor, _| {
17896                        editor
17897                            .selection_history
17898                            .insert_transaction(transaction_id_now, selections_prev);
17899                    });
17900                }
17901            }
17902
17903            Ok(())
17904        })
17905    }
17906
17907    fn organize_imports(
17908        &mut self,
17909        _: &OrganizeImports,
17910        window: &mut Window,
17911        cx: &mut Context<Self>,
17912    ) -> Option<Task<Result<()>>> {
17913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17914        let project = match &self.project {
17915            Some(project) => project.clone(),
17916            None => return None,
17917        };
17918        Some(self.perform_code_action_kind(
17919            project,
17920            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17921            window,
17922            cx,
17923        ))
17924    }
17925
17926    fn perform_code_action_kind(
17927        &mut self,
17928        project: Entity<Project>,
17929        kind: CodeActionKind,
17930        window: &mut Window,
17931        cx: &mut Context<Self>,
17932    ) -> Task<Result<()>> {
17933        let buffer = self.buffer.clone();
17934        let buffers = buffer.read(cx).all_buffers();
17935        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17936        let apply_action = project.update(cx, |project, cx| {
17937            project.apply_code_action_kind(buffers, kind, true, cx)
17938        });
17939        cx.spawn_in(window, async move |_, cx| {
17940            let transaction = futures::select_biased! {
17941                () = timeout => {
17942                    log::warn!("timed out waiting for executing code action");
17943                    None
17944                }
17945                transaction = apply_action.log_err().fuse() => transaction,
17946            };
17947            buffer
17948                .update(cx, |buffer, cx| {
17949                    // check if we need this
17950                    if let Some(transaction) = transaction
17951                        && !buffer.is_singleton()
17952                    {
17953                        buffer.push_transaction(&transaction.0, cx);
17954                    }
17955                    cx.notify();
17956                })
17957                .ok();
17958            Ok(())
17959        })
17960    }
17961
17962    pub fn restart_language_server(
17963        &mut self,
17964        _: &RestartLanguageServer,
17965        _: &mut Window,
17966        cx: &mut Context<Self>,
17967    ) {
17968        if let Some(project) = self.project.clone() {
17969            self.buffer.update(cx, |multi_buffer, cx| {
17970                project.update(cx, |project, cx| {
17971                    project.restart_language_servers_for_buffers(
17972                        multi_buffer.all_buffers().into_iter().collect(),
17973                        HashSet::default(),
17974                        cx,
17975                    );
17976                });
17977            })
17978        }
17979    }
17980
17981    pub fn stop_language_server(
17982        &mut self,
17983        _: &StopLanguageServer,
17984        _: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        if let Some(project) = self.project.clone() {
17988            self.buffer.update(cx, |multi_buffer, cx| {
17989                project.update(cx, |project, cx| {
17990                    project.stop_language_servers_for_buffers(
17991                        multi_buffer.all_buffers().into_iter().collect(),
17992                        HashSet::default(),
17993                        cx,
17994                    );
17995                });
17996            });
17997            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17998        }
17999    }
18000
18001    fn cancel_language_server_work(
18002        workspace: &mut Workspace,
18003        _: &actions::CancelLanguageServerWork,
18004        _: &mut Window,
18005        cx: &mut Context<Workspace>,
18006    ) {
18007        let project = workspace.project();
18008        let buffers = workspace
18009            .active_item(cx)
18010            .and_then(|item| item.act_as::<Editor>(cx))
18011            .map_or(HashSet::default(), |editor| {
18012                editor.read(cx).buffer.read(cx).all_buffers()
18013            });
18014        project.update(cx, |project, cx| {
18015            project.cancel_language_server_work_for_buffers(buffers, cx);
18016        });
18017    }
18018
18019    fn show_character_palette(
18020        &mut self,
18021        _: &ShowCharacterPalette,
18022        window: &mut Window,
18023        _: &mut Context<Self>,
18024    ) {
18025        window.show_character_palette();
18026    }
18027
18028    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18029        if !self.diagnostics_enabled() {
18030            return;
18031        }
18032
18033        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18034            let buffer = self.buffer.read(cx).snapshot(cx);
18035            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18036            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18037            let is_valid = buffer
18038                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18039                .any(|entry| {
18040                    entry.diagnostic.is_primary
18041                        && !entry.range.is_empty()
18042                        && entry.range.start == primary_range_start
18043                        && entry.diagnostic.message == active_diagnostics.active_message
18044                });
18045
18046            if !is_valid {
18047                self.dismiss_diagnostics(cx);
18048            }
18049        }
18050    }
18051
18052    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18053        match &self.active_diagnostics {
18054            ActiveDiagnostic::Group(group) => Some(group),
18055            _ => None,
18056        }
18057    }
18058
18059    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18060        if !self.diagnostics_enabled() {
18061            return;
18062        }
18063        self.dismiss_diagnostics(cx);
18064        self.active_diagnostics = ActiveDiagnostic::All;
18065    }
18066
18067    fn activate_diagnostics(
18068        &mut self,
18069        buffer_id: BufferId,
18070        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18075            return;
18076        }
18077        self.dismiss_diagnostics(cx);
18078        let snapshot = self.snapshot(window, cx);
18079        let buffer = self.buffer.read(cx).snapshot(cx);
18080        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18081            return;
18082        };
18083
18084        let diagnostic_group = buffer
18085            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18086            .collect::<Vec<_>>();
18087
18088        let language_registry = self
18089            .project()
18090            .map(|project| project.read(cx).languages().clone());
18091
18092        let blocks = renderer.render_group(
18093            diagnostic_group,
18094            buffer_id,
18095            snapshot,
18096            cx.weak_entity(),
18097            language_registry,
18098            cx,
18099        );
18100
18101        let blocks = self.display_map.update(cx, |display_map, cx| {
18102            display_map.insert_blocks(blocks, cx).into_iter().collect()
18103        });
18104        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18105            active_range: buffer.anchor_before(diagnostic.range.start)
18106                ..buffer.anchor_after(diagnostic.range.end),
18107            active_message: diagnostic.diagnostic.message.clone(),
18108            group_id: diagnostic.diagnostic.group_id,
18109            blocks,
18110        });
18111        cx.notify();
18112    }
18113
18114    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18115        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18116            return;
18117        };
18118
18119        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18120        if let ActiveDiagnostic::Group(group) = prev {
18121            self.display_map.update(cx, |display_map, cx| {
18122                display_map.remove_blocks(group.blocks, cx);
18123            });
18124            cx.notify();
18125        }
18126    }
18127
18128    /// Disable inline diagnostics rendering for this editor.
18129    pub fn disable_inline_diagnostics(&mut self) {
18130        self.inline_diagnostics_enabled = false;
18131        self.inline_diagnostics_update = Task::ready(());
18132        self.inline_diagnostics.clear();
18133    }
18134
18135    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18136        self.diagnostics_enabled = false;
18137        self.dismiss_diagnostics(cx);
18138        self.inline_diagnostics_update = Task::ready(());
18139        self.inline_diagnostics.clear();
18140    }
18141
18142    pub fn disable_word_completions(&mut self) {
18143        self.word_completions_enabled = false;
18144    }
18145
18146    pub fn diagnostics_enabled(&self) -> bool {
18147        self.diagnostics_enabled && self.mode.is_full()
18148    }
18149
18150    pub fn inline_diagnostics_enabled(&self) -> bool {
18151        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18152    }
18153
18154    pub fn show_inline_diagnostics(&self) -> bool {
18155        self.show_inline_diagnostics
18156    }
18157
18158    pub fn toggle_inline_diagnostics(
18159        &mut self,
18160        _: &ToggleInlineDiagnostics,
18161        window: &mut Window,
18162        cx: &mut Context<Editor>,
18163    ) {
18164        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18165        self.refresh_inline_diagnostics(false, window, cx);
18166    }
18167
18168    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18169        self.diagnostics_max_severity = severity;
18170        self.display_map.update(cx, |display_map, _| {
18171            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18172        });
18173    }
18174
18175    pub fn toggle_diagnostics(
18176        &mut self,
18177        _: &ToggleDiagnostics,
18178        window: &mut Window,
18179        cx: &mut Context<Editor>,
18180    ) {
18181        if !self.diagnostics_enabled() {
18182            return;
18183        }
18184
18185        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18186            EditorSettings::get_global(cx)
18187                .diagnostics_max_severity
18188                .filter(|severity| severity != &DiagnosticSeverity::Off)
18189                .unwrap_or(DiagnosticSeverity::Hint)
18190        } else {
18191            DiagnosticSeverity::Off
18192        };
18193        self.set_max_diagnostics_severity(new_severity, cx);
18194        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18195            self.active_diagnostics = ActiveDiagnostic::None;
18196            self.inline_diagnostics_update = Task::ready(());
18197            self.inline_diagnostics.clear();
18198        } else {
18199            self.refresh_inline_diagnostics(false, window, cx);
18200        }
18201
18202        cx.notify();
18203    }
18204
18205    pub fn toggle_minimap(
18206        &mut self,
18207        _: &ToggleMinimap,
18208        window: &mut Window,
18209        cx: &mut Context<Editor>,
18210    ) {
18211        if self.supports_minimap(cx) {
18212            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18213        }
18214    }
18215
18216    fn refresh_inline_diagnostics(
18217        &mut self,
18218        debounce: bool,
18219        window: &mut Window,
18220        cx: &mut Context<Self>,
18221    ) {
18222        let max_severity = ProjectSettings::get_global(cx)
18223            .diagnostics
18224            .inline
18225            .max_severity
18226            .unwrap_or(self.diagnostics_max_severity);
18227
18228        if !self.inline_diagnostics_enabled()
18229            || !self.diagnostics_enabled()
18230            || !self.show_inline_diagnostics
18231            || max_severity == DiagnosticSeverity::Off
18232        {
18233            self.inline_diagnostics_update = Task::ready(());
18234            self.inline_diagnostics.clear();
18235            return;
18236        }
18237
18238        let debounce_ms = ProjectSettings::get_global(cx)
18239            .diagnostics
18240            .inline
18241            .update_debounce_ms;
18242        let debounce = if debounce && debounce_ms > 0 {
18243            Some(Duration::from_millis(debounce_ms))
18244        } else {
18245            None
18246        };
18247        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18248            if let Some(debounce) = debounce {
18249                cx.background_executor().timer(debounce).await;
18250            }
18251            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18252                editor
18253                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18254                    .ok()
18255            }) else {
18256                return;
18257            };
18258
18259            let new_inline_diagnostics = cx
18260                .background_spawn(async move {
18261                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18262                    for diagnostic_entry in
18263                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18264                    {
18265                        let message = diagnostic_entry
18266                            .diagnostic
18267                            .message
18268                            .split_once('\n')
18269                            .map(|(line, _)| line)
18270                            .map(SharedString::new)
18271                            .unwrap_or_else(|| {
18272                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18273                            });
18274                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18275                        let (Ok(i) | Err(i)) = inline_diagnostics
18276                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18277                        inline_diagnostics.insert(
18278                            i,
18279                            (
18280                                start_anchor,
18281                                InlineDiagnostic {
18282                                    message,
18283                                    group_id: diagnostic_entry.diagnostic.group_id,
18284                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18285                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18286                                    severity: diagnostic_entry.diagnostic.severity,
18287                                },
18288                            ),
18289                        );
18290                    }
18291                    inline_diagnostics
18292                })
18293                .await;
18294
18295            editor
18296                .update(cx, |editor, cx| {
18297                    editor.inline_diagnostics = new_inline_diagnostics;
18298                    cx.notify();
18299                })
18300                .ok();
18301        });
18302    }
18303
18304    fn pull_diagnostics(
18305        &mut self,
18306        buffer_id: Option<BufferId>,
18307        window: &Window,
18308        cx: &mut Context<Self>,
18309    ) -> Option<()> {
18310        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18311            return None;
18312        }
18313        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18314            .diagnostics
18315            .lsp_pull_diagnostics;
18316        if !pull_diagnostics_settings.enabled {
18317            return None;
18318        }
18319        let project = self.project()?.downgrade();
18320        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18321        let mut buffers = self.buffer.read(cx).all_buffers();
18322        buffers.retain(|buffer| {
18323            let buffer_id_to_retain = buffer.read(cx).remote_id();
18324            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18325                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18326        });
18327        if buffers.is_empty() {
18328            self.pull_diagnostics_task = Task::ready(());
18329            return None;
18330        }
18331
18332        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18333            cx.background_executor().timer(debounce).await;
18334
18335            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18336                buffers
18337                    .into_iter()
18338                    .filter_map(|buffer| {
18339                        project
18340                            .update(cx, |project, cx| {
18341                                project.lsp_store().update(cx, |lsp_store, cx| {
18342                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18343                                })
18344                            })
18345                            .ok()
18346                    })
18347                    .collect::<FuturesUnordered<_>>()
18348            }) else {
18349                return;
18350            };
18351
18352            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18353                match pull_task {
18354                    Ok(()) => {
18355                        if editor
18356                            .update_in(cx, |editor, window, cx| {
18357                                editor.update_diagnostics_state(window, cx);
18358                            })
18359                            .is_err()
18360                        {
18361                            return;
18362                        }
18363                    }
18364                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18365                }
18366            }
18367        });
18368
18369        Some(())
18370    }
18371
18372    pub fn set_selections_from_remote(
18373        &mut self,
18374        selections: Vec<Selection<Anchor>>,
18375        pending_selection: Option<Selection<Anchor>>,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        let old_cursor_position = self.selections.newest_anchor().head();
18380        self.selections
18381            .change_with(&self.display_snapshot(cx), |s| {
18382                s.select_anchors(selections);
18383                if let Some(pending_selection) = pending_selection {
18384                    s.set_pending(pending_selection, SelectMode::Character);
18385                } else {
18386                    s.clear_pending();
18387                }
18388            });
18389        self.selections_did_change(
18390            false,
18391            &old_cursor_position,
18392            SelectionEffects::default(),
18393            window,
18394            cx,
18395        );
18396    }
18397
18398    pub fn transact(
18399        &mut self,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18403    ) -> Option<TransactionId> {
18404        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18405            this.start_transaction_at(Instant::now(), window, cx);
18406            update(this, window, cx);
18407            this.end_transaction_at(Instant::now(), cx)
18408        })
18409    }
18410
18411    pub fn start_transaction_at(
18412        &mut self,
18413        now: Instant,
18414        window: &mut Window,
18415        cx: &mut Context<Self>,
18416    ) -> Option<TransactionId> {
18417        self.end_selection(window, cx);
18418        if let Some(tx_id) = self
18419            .buffer
18420            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18421        {
18422            self.selection_history
18423                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18424            cx.emit(EditorEvent::TransactionBegun {
18425                transaction_id: tx_id,
18426            });
18427            Some(tx_id)
18428        } else {
18429            None
18430        }
18431    }
18432
18433    pub fn end_transaction_at(
18434        &mut self,
18435        now: Instant,
18436        cx: &mut Context<Self>,
18437    ) -> Option<TransactionId> {
18438        if let Some(transaction_id) = self
18439            .buffer
18440            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18441        {
18442            if let Some((_, end_selections)) =
18443                self.selection_history.transaction_mut(transaction_id)
18444            {
18445                *end_selections = Some(self.selections.disjoint_anchors_arc());
18446            } else {
18447                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18448            }
18449
18450            cx.emit(EditorEvent::Edited { transaction_id });
18451            Some(transaction_id)
18452        } else {
18453            None
18454        }
18455    }
18456
18457    pub fn modify_transaction_selection_history(
18458        &mut self,
18459        transaction_id: TransactionId,
18460        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18461    ) -> bool {
18462        self.selection_history
18463            .transaction_mut(transaction_id)
18464            .map(modify)
18465            .is_some()
18466    }
18467
18468    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18469        if self.selection_mark_mode {
18470            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18471                s.move_with(|_, sel| {
18472                    sel.collapse_to(sel.head(), SelectionGoal::None);
18473                });
18474            })
18475        }
18476        self.selection_mark_mode = true;
18477        cx.notify();
18478    }
18479
18480    pub fn swap_selection_ends(
18481        &mut self,
18482        _: &actions::SwapSelectionEnds,
18483        window: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) {
18486        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18487            s.move_with(|_, sel| {
18488                if sel.start != sel.end {
18489                    sel.reversed = !sel.reversed
18490                }
18491            });
18492        });
18493        self.request_autoscroll(Autoscroll::newest(), cx);
18494        cx.notify();
18495    }
18496
18497    pub fn toggle_focus(
18498        workspace: &mut Workspace,
18499        _: &actions::ToggleFocus,
18500        window: &mut Window,
18501        cx: &mut Context<Workspace>,
18502    ) {
18503        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18504            return;
18505        };
18506        workspace.activate_item(&item, true, true, window, cx);
18507    }
18508
18509    pub fn toggle_fold(
18510        &mut self,
18511        _: &actions::ToggleFold,
18512        window: &mut Window,
18513        cx: &mut Context<Self>,
18514    ) {
18515        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18516            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18517            let selection = self.selections.newest::<Point>(&display_map);
18518
18519            let range = if selection.is_empty() {
18520                let point = selection.head().to_display_point(&display_map);
18521                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18522                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18523                    .to_point(&display_map);
18524                start..end
18525            } else {
18526                selection.range()
18527            };
18528            if display_map.folds_in_range(range).next().is_some() {
18529                self.unfold_lines(&Default::default(), window, cx)
18530            } else {
18531                self.fold(&Default::default(), window, cx)
18532            }
18533        } else {
18534            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18535            let buffer_ids: HashSet<_> = self
18536                .selections
18537                .disjoint_anchor_ranges()
18538                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18539                .collect();
18540
18541            let should_unfold = buffer_ids
18542                .iter()
18543                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18544
18545            for buffer_id in buffer_ids {
18546                if should_unfold {
18547                    self.unfold_buffer(buffer_id, cx);
18548                } else {
18549                    self.fold_buffer(buffer_id, cx);
18550                }
18551            }
18552        }
18553    }
18554
18555    pub fn toggle_fold_recursive(
18556        &mut self,
18557        _: &actions::ToggleFoldRecursive,
18558        window: &mut Window,
18559        cx: &mut Context<Self>,
18560    ) {
18561        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18562
18563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18564        let range = if selection.is_empty() {
18565            let point = selection.head().to_display_point(&display_map);
18566            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18567            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18568                .to_point(&display_map);
18569            start..end
18570        } else {
18571            selection.range()
18572        };
18573        if display_map.folds_in_range(range).next().is_some() {
18574            self.unfold_recursive(&Default::default(), window, cx)
18575        } else {
18576            self.fold_recursive(&Default::default(), window, cx)
18577        }
18578    }
18579
18580    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18581        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18582            let mut to_fold = Vec::new();
18583            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18584            let selections = self.selections.all_adjusted(&display_map);
18585
18586            for selection in selections {
18587                let range = selection.range().sorted();
18588                let buffer_start_row = range.start.row;
18589
18590                if range.start.row != range.end.row {
18591                    let mut found = false;
18592                    let mut row = range.start.row;
18593                    while row <= range.end.row {
18594                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18595                        {
18596                            found = true;
18597                            row = crease.range().end.row + 1;
18598                            to_fold.push(crease);
18599                        } else {
18600                            row += 1
18601                        }
18602                    }
18603                    if found {
18604                        continue;
18605                    }
18606                }
18607
18608                for row in (0..=range.start.row).rev() {
18609                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18610                        && crease.range().end.row >= buffer_start_row
18611                    {
18612                        to_fold.push(crease);
18613                        if row <= range.start.row {
18614                            break;
18615                        }
18616                    }
18617                }
18618            }
18619
18620            self.fold_creases(to_fold, true, window, cx);
18621        } else {
18622            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18623            let buffer_ids = self
18624                .selections
18625                .disjoint_anchor_ranges()
18626                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18627                .collect::<HashSet<_>>();
18628            for buffer_id in buffer_ids {
18629                self.fold_buffer(buffer_id, cx);
18630            }
18631        }
18632    }
18633
18634    pub fn toggle_fold_all(
18635        &mut self,
18636        _: &actions::ToggleFoldAll,
18637        window: &mut Window,
18638        cx: &mut Context<Self>,
18639    ) {
18640        if self.buffer.read(cx).is_singleton() {
18641            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18642            let has_folds = display_map
18643                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18644                .next()
18645                .is_some();
18646
18647            if has_folds {
18648                self.unfold_all(&actions::UnfoldAll, window, cx);
18649            } else {
18650                self.fold_all(&actions::FoldAll, window, cx);
18651            }
18652        } else {
18653            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18654            let should_unfold = buffer_ids
18655                .iter()
18656                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18657
18658            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18659                editor
18660                    .update_in(cx, |editor, _, cx| {
18661                        for buffer_id in buffer_ids {
18662                            if should_unfold {
18663                                editor.unfold_buffer(buffer_id, cx);
18664                            } else {
18665                                editor.fold_buffer(buffer_id, cx);
18666                            }
18667                        }
18668                    })
18669                    .ok();
18670            });
18671        }
18672    }
18673
18674    fn fold_at_level(
18675        &mut self,
18676        fold_at: &FoldAtLevel,
18677        window: &mut Window,
18678        cx: &mut Context<Self>,
18679    ) {
18680        if !self.buffer.read(cx).is_singleton() {
18681            return;
18682        }
18683
18684        let fold_at_level = fold_at.0;
18685        let snapshot = self.buffer.read(cx).snapshot(cx);
18686        let mut to_fold = Vec::new();
18687        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18688
18689        let row_ranges_to_keep: Vec<Range<u32>> = self
18690            .selections
18691            .all::<Point>(&self.display_snapshot(cx))
18692            .into_iter()
18693            .map(|sel| sel.start.row..sel.end.row)
18694            .collect();
18695
18696        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18697            while start_row < end_row {
18698                match self
18699                    .snapshot(window, cx)
18700                    .crease_for_buffer_row(MultiBufferRow(start_row))
18701                {
18702                    Some(crease) => {
18703                        let nested_start_row = crease.range().start.row + 1;
18704                        let nested_end_row = crease.range().end.row;
18705
18706                        if current_level < fold_at_level {
18707                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18708                        } else if current_level == fold_at_level {
18709                            // Fold iff there is no selection completely contained within the fold region
18710                            if !row_ranges_to_keep.iter().any(|selection| {
18711                                selection.end >= nested_start_row
18712                                    && selection.start <= nested_end_row
18713                            }) {
18714                                to_fold.push(crease);
18715                            }
18716                        }
18717
18718                        start_row = nested_end_row + 1;
18719                    }
18720                    None => start_row += 1,
18721                }
18722            }
18723        }
18724
18725        self.fold_creases(to_fold, true, window, cx);
18726    }
18727
18728    pub fn fold_at_level_1(
18729        &mut self,
18730        _: &actions::FoldAtLevel1,
18731        window: &mut Window,
18732        cx: &mut Context<Self>,
18733    ) {
18734        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18735    }
18736
18737    pub fn fold_at_level_2(
18738        &mut self,
18739        _: &actions::FoldAtLevel2,
18740        window: &mut Window,
18741        cx: &mut Context<Self>,
18742    ) {
18743        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18744    }
18745
18746    pub fn fold_at_level_3(
18747        &mut self,
18748        _: &actions::FoldAtLevel3,
18749        window: &mut Window,
18750        cx: &mut Context<Self>,
18751    ) {
18752        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18753    }
18754
18755    pub fn fold_at_level_4(
18756        &mut self,
18757        _: &actions::FoldAtLevel4,
18758        window: &mut Window,
18759        cx: &mut Context<Self>,
18760    ) {
18761        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18762    }
18763
18764    pub fn fold_at_level_5(
18765        &mut self,
18766        _: &actions::FoldAtLevel5,
18767        window: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) {
18770        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18771    }
18772
18773    pub fn fold_at_level_6(
18774        &mut self,
18775        _: &actions::FoldAtLevel6,
18776        window: &mut Window,
18777        cx: &mut Context<Self>,
18778    ) {
18779        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18780    }
18781
18782    pub fn fold_at_level_7(
18783        &mut self,
18784        _: &actions::FoldAtLevel7,
18785        window: &mut Window,
18786        cx: &mut Context<Self>,
18787    ) {
18788        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18789    }
18790
18791    pub fn fold_at_level_8(
18792        &mut self,
18793        _: &actions::FoldAtLevel8,
18794        window: &mut Window,
18795        cx: &mut Context<Self>,
18796    ) {
18797        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18798    }
18799
18800    pub fn fold_at_level_9(
18801        &mut self,
18802        _: &actions::FoldAtLevel9,
18803        window: &mut Window,
18804        cx: &mut Context<Self>,
18805    ) {
18806        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18807    }
18808
18809    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18810        if self.buffer.read(cx).is_singleton() {
18811            let mut fold_ranges = Vec::new();
18812            let snapshot = self.buffer.read(cx).snapshot(cx);
18813
18814            for row in 0..snapshot.max_row().0 {
18815                if let Some(foldable_range) = self
18816                    .snapshot(window, cx)
18817                    .crease_for_buffer_row(MultiBufferRow(row))
18818                {
18819                    fold_ranges.push(foldable_range);
18820                }
18821            }
18822
18823            self.fold_creases(fold_ranges, true, window, cx);
18824        } else {
18825            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18826                editor
18827                    .update_in(cx, |editor, _, cx| {
18828                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18829                            editor.fold_buffer(buffer_id, cx);
18830                        }
18831                    })
18832                    .ok();
18833            });
18834        }
18835    }
18836
18837    pub fn fold_function_bodies(
18838        &mut self,
18839        _: &actions::FoldFunctionBodies,
18840        window: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) {
18843        let snapshot = self.buffer.read(cx).snapshot(cx);
18844
18845        let ranges = snapshot
18846            .text_object_ranges(
18847                MultiBufferOffset(0)..snapshot.len(),
18848                TreeSitterOptions::default(),
18849            )
18850            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18851            .collect::<Vec<_>>();
18852
18853        let creases = ranges
18854            .into_iter()
18855            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18856            .collect();
18857
18858        self.fold_creases(creases, true, window, cx);
18859    }
18860
18861    pub fn fold_recursive(
18862        &mut self,
18863        _: &actions::FoldRecursive,
18864        window: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        let mut to_fold = Vec::new();
18868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18869        let selections = self.selections.all_adjusted(&display_map);
18870
18871        for selection in selections {
18872            let range = selection.range().sorted();
18873            let buffer_start_row = range.start.row;
18874
18875            if range.start.row != range.end.row {
18876                let mut found = false;
18877                for row in range.start.row..=range.end.row {
18878                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18879                        found = true;
18880                        to_fold.push(crease);
18881                    }
18882                }
18883                if found {
18884                    continue;
18885                }
18886            }
18887
18888            for row in (0..=range.start.row).rev() {
18889                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18890                    if crease.range().end.row >= buffer_start_row {
18891                        to_fold.push(crease);
18892                    } else {
18893                        break;
18894                    }
18895                }
18896            }
18897        }
18898
18899        self.fold_creases(to_fold, true, window, cx);
18900    }
18901
18902    pub fn fold_at(
18903        &mut self,
18904        buffer_row: MultiBufferRow,
18905        window: &mut Window,
18906        cx: &mut Context<Self>,
18907    ) {
18908        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18909
18910        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18911            let autoscroll = self
18912                .selections
18913                .all::<Point>(&display_map)
18914                .iter()
18915                .any(|selection| crease.range().overlaps(&selection.range()));
18916
18917            self.fold_creases(vec![crease], autoscroll, window, cx);
18918        }
18919    }
18920
18921    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18922        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18923            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18924            let buffer = display_map.buffer_snapshot();
18925            let selections = self.selections.all::<Point>(&display_map);
18926            let ranges = selections
18927                .iter()
18928                .map(|s| {
18929                    let range = s.display_range(&display_map).sorted();
18930                    let mut start = range.start.to_point(&display_map);
18931                    let mut end = range.end.to_point(&display_map);
18932                    start.column = 0;
18933                    end.column = buffer.line_len(MultiBufferRow(end.row));
18934                    start..end
18935                })
18936                .collect::<Vec<_>>();
18937
18938            self.unfold_ranges(&ranges, true, true, cx);
18939        } else {
18940            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18941            let buffer_ids = self
18942                .selections
18943                .disjoint_anchor_ranges()
18944                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18945                .collect::<HashSet<_>>();
18946            for buffer_id in buffer_ids {
18947                self.unfold_buffer(buffer_id, cx);
18948            }
18949        }
18950    }
18951
18952    pub fn unfold_recursive(
18953        &mut self,
18954        _: &UnfoldRecursive,
18955        _window: &mut Window,
18956        cx: &mut Context<Self>,
18957    ) {
18958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18959        let selections = self.selections.all::<Point>(&display_map);
18960        let ranges = selections
18961            .iter()
18962            .map(|s| {
18963                let mut range = s.display_range(&display_map).sorted();
18964                *range.start.column_mut() = 0;
18965                *range.end.column_mut() = display_map.line_len(range.end.row());
18966                let start = range.start.to_point(&display_map);
18967                let end = range.end.to_point(&display_map);
18968                start..end
18969            })
18970            .collect::<Vec<_>>();
18971
18972        self.unfold_ranges(&ranges, true, true, cx);
18973    }
18974
18975    pub fn unfold_at(
18976        &mut self,
18977        buffer_row: MultiBufferRow,
18978        _window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18982
18983        let intersection_range = Point::new(buffer_row.0, 0)
18984            ..Point::new(
18985                buffer_row.0,
18986                display_map.buffer_snapshot().line_len(buffer_row),
18987            );
18988
18989        let autoscroll = self
18990            .selections
18991            .all::<Point>(&display_map)
18992            .iter()
18993            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18994
18995        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18996    }
18997
18998    pub fn unfold_all(
18999        &mut self,
19000        _: &actions::UnfoldAll,
19001        _window: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        if self.buffer.read(cx).is_singleton() {
19005            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19006            self.unfold_ranges(
19007                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19008                true,
19009                true,
19010                cx,
19011            );
19012        } else {
19013            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19014                editor
19015                    .update(cx, |editor, cx| {
19016                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19017                            editor.unfold_buffer(buffer_id, cx);
19018                        }
19019                    })
19020                    .ok();
19021            });
19022        }
19023    }
19024
19025    pub fn fold_selected_ranges(
19026        &mut self,
19027        _: &FoldSelectedRanges,
19028        window: &mut Window,
19029        cx: &mut Context<Self>,
19030    ) {
19031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19032        let selections = self.selections.all_adjusted(&display_map);
19033        let ranges = selections
19034            .into_iter()
19035            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19036            .collect::<Vec<_>>();
19037        self.fold_creases(ranges, true, window, cx);
19038    }
19039
19040    pub fn fold_ranges<T: ToOffset + Clone>(
19041        &mut self,
19042        ranges: Vec<Range<T>>,
19043        auto_scroll: bool,
19044        window: &mut Window,
19045        cx: &mut Context<Self>,
19046    ) {
19047        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19048        let ranges = ranges
19049            .into_iter()
19050            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19051            .collect::<Vec<_>>();
19052        self.fold_creases(ranges, auto_scroll, window, cx);
19053    }
19054
19055    pub fn fold_creases<T: ToOffset + Clone>(
19056        &mut self,
19057        creases: Vec<Crease<T>>,
19058        auto_scroll: bool,
19059        _window: &mut Window,
19060        cx: &mut Context<Self>,
19061    ) {
19062        if creases.is_empty() {
19063            return;
19064        }
19065
19066        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19067
19068        if auto_scroll {
19069            self.request_autoscroll(Autoscroll::fit(), cx);
19070        }
19071
19072        cx.notify();
19073
19074        self.scrollbar_marker_state.dirty = true;
19075        self.folds_did_change(cx);
19076    }
19077
19078    /// Removes any folds whose ranges intersect any of the given ranges.
19079    pub fn unfold_ranges<T: ToOffset + Clone>(
19080        &mut self,
19081        ranges: &[Range<T>],
19082        inclusive: bool,
19083        auto_scroll: bool,
19084        cx: &mut Context<Self>,
19085    ) {
19086        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19087            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19088        });
19089        self.folds_did_change(cx);
19090    }
19091
19092    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19093        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19094            return;
19095        }
19096
19097        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19098        self.display_map.update(cx, |display_map, cx| {
19099            display_map.fold_buffers([buffer_id], cx)
19100        });
19101
19102        let snapshot = self.display_snapshot(cx);
19103        self.selections.change_with(&snapshot, |selections| {
19104            selections.remove_selections_from_buffer(buffer_id);
19105        });
19106
19107        cx.emit(EditorEvent::BufferFoldToggled {
19108            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19109            folded: true,
19110        });
19111        cx.notify();
19112    }
19113
19114    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19115        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19116            return;
19117        }
19118        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19119        self.display_map.update(cx, |display_map, cx| {
19120            display_map.unfold_buffers([buffer_id], cx);
19121        });
19122        cx.emit(EditorEvent::BufferFoldToggled {
19123            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19124            folded: false,
19125        });
19126        cx.notify();
19127    }
19128
19129    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19130        self.display_map.read(cx).is_buffer_folded(buffer)
19131    }
19132
19133    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19134        self.display_map.read(cx).folded_buffers()
19135    }
19136
19137    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19138        self.display_map.update(cx, |display_map, cx| {
19139            display_map.disable_header_for_buffer(buffer_id, cx);
19140        });
19141        cx.notify();
19142    }
19143
19144    /// Removes any folds with the given ranges.
19145    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19146        &mut self,
19147        ranges: &[Range<T>],
19148        type_id: TypeId,
19149        auto_scroll: bool,
19150        cx: &mut Context<Self>,
19151    ) {
19152        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19153            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19154        });
19155        self.folds_did_change(cx);
19156    }
19157
19158    fn remove_folds_with<T: ToOffset + Clone>(
19159        &mut self,
19160        ranges: &[Range<T>],
19161        auto_scroll: bool,
19162        cx: &mut Context<Self>,
19163        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19164    ) {
19165        if ranges.is_empty() {
19166            return;
19167        }
19168
19169        let mut buffers_affected = HashSet::default();
19170        let multi_buffer = self.buffer().read(cx);
19171        for range in ranges {
19172            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19173                buffers_affected.insert(buffer.read(cx).remote_id());
19174            };
19175        }
19176
19177        self.display_map.update(cx, update);
19178
19179        if auto_scroll {
19180            self.request_autoscroll(Autoscroll::fit(), cx);
19181        }
19182
19183        cx.notify();
19184        self.scrollbar_marker_state.dirty = true;
19185        self.active_indent_guides_state.dirty = true;
19186    }
19187
19188    pub fn update_renderer_widths(
19189        &mut self,
19190        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19191        cx: &mut Context<Self>,
19192    ) -> bool {
19193        self.display_map
19194            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19195    }
19196
19197    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19198        self.display_map.read(cx).fold_placeholder.clone()
19199    }
19200
19201    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19202        self.buffer.update(cx, |buffer, cx| {
19203            buffer.set_all_diff_hunks_expanded(cx);
19204        });
19205    }
19206
19207    pub fn expand_all_diff_hunks(
19208        &mut self,
19209        _: &ExpandAllDiffHunks,
19210        _window: &mut Window,
19211        cx: &mut Context<Self>,
19212    ) {
19213        self.buffer.update(cx, |buffer, cx| {
19214            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19215        });
19216    }
19217
19218    pub fn collapse_all_diff_hunks(
19219        &mut self,
19220        _: &CollapseAllDiffHunks,
19221        _window: &mut Window,
19222        cx: &mut Context<Self>,
19223    ) {
19224        self.buffer.update(cx, |buffer, cx| {
19225            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19226        });
19227    }
19228
19229    pub fn toggle_selected_diff_hunks(
19230        &mut self,
19231        _: &ToggleSelectedDiffHunks,
19232        _window: &mut Window,
19233        cx: &mut Context<Self>,
19234    ) {
19235        let ranges: Vec<_> = self
19236            .selections
19237            .disjoint_anchors()
19238            .iter()
19239            .map(|s| s.range())
19240            .collect();
19241        self.toggle_diff_hunks_in_ranges(ranges, cx);
19242    }
19243
19244    pub fn diff_hunks_in_ranges<'a>(
19245        &'a self,
19246        ranges: &'a [Range<Anchor>],
19247        buffer: &'a MultiBufferSnapshot,
19248    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19249        ranges.iter().flat_map(move |range| {
19250            let end_excerpt_id = range.end.excerpt_id;
19251            let range = range.to_point(buffer);
19252            let mut peek_end = range.end;
19253            if range.end.row < buffer.max_row().0 {
19254                peek_end = Point::new(range.end.row + 1, 0);
19255            }
19256            buffer
19257                .diff_hunks_in_range(range.start..peek_end)
19258                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19259        })
19260    }
19261
19262    pub fn has_stageable_diff_hunks_in_ranges(
19263        &self,
19264        ranges: &[Range<Anchor>],
19265        snapshot: &MultiBufferSnapshot,
19266    ) -> bool {
19267        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19268        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19269    }
19270
19271    pub fn toggle_staged_selected_diff_hunks(
19272        &mut self,
19273        _: &::git::ToggleStaged,
19274        _: &mut Window,
19275        cx: &mut Context<Self>,
19276    ) {
19277        let snapshot = self.buffer.read(cx).snapshot(cx);
19278        let ranges: Vec<_> = self
19279            .selections
19280            .disjoint_anchors()
19281            .iter()
19282            .map(|s| s.range())
19283            .collect();
19284        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19285        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19286    }
19287
19288    pub fn set_render_diff_hunk_controls(
19289        &mut self,
19290        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19291        cx: &mut Context<Self>,
19292    ) {
19293        self.render_diff_hunk_controls = render_diff_hunk_controls;
19294        cx.notify();
19295    }
19296
19297    pub fn stage_and_next(
19298        &mut self,
19299        _: &::git::StageAndNext,
19300        window: &mut Window,
19301        cx: &mut Context<Self>,
19302    ) {
19303        self.do_stage_or_unstage_and_next(true, window, cx);
19304    }
19305
19306    pub fn unstage_and_next(
19307        &mut self,
19308        _: &::git::UnstageAndNext,
19309        window: &mut Window,
19310        cx: &mut Context<Self>,
19311    ) {
19312        self.do_stage_or_unstage_and_next(false, window, cx);
19313    }
19314
19315    pub fn stage_or_unstage_diff_hunks(
19316        &mut self,
19317        stage: bool,
19318        ranges: Vec<Range<Anchor>>,
19319        cx: &mut Context<Self>,
19320    ) {
19321        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19322        cx.spawn(async move |this, cx| {
19323            task.await?;
19324            this.update(cx, |this, cx| {
19325                let snapshot = this.buffer.read(cx).snapshot(cx);
19326                let chunk_by = this
19327                    .diff_hunks_in_ranges(&ranges, &snapshot)
19328                    .chunk_by(|hunk| hunk.buffer_id);
19329                for (buffer_id, hunks) in &chunk_by {
19330                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19331                }
19332            })
19333        })
19334        .detach_and_log_err(cx);
19335    }
19336
19337    fn save_buffers_for_ranges_if_needed(
19338        &mut self,
19339        ranges: &[Range<Anchor>],
19340        cx: &mut Context<Editor>,
19341    ) -> Task<Result<()>> {
19342        let multibuffer = self.buffer.read(cx);
19343        let snapshot = multibuffer.read(cx);
19344        let buffer_ids: HashSet<_> = ranges
19345            .iter()
19346            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19347            .collect();
19348        drop(snapshot);
19349
19350        let mut buffers = HashSet::default();
19351        for buffer_id in buffer_ids {
19352            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19353                let buffer = buffer_entity.read(cx);
19354                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19355                {
19356                    buffers.insert(buffer_entity);
19357                }
19358            }
19359        }
19360
19361        if let Some(project) = &self.project {
19362            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19363        } else {
19364            Task::ready(Ok(()))
19365        }
19366    }
19367
19368    fn do_stage_or_unstage_and_next(
19369        &mut self,
19370        stage: bool,
19371        window: &mut Window,
19372        cx: &mut Context<Self>,
19373    ) {
19374        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19375
19376        if ranges.iter().any(|range| range.start != range.end) {
19377            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19378            return;
19379        }
19380
19381        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19382        let snapshot = self.snapshot(window, cx);
19383        let position = self
19384            .selections
19385            .newest::<Point>(&snapshot.display_snapshot)
19386            .head();
19387        let mut row = snapshot
19388            .buffer_snapshot()
19389            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19390            .find(|hunk| hunk.row_range.start.0 > position.row)
19391            .map(|hunk| hunk.row_range.start);
19392
19393        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19394        // Outside of the project diff editor, wrap around to the beginning.
19395        if !all_diff_hunks_expanded {
19396            row = row.or_else(|| {
19397                snapshot
19398                    .buffer_snapshot()
19399                    .diff_hunks_in_range(Point::zero()..position)
19400                    .find(|hunk| hunk.row_range.end.0 < position.row)
19401                    .map(|hunk| hunk.row_range.start)
19402            });
19403        }
19404
19405        if let Some(row) = row {
19406            let destination = Point::new(row.0, 0);
19407            let autoscroll = Autoscroll::center();
19408
19409            self.unfold_ranges(&[destination..destination], false, false, cx);
19410            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19411                s.select_ranges([destination..destination]);
19412            });
19413        }
19414    }
19415
19416    fn do_stage_or_unstage(
19417        &self,
19418        stage: bool,
19419        buffer_id: BufferId,
19420        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19421        cx: &mut App,
19422    ) -> Option<()> {
19423        let project = self.project()?;
19424        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19425        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19426        let buffer_snapshot = buffer.read(cx).snapshot();
19427        let file_exists = buffer_snapshot
19428            .file()
19429            .is_some_and(|file| file.disk_state().exists());
19430        diff.update(cx, |diff, cx| {
19431            diff.stage_or_unstage_hunks(
19432                stage,
19433                &hunks
19434                    .map(|hunk| buffer_diff::DiffHunk {
19435                        buffer_range: hunk.buffer_range,
19436                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19437                            ..hunk.diff_base_byte_range.end.0,
19438                        secondary_status: hunk.secondary_status,
19439                        range: Point::zero()..Point::zero(), // unused
19440                    })
19441                    .collect::<Vec<_>>(),
19442                &buffer_snapshot,
19443                file_exists,
19444                cx,
19445            )
19446        });
19447        None
19448    }
19449
19450    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19451        let ranges: Vec<_> = self
19452            .selections
19453            .disjoint_anchors()
19454            .iter()
19455            .map(|s| s.range())
19456            .collect();
19457        self.buffer
19458            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19459    }
19460
19461    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19462        self.buffer.update(cx, |buffer, cx| {
19463            let ranges = vec![Anchor::min()..Anchor::max()];
19464            if !buffer.all_diff_hunks_expanded()
19465                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19466            {
19467                buffer.collapse_diff_hunks(ranges, cx);
19468                true
19469            } else {
19470                false
19471            }
19472        })
19473    }
19474
19475    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19476        if self.buffer.read(cx).all_diff_hunks_expanded() {
19477            return true;
19478        }
19479        let ranges = vec![Anchor::min()..Anchor::max()];
19480        self.buffer
19481            .read(cx)
19482            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19483    }
19484
19485    fn toggle_diff_hunks_in_ranges(
19486        &mut self,
19487        ranges: Vec<Range<Anchor>>,
19488        cx: &mut Context<Editor>,
19489    ) {
19490        self.buffer.update(cx, |buffer, cx| {
19491            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19492            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19493        })
19494    }
19495
19496    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19497        self.buffer.update(cx, |buffer, cx| {
19498            let snapshot = buffer.snapshot(cx);
19499            let excerpt_id = range.end.excerpt_id;
19500            let point_range = range.to_point(&snapshot);
19501            let expand = !buffer.single_hunk_is_expanded(range, cx);
19502            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19503        })
19504    }
19505
19506    pub(crate) fn apply_all_diff_hunks(
19507        &mut self,
19508        _: &ApplyAllDiffHunks,
19509        window: &mut Window,
19510        cx: &mut Context<Self>,
19511    ) {
19512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19513
19514        let buffers = self.buffer.read(cx).all_buffers();
19515        for branch_buffer in buffers {
19516            branch_buffer.update(cx, |branch_buffer, cx| {
19517                branch_buffer.merge_into_base(Vec::new(), cx);
19518            });
19519        }
19520
19521        if let Some(project) = self.project.clone() {
19522            self.save(
19523                SaveOptions {
19524                    format: true,
19525                    autosave: false,
19526                },
19527                project,
19528                window,
19529                cx,
19530            )
19531            .detach_and_log_err(cx);
19532        }
19533    }
19534
19535    pub(crate) fn apply_selected_diff_hunks(
19536        &mut self,
19537        _: &ApplyDiffHunk,
19538        window: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19542        let snapshot = self.snapshot(window, cx);
19543        let hunks = snapshot.hunks_for_ranges(
19544            self.selections
19545                .all(&snapshot.display_snapshot)
19546                .into_iter()
19547                .map(|selection| selection.range()),
19548        );
19549        let mut ranges_by_buffer = HashMap::default();
19550        self.transact(window, cx, |editor, _window, cx| {
19551            for hunk in hunks {
19552                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19553                    ranges_by_buffer
19554                        .entry(buffer.clone())
19555                        .or_insert_with(Vec::new)
19556                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19557                }
19558            }
19559
19560            for (buffer, ranges) in ranges_by_buffer {
19561                buffer.update(cx, |buffer, cx| {
19562                    buffer.merge_into_base(ranges, cx);
19563                });
19564            }
19565        });
19566
19567        if let Some(project) = self.project.clone() {
19568            self.save(
19569                SaveOptions {
19570                    format: true,
19571                    autosave: false,
19572                },
19573                project,
19574                window,
19575                cx,
19576            )
19577            .detach_and_log_err(cx);
19578        }
19579    }
19580
19581    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19582        if hovered != self.gutter_hovered {
19583            self.gutter_hovered = hovered;
19584            cx.notify();
19585        }
19586    }
19587
19588    pub fn insert_blocks(
19589        &mut self,
19590        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19591        autoscroll: Option<Autoscroll>,
19592        cx: &mut Context<Self>,
19593    ) -> Vec<CustomBlockId> {
19594        let blocks = self
19595            .display_map
19596            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19597        if let Some(autoscroll) = autoscroll {
19598            self.request_autoscroll(autoscroll, cx);
19599        }
19600        cx.notify();
19601        blocks
19602    }
19603
19604    pub fn resize_blocks(
19605        &mut self,
19606        heights: HashMap<CustomBlockId, u32>,
19607        autoscroll: Option<Autoscroll>,
19608        cx: &mut Context<Self>,
19609    ) {
19610        self.display_map
19611            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19612        if let Some(autoscroll) = autoscroll {
19613            self.request_autoscroll(autoscroll, cx);
19614        }
19615        cx.notify();
19616    }
19617
19618    pub fn replace_blocks(
19619        &mut self,
19620        renderers: HashMap<CustomBlockId, RenderBlock>,
19621        autoscroll: Option<Autoscroll>,
19622        cx: &mut Context<Self>,
19623    ) {
19624        self.display_map
19625            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19626        if let Some(autoscroll) = autoscroll {
19627            self.request_autoscroll(autoscroll, cx);
19628        }
19629        cx.notify();
19630    }
19631
19632    pub fn remove_blocks(
19633        &mut self,
19634        block_ids: HashSet<CustomBlockId>,
19635        autoscroll: Option<Autoscroll>,
19636        cx: &mut Context<Self>,
19637    ) {
19638        self.display_map.update(cx, |display_map, cx| {
19639            display_map.remove_blocks(block_ids, cx)
19640        });
19641        if let Some(autoscroll) = autoscroll {
19642            self.request_autoscroll(autoscroll, cx);
19643        }
19644        cx.notify();
19645    }
19646
19647    pub fn row_for_block(
19648        &self,
19649        block_id: CustomBlockId,
19650        cx: &mut Context<Self>,
19651    ) -> Option<DisplayRow> {
19652        self.display_map
19653            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19654    }
19655
19656    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19657        self.focused_block = Some(focused_block);
19658    }
19659
19660    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19661        self.focused_block.take()
19662    }
19663
19664    pub fn insert_creases(
19665        &mut self,
19666        creases: impl IntoIterator<Item = Crease<Anchor>>,
19667        cx: &mut Context<Self>,
19668    ) -> Vec<CreaseId> {
19669        self.display_map
19670            .update(cx, |map, cx| map.insert_creases(creases, cx))
19671    }
19672
19673    pub fn remove_creases(
19674        &mut self,
19675        ids: impl IntoIterator<Item = CreaseId>,
19676        cx: &mut Context<Self>,
19677    ) -> Vec<(CreaseId, Range<Anchor>)> {
19678        self.display_map
19679            .update(cx, |map, cx| map.remove_creases(ids, cx))
19680    }
19681
19682    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19683        self.display_map
19684            .update(cx, |map, cx| map.snapshot(cx))
19685            .longest_row()
19686    }
19687
19688    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19689        self.display_map
19690            .update(cx, |map, cx| map.snapshot(cx))
19691            .max_point()
19692    }
19693
19694    pub fn text(&self, cx: &App) -> String {
19695        self.buffer.read(cx).read(cx).text()
19696    }
19697
19698    pub fn is_empty(&self, cx: &App) -> bool {
19699        self.buffer.read(cx).read(cx).is_empty()
19700    }
19701
19702    pub fn text_option(&self, cx: &App) -> Option<String> {
19703        let text = self.text(cx);
19704        let text = text.trim();
19705
19706        if text.is_empty() {
19707            return None;
19708        }
19709
19710        Some(text.to_string())
19711    }
19712
19713    pub fn set_text(
19714        &mut self,
19715        text: impl Into<Arc<str>>,
19716        window: &mut Window,
19717        cx: &mut Context<Self>,
19718    ) {
19719        self.transact(window, cx, |this, _, cx| {
19720            this.buffer
19721                .read(cx)
19722                .as_singleton()
19723                .expect("you can only call set_text on editors for singleton buffers")
19724                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19725        });
19726    }
19727
19728    pub fn display_text(&self, cx: &mut App) -> String {
19729        self.display_map
19730            .update(cx, |map, cx| map.snapshot(cx))
19731            .text()
19732    }
19733
19734    fn create_minimap(
19735        &self,
19736        minimap_settings: MinimapSettings,
19737        window: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) -> Option<Entity<Self>> {
19740        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19741            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19742    }
19743
19744    fn initialize_new_minimap(
19745        &self,
19746        minimap_settings: MinimapSettings,
19747        window: &mut Window,
19748        cx: &mut Context<Self>,
19749    ) -> Entity<Self> {
19750        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19751
19752        let mut minimap = Editor::new_internal(
19753            EditorMode::Minimap {
19754                parent: cx.weak_entity(),
19755            },
19756            self.buffer.clone(),
19757            None,
19758            Some(self.display_map.clone()),
19759            window,
19760            cx,
19761        );
19762        minimap.scroll_manager.clone_state(&self.scroll_manager);
19763        minimap.set_text_style_refinement(TextStyleRefinement {
19764            font_size: Some(MINIMAP_FONT_SIZE),
19765            font_weight: Some(MINIMAP_FONT_WEIGHT),
19766            ..Default::default()
19767        });
19768        minimap.update_minimap_configuration(minimap_settings, cx);
19769        cx.new(|_| minimap)
19770    }
19771
19772    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19773        let current_line_highlight = minimap_settings
19774            .current_line_highlight
19775            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19776        self.set_current_line_highlight(Some(current_line_highlight));
19777    }
19778
19779    pub fn minimap(&self) -> Option<&Entity<Self>> {
19780        self.minimap
19781            .as_ref()
19782            .filter(|_| self.minimap_visibility.visible())
19783    }
19784
19785    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19786        let mut wrap_guides = smallvec![];
19787
19788        if self.show_wrap_guides == Some(false) {
19789            return wrap_guides;
19790        }
19791
19792        let settings = self.buffer.read(cx).language_settings(cx);
19793        if settings.show_wrap_guides {
19794            match self.soft_wrap_mode(cx) {
19795                SoftWrap::Column(soft_wrap) => {
19796                    wrap_guides.push((soft_wrap as usize, true));
19797                }
19798                SoftWrap::Bounded(soft_wrap) => {
19799                    wrap_guides.push((soft_wrap as usize, true));
19800                }
19801                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19802            }
19803            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19804        }
19805
19806        wrap_guides
19807    }
19808
19809    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19810        let settings = self.buffer.read(cx).language_settings(cx);
19811        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19812        match mode {
19813            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19814                SoftWrap::None
19815            }
19816            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19817            language_settings::SoftWrap::PreferredLineLength => {
19818                SoftWrap::Column(settings.preferred_line_length)
19819            }
19820            language_settings::SoftWrap::Bounded => {
19821                SoftWrap::Bounded(settings.preferred_line_length)
19822            }
19823        }
19824    }
19825
19826    pub fn set_soft_wrap_mode(
19827        &mut self,
19828        mode: language_settings::SoftWrap,
19829
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.soft_wrap_mode_override = Some(mode);
19833        cx.notify();
19834    }
19835
19836    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19837        self.hard_wrap = hard_wrap;
19838        cx.notify();
19839    }
19840
19841    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19842        self.text_style_refinement = Some(style);
19843    }
19844
19845    /// called by the Element so we know what style we were most recently rendered with.
19846    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19847        // We intentionally do not inform the display map about the minimap style
19848        // so that wrapping is not recalculated and stays consistent for the editor
19849        // and its linked minimap.
19850        if !self.mode.is_minimap() {
19851            let font = style.text.font();
19852            let font_size = style.text.font_size.to_pixels(window.rem_size());
19853            let display_map = self
19854                .placeholder_display_map
19855                .as_ref()
19856                .filter(|_| self.is_empty(cx))
19857                .unwrap_or(&self.display_map);
19858
19859            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19860        }
19861        self.style = Some(style);
19862    }
19863
19864    pub fn style(&self) -> Option<&EditorStyle> {
19865        self.style.as_ref()
19866    }
19867
19868    // Called by the element. This method is not designed to be called outside of the editor
19869    // element's layout code because it does not notify when rewrapping is computed synchronously.
19870    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19871        if self.is_empty(cx) {
19872            self.placeholder_display_map
19873                .as_ref()
19874                .map_or(false, |display_map| {
19875                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19876                })
19877        } else {
19878            self.display_map
19879                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19880        }
19881    }
19882
19883    pub fn set_soft_wrap(&mut self) {
19884        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19885    }
19886
19887    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19888        if self.soft_wrap_mode_override.is_some() {
19889            self.soft_wrap_mode_override.take();
19890        } else {
19891            let soft_wrap = match self.soft_wrap_mode(cx) {
19892                SoftWrap::GitDiff => return,
19893                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19894                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19895                    language_settings::SoftWrap::None
19896                }
19897            };
19898            self.soft_wrap_mode_override = Some(soft_wrap);
19899        }
19900        cx.notify();
19901    }
19902
19903    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19904        let Some(workspace) = self.workspace() else {
19905            return;
19906        };
19907        let fs = workspace.read(cx).app_state().fs.clone();
19908        let current_show = TabBarSettings::get_global(cx).show;
19909        update_settings_file(fs, cx, move |setting, _| {
19910            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19911        });
19912    }
19913
19914    pub fn toggle_indent_guides(
19915        &mut self,
19916        _: &ToggleIndentGuides,
19917        _: &mut Window,
19918        cx: &mut Context<Self>,
19919    ) {
19920        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19921            self.buffer
19922                .read(cx)
19923                .language_settings(cx)
19924                .indent_guides
19925                .enabled
19926        });
19927        self.show_indent_guides = Some(!currently_enabled);
19928        cx.notify();
19929    }
19930
19931    fn should_show_indent_guides(&self) -> Option<bool> {
19932        self.show_indent_guides
19933    }
19934
19935    pub fn toggle_line_numbers(
19936        &mut self,
19937        _: &ToggleLineNumbers,
19938        _: &mut Window,
19939        cx: &mut Context<Self>,
19940    ) {
19941        let mut editor_settings = EditorSettings::get_global(cx).clone();
19942        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19943        EditorSettings::override_global(editor_settings, cx);
19944    }
19945
19946    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19947        if let Some(show_line_numbers) = self.show_line_numbers {
19948            return show_line_numbers;
19949        }
19950        EditorSettings::get_global(cx).gutter.line_numbers
19951    }
19952
19953    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19954        match (
19955            self.use_relative_line_numbers,
19956            EditorSettings::get_global(cx).relative_line_numbers,
19957        ) {
19958            (None, setting) => setting,
19959            (Some(false), _) => RelativeLineNumbers::Disabled,
19960            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19961            (Some(true), _) => RelativeLineNumbers::Enabled,
19962        }
19963    }
19964
19965    pub fn toggle_relative_line_numbers(
19966        &mut self,
19967        _: &ToggleRelativeLineNumbers,
19968        _: &mut Window,
19969        cx: &mut Context<Self>,
19970    ) {
19971        let is_relative = self.relative_line_numbers(cx);
19972        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19973    }
19974
19975    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19976        self.use_relative_line_numbers = is_relative;
19977        cx.notify();
19978    }
19979
19980    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19981        self.show_gutter = show_gutter;
19982        cx.notify();
19983    }
19984
19985    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19986        self.show_scrollbars = ScrollbarAxes {
19987            horizontal: show,
19988            vertical: show,
19989        };
19990        cx.notify();
19991    }
19992
19993    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19994        self.show_scrollbars.vertical = show;
19995        cx.notify();
19996    }
19997
19998    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19999        self.show_scrollbars.horizontal = show;
20000        cx.notify();
20001    }
20002
20003    pub fn set_minimap_visibility(
20004        &mut self,
20005        minimap_visibility: MinimapVisibility,
20006        window: &mut Window,
20007        cx: &mut Context<Self>,
20008    ) {
20009        if self.minimap_visibility != minimap_visibility {
20010            if minimap_visibility.visible() && self.minimap.is_none() {
20011                let minimap_settings = EditorSettings::get_global(cx).minimap;
20012                self.minimap =
20013                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20014            }
20015            self.minimap_visibility = minimap_visibility;
20016            cx.notify();
20017        }
20018    }
20019
20020    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20021        self.set_show_scrollbars(false, cx);
20022        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20023    }
20024
20025    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20026        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20027    }
20028
20029    /// Normally the text in full mode and auto height editors is padded on the
20030    /// left side by roughly half a character width for improved hit testing.
20031    ///
20032    /// Use this method to disable this for cases where this is not wanted (e.g.
20033    /// if you want to align the editor text with some other text above or below)
20034    /// or if you want to add this padding to single-line editors.
20035    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20036        self.offset_content = offset_content;
20037        cx.notify();
20038    }
20039
20040    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20041        self.show_line_numbers = Some(show_line_numbers);
20042        cx.notify();
20043    }
20044
20045    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20046        self.disable_expand_excerpt_buttons = true;
20047        cx.notify();
20048    }
20049
20050    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20051        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20052        cx.notify();
20053    }
20054
20055    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20056        self.show_code_actions = Some(show_code_actions);
20057        cx.notify();
20058    }
20059
20060    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20061        self.show_runnables = Some(show_runnables);
20062        cx.notify();
20063    }
20064
20065    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20066        self.show_breakpoints = Some(show_breakpoints);
20067        cx.notify();
20068    }
20069
20070    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20071        if self.display_map.read(cx).masked != masked {
20072            self.display_map.update(cx, |map, _| map.masked = masked);
20073        }
20074        cx.notify()
20075    }
20076
20077    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20078        self.show_wrap_guides = Some(show_wrap_guides);
20079        cx.notify();
20080    }
20081
20082    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20083        self.show_indent_guides = Some(show_indent_guides);
20084        cx.notify();
20085    }
20086
20087    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20088        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20089            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20090                && let Some(dir) = file.abs_path(cx).parent()
20091            {
20092                return Some(dir.to_owned());
20093            }
20094        }
20095
20096        None
20097    }
20098
20099    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20100        self.active_excerpt(cx)?
20101            .1
20102            .read(cx)
20103            .file()
20104            .and_then(|f| f.as_local())
20105    }
20106
20107    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20108        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20109            let buffer = buffer.read(cx);
20110            if let Some(project_path) = buffer.project_path(cx) {
20111                let project = self.project()?.read(cx);
20112                project.absolute_path(&project_path, cx)
20113            } else {
20114                buffer
20115                    .file()
20116                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20117            }
20118        })
20119    }
20120
20121    pub fn reveal_in_finder(
20122        &mut self,
20123        _: &RevealInFileManager,
20124        _window: &mut Window,
20125        cx: &mut Context<Self>,
20126    ) {
20127        if let Some(target) = self.target_file(cx) {
20128            cx.reveal_path(&target.abs_path(cx));
20129        }
20130    }
20131
20132    pub fn copy_path(
20133        &mut self,
20134        _: &zed_actions::workspace::CopyPath,
20135        _window: &mut Window,
20136        cx: &mut Context<Self>,
20137    ) {
20138        if let Some(path) = self.target_file_abs_path(cx)
20139            && let Some(path) = path.to_str()
20140        {
20141            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20142        } else {
20143            cx.propagate();
20144        }
20145    }
20146
20147    pub fn copy_relative_path(
20148        &mut self,
20149        _: &zed_actions::workspace::CopyRelativePath,
20150        _window: &mut Window,
20151        cx: &mut Context<Self>,
20152    ) {
20153        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20154            let project = self.project()?.read(cx);
20155            let path = buffer.read(cx).file()?.path();
20156            let path = path.display(project.path_style(cx));
20157            Some(path)
20158        }) {
20159            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20160        } else {
20161            cx.propagate();
20162        }
20163    }
20164
20165    /// Returns the project path for the editor's buffer, if any buffer is
20166    /// opened in the editor.
20167    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20168        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20169            buffer.read(cx).project_path(cx)
20170        } else {
20171            None
20172        }
20173    }
20174
20175    // Returns true if the editor handled a go-to-line request
20176    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20177        maybe!({
20178            let breakpoint_store = self.breakpoint_store.as_ref()?;
20179
20180            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20181            else {
20182                self.clear_row_highlights::<ActiveDebugLine>();
20183                return None;
20184            };
20185
20186            let position = active_stack_frame.position;
20187            let buffer_id = position.buffer_id?;
20188            let snapshot = self
20189                .project
20190                .as_ref()?
20191                .read(cx)
20192                .buffer_for_id(buffer_id, cx)?
20193                .read(cx)
20194                .snapshot();
20195
20196            let mut handled = false;
20197            for (id, ExcerptRange { context, .. }) in
20198                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20199            {
20200                if context.start.cmp(&position, &snapshot).is_ge()
20201                    || context.end.cmp(&position, &snapshot).is_lt()
20202                {
20203                    continue;
20204                }
20205                let snapshot = self.buffer.read(cx).snapshot(cx);
20206                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20207
20208                handled = true;
20209                self.clear_row_highlights::<ActiveDebugLine>();
20210
20211                self.go_to_line::<ActiveDebugLine>(
20212                    multibuffer_anchor,
20213                    Some(cx.theme().colors().editor_debugger_active_line_background),
20214                    window,
20215                    cx,
20216                );
20217
20218                cx.notify();
20219            }
20220
20221            handled.then_some(())
20222        })
20223        .is_some()
20224    }
20225
20226    pub fn copy_file_name_without_extension(
20227        &mut self,
20228        _: &CopyFileNameWithoutExtension,
20229        _: &mut Window,
20230        cx: &mut Context<Self>,
20231    ) {
20232        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20233            let file = buffer.read(cx).file()?;
20234            file.path().file_stem()
20235        }) {
20236            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20237        }
20238    }
20239
20240    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20241        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20242            let file = buffer.read(cx).file()?;
20243            Some(file.file_name(cx))
20244        }) {
20245            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20246        }
20247    }
20248
20249    pub fn toggle_git_blame(
20250        &mut self,
20251        _: &::git::Blame,
20252        window: &mut Window,
20253        cx: &mut Context<Self>,
20254    ) {
20255        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20256
20257        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20258            self.start_git_blame(true, window, cx);
20259        }
20260
20261        cx.notify();
20262    }
20263
20264    pub fn toggle_git_blame_inline(
20265        &mut self,
20266        _: &ToggleGitBlameInline,
20267        window: &mut Window,
20268        cx: &mut Context<Self>,
20269    ) {
20270        self.toggle_git_blame_inline_internal(true, window, cx);
20271        cx.notify();
20272    }
20273
20274    pub fn open_git_blame_commit(
20275        &mut self,
20276        _: &OpenGitBlameCommit,
20277        window: &mut Window,
20278        cx: &mut Context<Self>,
20279    ) {
20280        self.open_git_blame_commit_internal(window, cx);
20281    }
20282
20283    fn open_git_blame_commit_internal(
20284        &mut self,
20285        window: &mut Window,
20286        cx: &mut Context<Self>,
20287    ) -> Option<()> {
20288        let blame = self.blame.as_ref()?;
20289        let snapshot = self.snapshot(window, cx);
20290        let cursor = self
20291            .selections
20292            .newest::<Point>(&snapshot.display_snapshot)
20293            .head();
20294        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20295        let (_, blame_entry) = blame
20296            .update(cx, |blame, cx| {
20297                blame
20298                    .blame_for_rows(
20299                        &[RowInfo {
20300                            buffer_id: Some(buffer.remote_id()),
20301                            buffer_row: Some(point.row),
20302                            ..Default::default()
20303                        }],
20304                        cx,
20305                    )
20306                    .next()
20307            })
20308            .flatten()?;
20309        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20310        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20311        let workspace = self.workspace()?.downgrade();
20312        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20313        None
20314    }
20315
20316    pub fn git_blame_inline_enabled(&self) -> bool {
20317        self.git_blame_inline_enabled
20318    }
20319
20320    pub fn toggle_selection_menu(
20321        &mut self,
20322        _: &ToggleSelectionMenu,
20323        _: &mut Window,
20324        cx: &mut Context<Self>,
20325    ) {
20326        self.show_selection_menu = self
20327            .show_selection_menu
20328            .map(|show_selections_menu| !show_selections_menu)
20329            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20330
20331        cx.notify();
20332    }
20333
20334    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20335        self.show_selection_menu
20336            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20337    }
20338
20339    fn start_git_blame(
20340        &mut self,
20341        user_triggered: bool,
20342        window: &mut Window,
20343        cx: &mut Context<Self>,
20344    ) {
20345        if let Some(project) = self.project() {
20346            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20347                && buffer.read(cx).file().is_none()
20348            {
20349                return;
20350            }
20351
20352            let focused = self.focus_handle(cx).contains_focused(window, cx);
20353
20354            let project = project.clone();
20355            let blame = cx
20356                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20357            self.blame_subscription =
20358                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20359            self.blame = Some(blame);
20360        }
20361    }
20362
20363    fn toggle_git_blame_inline_internal(
20364        &mut self,
20365        user_triggered: bool,
20366        window: &mut Window,
20367        cx: &mut Context<Self>,
20368    ) {
20369        if self.git_blame_inline_enabled {
20370            self.git_blame_inline_enabled = false;
20371            self.show_git_blame_inline = false;
20372            self.show_git_blame_inline_delay_task.take();
20373        } else {
20374            self.git_blame_inline_enabled = true;
20375            self.start_git_blame_inline(user_triggered, window, cx);
20376        }
20377
20378        cx.notify();
20379    }
20380
20381    fn start_git_blame_inline(
20382        &mut self,
20383        user_triggered: bool,
20384        window: &mut Window,
20385        cx: &mut Context<Self>,
20386    ) {
20387        self.start_git_blame(user_triggered, window, cx);
20388
20389        if ProjectSettings::get_global(cx)
20390            .git
20391            .inline_blame_delay()
20392            .is_some()
20393        {
20394            self.start_inline_blame_timer(window, cx);
20395        } else {
20396            self.show_git_blame_inline = true
20397        }
20398    }
20399
20400    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20401        self.blame.as_ref()
20402    }
20403
20404    pub fn show_git_blame_gutter(&self) -> bool {
20405        self.show_git_blame_gutter
20406    }
20407
20408    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20409        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20410    }
20411
20412    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20413        self.show_git_blame_inline
20414            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20415            && !self.newest_selection_head_on_empty_line(cx)
20416            && self.has_blame_entries(cx)
20417    }
20418
20419    fn has_blame_entries(&self, cx: &App) -> bool {
20420        self.blame()
20421            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20422    }
20423
20424    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20425        let cursor_anchor = self.selections.newest_anchor().head();
20426
20427        let snapshot = self.buffer.read(cx).snapshot(cx);
20428        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20429
20430        snapshot.line_len(buffer_row) == 0
20431    }
20432
20433    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20434        let buffer_and_selection = maybe!({
20435            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20436            let selection_range = selection.range();
20437
20438            let multi_buffer = self.buffer().read(cx);
20439            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20440            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20441
20442            let (buffer, range, _) = if selection.reversed {
20443                buffer_ranges.first()
20444            } else {
20445                buffer_ranges.last()
20446            }?;
20447
20448            let selection = text::ToPoint::to_point(&range.start, buffer).row
20449                ..text::ToPoint::to_point(&range.end, buffer).row;
20450            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20451        });
20452
20453        let Some((buffer, selection)) = buffer_and_selection else {
20454            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20455        };
20456
20457        let Some(project) = self.project() else {
20458            return Task::ready(Err(anyhow!("editor does not have project")));
20459        };
20460
20461        project.update(cx, |project, cx| {
20462            project.get_permalink_to_line(&buffer, selection, cx)
20463        })
20464    }
20465
20466    pub fn copy_permalink_to_line(
20467        &mut self,
20468        _: &CopyPermalinkToLine,
20469        window: &mut Window,
20470        cx: &mut Context<Self>,
20471    ) {
20472        let permalink_task = self.get_permalink_to_line(cx);
20473        let workspace = self.workspace();
20474
20475        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20476            Ok(permalink) => {
20477                cx.update(|_, cx| {
20478                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20479                })
20480                .ok();
20481            }
20482            Err(err) => {
20483                let message = format!("Failed to copy permalink: {err}");
20484
20485                anyhow::Result::<()>::Err(err).log_err();
20486
20487                if let Some(workspace) = workspace {
20488                    workspace
20489                        .update_in(cx, |workspace, _, cx| {
20490                            struct CopyPermalinkToLine;
20491
20492                            workspace.show_toast(
20493                                Toast::new(
20494                                    NotificationId::unique::<CopyPermalinkToLine>(),
20495                                    message,
20496                                ),
20497                                cx,
20498                            )
20499                        })
20500                        .ok();
20501                }
20502            }
20503        })
20504        .detach();
20505    }
20506
20507    pub fn copy_file_location(
20508        &mut self,
20509        _: &CopyFileLocation,
20510        _: &mut Window,
20511        cx: &mut Context<Self>,
20512    ) {
20513        let selection = self
20514            .selections
20515            .newest::<Point>(&self.display_snapshot(cx))
20516            .start
20517            .row
20518            + 1;
20519        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20520            let project = self.project()?.read(cx);
20521            let file = buffer.read(cx).file()?;
20522            let path = file.path().display(project.path_style(cx));
20523
20524            Some(format!("{path}:{selection}"))
20525        }) {
20526            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20527        }
20528    }
20529
20530    pub fn open_permalink_to_line(
20531        &mut self,
20532        _: &OpenPermalinkToLine,
20533        window: &mut Window,
20534        cx: &mut Context<Self>,
20535    ) {
20536        let permalink_task = self.get_permalink_to_line(cx);
20537        let workspace = self.workspace();
20538
20539        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20540            Ok(permalink) => {
20541                cx.update(|_, cx| {
20542                    cx.open_url(permalink.as_ref());
20543                })
20544                .ok();
20545            }
20546            Err(err) => {
20547                let message = format!("Failed to open permalink: {err}");
20548
20549                anyhow::Result::<()>::Err(err).log_err();
20550
20551                if let Some(workspace) = workspace {
20552                    workspace
20553                        .update(cx, |workspace, cx| {
20554                            struct OpenPermalinkToLine;
20555
20556                            workspace.show_toast(
20557                                Toast::new(
20558                                    NotificationId::unique::<OpenPermalinkToLine>(),
20559                                    message,
20560                                ),
20561                                cx,
20562                            )
20563                        })
20564                        .ok();
20565                }
20566            }
20567        })
20568        .detach();
20569    }
20570
20571    pub fn insert_uuid_v4(
20572        &mut self,
20573        _: &InsertUuidV4,
20574        window: &mut Window,
20575        cx: &mut Context<Self>,
20576    ) {
20577        self.insert_uuid(UuidVersion::V4, window, cx);
20578    }
20579
20580    pub fn insert_uuid_v7(
20581        &mut self,
20582        _: &InsertUuidV7,
20583        window: &mut Window,
20584        cx: &mut Context<Self>,
20585    ) {
20586        self.insert_uuid(UuidVersion::V7, window, cx);
20587    }
20588
20589    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20591        self.transact(window, cx, |this, window, cx| {
20592            let edits = this
20593                .selections
20594                .all::<Point>(&this.display_snapshot(cx))
20595                .into_iter()
20596                .map(|selection| {
20597                    let uuid = match version {
20598                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20599                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20600                    };
20601
20602                    (selection.range(), uuid.to_string())
20603                });
20604            this.edit(edits, cx);
20605            this.refresh_edit_prediction(true, false, window, cx);
20606        });
20607    }
20608
20609    pub fn open_selections_in_multibuffer(
20610        &mut self,
20611        _: &OpenSelectionsInMultibuffer,
20612        window: &mut Window,
20613        cx: &mut Context<Self>,
20614    ) {
20615        let multibuffer = self.buffer.read(cx);
20616
20617        let Some(buffer) = multibuffer.as_singleton() else {
20618            return;
20619        };
20620
20621        let Some(workspace) = self.workspace() else {
20622            return;
20623        };
20624
20625        let title = multibuffer.title(cx).to_string();
20626
20627        let locations = self
20628            .selections
20629            .all_anchors(&self.display_snapshot(cx))
20630            .iter()
20631            .map(|selection| {
20632                (
20633                    buffer.clone(),
20634                    (selection.start.text_anchor..selection.end.text_anchor)
20635                        .to_point(buffer.read(cx)),
20636                )
20637            })
20638            .into_group_map();
20639
20640        cx.spawn_in(window, async move |_, cx| {
20641            workspace.update_in(cx, |workspace, window, cx| {
20642                Self::open_locations_in_multibuffer(
20643                    workspace,
20644                    locations,
20645                    format!("Selections for '{title}'"),
20646                    false,
20647                    MultibufferSelectionMode::All,
20648                    window,
20649                    cx,
20650                );
20651            })
20652        })
20653        .detach();
20654    }
20655
20656    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20657    /// last highlight added will be used.
20658    ///
20659    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20660    pub fn highlight_rows<T: 'static>(
20661        &mut self,
20662        range: Range<Anchor>,
20663        color: Hsla,
20664        options: RowHighlightOptions,
20665        cx: &mut Context<Self>,
20666    ) {
20667        let snapshot = self.buffer().read(cx).snapshot(cx);
20668        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20669        let ix = row_highlights.binary_search_by(|highlight| {
20670            Ordering::Equal
20671                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20672                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20673        });
20674
20675        if let Err(mut ix) = ix {
20676            let index = post_inc(&mut self.highlight_order);
20677
20678            // If this range intersects with the preceding highlight, then merge it with
20679            // the preceding highlight. Otherwise insert a new highlight.
20680            let mut merged = false;
20681            if ix > 0 {
20682                let prev_highlight = &mut row_highlights[ix - 1];
20683                if prev_highlight
20684                    .range
20685                    .end
20686                    .cmp(&range.start, &snapshot)
20687                    .is_ge()
20688                {
20689                    ix -= 1;
20690                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20691                        prev_highlight.range.end = range.end;
20692                    }
20693                    merged = true;
20694                    prev_highlight.index = index;
20695                    prev_highlight.color = color;
20696                    prev_highlight.options = options;
20697                }
20698            }
20699
20700            if !merged {
20701                row_highlights.insert(
20702                    ix,
20703                    RowHighlight {
20704                        range,
20705                        index,
20706                        color,
20707                        options,
20708                        type_id: TypeId::of::<T>(),
20709                    },
20710                );
20711            }
20712
20713            // If any of the following highlights intersect with this one, merge them.
20714            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20715                let highlight = &row_highlights[ix];
20716                if next_highlight
20717                    .range
20718                    .start
20719                    .cmp(&highlight.range.end, &snapshot)
20720                    .is_le()
20721                {
20722                    if next_highlight
20723                        .range
20724                        .end
20725                        .cmp(&highlight.range.end, &snapshot)
20726                        .is_gt()
20727                    {
20728                        row_highlights[ix].range.end = next_highlight.range.end;
20729                    }
20730                    row_highlights.remove(ix + 1);
20731                } else {
20732                    break;
20733                }
20734            }
20735        }
20736    }
20737
20738    /// Remove any highlighted row ranges of the given type that intersect the
20739    /// given ranges.
20740    pub fn remove_highlighted_rows<T: 'static>(
20741        &mut self,
20742        ranges_to_remove: Vec<Range<Anchor>>,
20743        cx: &mut Context<Self>,
20744    ) {
20745        let snapshot = self.buffer().read(cx).snapshot(cx);
20746        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20747        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20748        row_highlights.retain(|highlight| {
20749            while let Some(range_to_remove) = ranges_to_remove.peek() {
20750                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20751                    Ordering::Less | Ordering::Equal => {
20752                        ranges_to_remove.next();
20753                    }
20754                    Ordering::Greater => {
20755                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20756                            Ordering::Less | Ordering::Equal => {
20757                                return false;
20758                            }
20759                            Ordering::Greater => break,
20760                        }
20761                    }
20762                }
20763            }
20764
20765            true
20766        })
20767    }
20768
20769    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20770    pub fn clear_row_highlights<T: 'static>(&mut self) {
20771        self.highlighted_rows.remove(&TypeId::of::<T>());
20772    }
20773
20774    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20775    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20776        self.highlighted_rows
20777            .get(&TypeId::of::<T>())
20778            .map_or(&[] as &[_], |vec| vec.as_slice())
20779            .iter()
20780            .map(|highlight| (highlight.range.clone(), highlight.color))
20781    }
20782
20783    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20784    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20785    /// Allows to ignore certain kinds of highlights.
20786    pub fn highlighted_display_rows(
20787        &self,
20788        window: &mut Window,
20789        cx: &mut App,
20790    ) -> BTreeMap<DisplayRow, LineHighlight> {
20791        let snapshot = self.snapshot(window, cx);
20792        let mut used_highlight_orders = HashMap::default();
20793        self.highlighted_rows
20794            .iter()
20795            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20796            .fold(
20797                BTreeMap::<DisplayRow, LineHighlight>::new(),
20798                |mut unique_rows, highlight| {
20799                    let start = highlight.range.start.to_display_point(&snapshot);
20800                    let end = highlight.range.end.to_display_point(&snapshot);
20801                    let start_row = start.row().0;
20802                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20803                    {
20804                        end.row().0.saturating_sub(1)
20805                    } else {
20806                        end.row().0
20807                    };
20808                    for row in start_row..=end_row {
20809                        let used_index =
20810                            used_highlight_orders.entry(row).or_insert(highlight.index);
20811                        if highlight.index >= *used_index {
20812                            *used_index = highlight.index;
20813                            unique_rows.insert(
20814                                DisplayRow(row),
20815                                LineHighlight {
20816                                    include_gutter: highlight.options.include_gutter,
20817                                    border: None,
20818                                    background: highlight.color.into(),
20819                                    type_id: Some(highlight.type_id),
20820                                },
20821                            );
20822                        }
20823                    }
20824                    unique_rows
20825                },
20826            )
20827    }
20828
20829    pub fn highlighted_display_row_for_autoscroll(
20830        &self,
20831        snapshot: &DisplaySnapshot,
20832    ) -> Option<DisplayRow> {
20833        self.highlighted_rows
20834            .values()
20835            .flat_map(|highlighted_rows| highlighted_rows.iter())
20836            .filter_map(|highlight| {
20837                if highlight.options.autoscroll {
20838                    Some(highlight.range.start.to_display_point(snapshot).row())
20839                } else {
20840                    None
20841                }
20842            })
20843            .min()
20844    }
20845
20846    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20847        self.highlight_background::<SearchWithinRange>(
20848            ranges,
20849            |colors| colors.colors().editor_document_highlight_read_background,
20850            cx,
20851        )
20852    }
20853
20854    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20855        self.breadcrumb_header = Some(new_header);
20856    }
20857
20858    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20859        self.clear_background_highlights::<SearchWithinRange>(cx);
20860    }
20861
20862    pub fn highlight_background<T: 'static>(
20863        &mut self,
20864        ranges: &[Range<Anchor>],
20865        color_fetcher: fn(&Theme) -> Hsla,
20866        cx: &mut Context<Self>,
20867    ) {
20868        self.background_highlights.insert(
20869            HighlightKey::Type(TypeId::of::<T>()),
20870            (color_fetcher, Arc::from(ranges)),
20871        );
20872        self.scrollbar_marker_state.dirty = true;
20873        cx.notify();
20874    }
20875
20876    pub fn highlight_background_key<T: 'static>(
20877        &mut self,
20878        key: usize,
20879        ranges: &[Range<Anchor>],
20880        color_fetcher: fn(&Theme) -> Hsla,
20881        cx: &mut Context<Self>,
20882    ) {
20883        self.background_highlights.insert(
20884            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20885            (color_fetcher, Arc::from(ranges)),
20886        );
20887        self.scrollbar_marker_state.dirty = true;
20888        cx.notify();
20889    }
20890
20891    pub fn clear_background_highlights<T: 'static>(
20892        &mut self,
20893        cx: &mut Context<Self>,
20894    ) -> Option<BackgroundHighlight> {
20895        let text_highlights = self
20896            .background_highlights
20897            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20898        if !text_highlights.1.is_empty() {
20899            self.scrollbar_marker_state.dirty = true;
20900            cx.notify();
20901        }
20902        Some(text_highlights)
20903    }
20904
20905    pub fn highlight_gutter<T: 'static>(
20906        &mut self,
20907        ranges: impl Into<Vec<Range<Anchor>>>,
20908        color_fetcher: fn(&App) -> Hsla,
20909        cx: &mut Context<Self>,
20910    ) {
20911        self.gutter_highlights
20912            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20913        cx.notify();
20914    }
20915
20916    pub fn clear_gutter_highlights<T: 'static>(
20917        &mut self,
20918        cx: &mut Context<Self>,
20919    ) -> Option<GutterHighlight> {
20920        cx.notify();
20921        self.gutter_highlights.remove(&TypeId::of::<T>())
20922    }
20923
20924    pub fn insert_gutter_highlight<T: 'static>(
20925        &mut self,
20926        range: Range<Anchor>,
20927        color_fetcher: fn(&App) -> Hsla,
20928        cx: &mut Context<Self>,
20929    ) {
20930        let snapshot = self.buffer().read(cx).snapshot(cx);
20931        let mut highlights = self
20932            .gutter_highlights
20933            .remove(&TypeId::of::<T>())
20934            .map(|(_, highlights)| highlights)
20935            .unwrap_or_default();
20936        let ix = highlights.binary_search_by(|highlight| {
20937            Ordering::Equal
20938                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20939                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20940        });
20941        if let Err(ix) = ix {
20942            highlights.insert(ix, range);
20943        }
20944        self.gutter_highlights
20945            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20946    }
20947
20948    pub fn remove_gutter_highlights<T: 'static>(
20949        &mut self,
20950        ranges_to_remove: Vec<Range<Anchor>>,
20951        cx: &mut Context<Self>,
20952    ) {
20953        let snapshot = self.buffer().read(cx).snapshot(cx);
20954        let Some((color_fetcher, mut gutter_highlights)) =
20955            self.gutter_highlights.remove(&TypeId::of::<T>())
20956        else {
20957            return;
20958        };
20959        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20960        gutter_highlights.retain(|highlight| {
20961            while let Some(range_to_remove) = ranges_to_remove.peek() {
20962                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20963                    Ordering::Less | Ordering::Equal => {
20964                        ranges_to_remove.next();
20965                    }
20966                    Ordering::Greater => {
20967                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20968                            Ordering::Less | Ordering::Equal => {
20969                                return false;
20970                            }
20971                            Ordering::Greater => break,
20972                        }
20973                    }
20974                }
20975            }
20976
20977            true
20978        });
20979        self.gutter_highlights
20980            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20981    }
20982
20983    #[cfg(feature = "test-support")]
20984    pub fn all_text_highlights(
20985        &self,
20986        window: &mut Window,
20987        cx: &mut Context<Self>,
20988    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20989        let snapshot = self.snapshot(window, cx);
20990        self.display_map.update(cx, |display_map, _| {
20991            display_map
20992                .all_text_highlights()
20993                .map(|highlight| {
20994                    let (style, ranges) = highlight.as_ref();
20995                    (
20996                        *style,
20997                        ranges
20998                            .iter()
20999                            .map(|range| range.clone().to_display_points(&snapshot))
21000                            .collect(),
21001                    )
21002                })
21003                .collect()
21004        })
21005    }
21006
21007    #[cfg(feature = "test-support")]
21008    pub fn all_text_background_highlights(
21009        &self,
21010        window: &mut Window,
21011        cx: &mut Context<Self>,
21012    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21013        let snapshot = self.snapshot(window, cx);
21014        let buffer = &snapshot.buffer_snapshot();
21015        let start = buffer.anchor_before(MultiBufferOffset(0));
21016        let end = buffer.anchor_after(buffer.len());
21017        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21018    }
21019
21020    #[cfg(any(test, feature = "test-support"))]
21021    pub fn sorted_background_highlights_in_range(
21022        &self,
21023        search_range: Range<Anchor>,
21024        display_snapshot: &DisplaySnapshot,
21025        theme: &Theme,
21026    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21027        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21028        res.sort_by(|a, b| {
21029            a.0.start
21030                .cmp(&b.0.start)
21031                .then_with(|| a.0.end.cmp(&b.0.end))
21032                .then_with(|| a.1.cmp(&b.1))
21033        });
21034        res
21035    }
21036
21037    #[cfg(feature = "test-support")]
21038    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21039        let snapshot = self.buffer().read(cx).snapshot(cx);
21040
21041        let highlights = self
21042            .background_highlights
21043            .get(&HighlightKey::Type(TypeId::of::<
21044                items::BufferSearchHighlights,
21045            >()));
21046
21047        if let Some((_color, ranges)) = highlights {
21048            ranges
21049                .iter()
21050                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21051                .collect_vec()
21052        } else {
21053            vec![]
21054        }
21055    }
21056
21057    fn document_highlights_for_position<'a>(
21058        &'a self,
21059        position: Anchor,
21060        buffer: &'a MultiBufferSnapshot,
21061    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21062        let read_highlights = self
21063            .background_highlights
21064            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21065            .map(|h| &h.1);
21066        let write_highlights = self
21067            .background_highlights
21068            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21069            .map(|h| &h.1);
21070        let left_position = position.bias_left(buffer);
21071        let right_position = position.bias_right(buffer);
21072        read_highlights
21073            .into_iter()
21074            .chain(write_highlights)
21075            .flat_map(move |ranges| {
21076                let start_ix = match ranges.binary_search_by(|probe| {
21077                    let cmp = probe.end.cmp(&left_position, buffer);
21078                    if cmp.is_ge() {
21079                        Ordering::Greater
21080                    } else {
21081                        Ordering::Less
21082                    }
21083                }) {
21084                    Ok(i) | Err(i) => i,
21085                };
21086
21087                ranges[start_ix..]
21088                    .iter()
21089                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21090            })
21091    }
21092
21093    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21094        self.background_highlights
21095            .get(&HighlightKey::Type(TypeId::of::<T>()))
21096            .is_some_and(|(_, highlights)| !highlights.is_empty())
21097    }
21098
21099    /// Returns all background highlights for a given range.
21100    ///
21101    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21102    pub fn background_highlights_in_range(
21103        &self,
21104        search_range: Range<Anchor>,
21105        display_snapshot: &DisplaySnapshot,
21106        theme: &Theme,
21107    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21108        let mut results = Vec::new();
21109        for (color_fetcher, ranges) in self.background_highlights.values() {
21110            let color = color_fetcher(theme);
21111            let start_ix = match ranges.binary_search_by(|probe| {
21112                let cmp = probe
21113                    .end
21114                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21115                if cmp.is_gt() {
21116                    Ordering::Greater
21117                } else {
21118                    Ordering::Less
21119                }
21120            }) {
21121                Ok(i) | Err(i) => i,
21122            };
21123            for range in &ranges[start_ix..] {
21124                if range
21125                    .start
21126                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21127                    .is_ge()
21128                {
21129                    break;
21130                }
21131
21132                let start = range.start.to_display_point(display_snapshot);
21133                let end = range.end.to_display_point(display_snapshot);
21134                results.push((start..end, color))
21135            }
21136        }
21137        results
21138    }
21139
21140    pub fn gutter_highlights_in_range(
21141        &self,
21142        search_range: Range<Anchor>,
21143        display_snapshot: &DisplaySnapshot,
21144        cx: &App,
21145    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21146        let mut results = Vec::new();
21147        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21148            let color = color_fetcher(cx);
21149            let start_ix = match ranges.binary_search_by(|probe| {
21150                let cmp = probe
21151                    .end
21152                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21153                if cmp.is_gt() {
21154                    Ordering::Greater
21155                } else {
21156                    Ordering::Less
21157                }
21158            }) {
21159                Ok(i) | Err(i) => i,
21160            };
21161            for range in &ranges[start_ix..] {
21162                if range
21163                    .start
21164                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21165                    .is_ge()
21166                {
21167                    break;
21168                }
21169
21170                let start = range.start.to_display_point(display_snapshot);
21171                let end = range.end.to_display_point(display_snapshot);
21172                results.push((start..end, color))
21173            }
21174        }
21175        results
21176    }
21177
21178    /// Get the text ranges corresponding to the redaction query
21179    pub fn redacted_ranges(
21180        &self,
21181        search_range: Range<Anchor>,
21182        display_snapshot: &DisplaySnapshot,
21183        cx: &App,
21184    ) -> Vec<Range<DisplayPoint>> {
21185        display_snapshot
21186            .buffer_snapshot()
21187            .redacted_ranges(search_range, |file| {
21188                if let Some(file) = file {
21189                    file.is_private()
21190                        && EditorSettings::get(
21191                            Some(SettingsLocation {
21192                                worktree_id: file.worktree_id(cx),
21193                                path: file.path().as_ref(),
21194                            }),
21195                            cx,
21196                        )
21197                        .redact_private_values
21198                } else {
21199                    false
21200                }
21201            })
21202            .map(|range| {
21203                range.start.to_display_point(display_snapshot)
21204                    ..range.end.to_display_point(display_snapshot)
21205            })
21206            .collect()
21207    }
21208
21209    pub fn highlight_text_key<T: 'static>(
21210        &mut self,
21211        key: usize,
21212        ranges: Vec<Range<Anchor>>,
21213        style: HighlightStyle,
21214        merge: bool,
21215        cx: &mut Context<Self>,
21216    ) {
21217        self.display_map.update(cx, |map, cx| {
21218            map.highlight_text(
21219                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21220                ranges,
21221                style,
21222                merge,
21223                cx,
21224            );
21225        });
21226        cx.notify();
21227    }
21228
21229    pub fn highlight_text<T: 'static>(
21230        &mut self,
21231        ranges: Vec<Range<Anchor>>,
21232        style: HighlightStyle,
21233        cx: &mut Context<Self>,
21234    ) {
21235        self.display_map.update(cx, |map, cx| {
21236            map.highlight_text(
21237                HighlightKey::Type(TypeId::of::<T>()),
21238                ranges,
21239                style,
21240                false,
21241                cx,
21242            )
21243        });
21244        cx.notify();
21245    }
21246
21247    pub fn text_highlights<'a, T: 'static>(
21248        &'a self,
21249        cx: &'a App,
21250    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21251        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21252    }
21253
21254    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21255        let cleared = self
21256            .display_map
21257            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21258        if cleared {
21259            cx.notify();
21260        }
21261    }
21262
21263    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21264        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21265            && self.focus_handle.is_focused(window)
21266    }
21267
21268    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21269        self.show_cursor_when_unfocused = is_enabled;
21270        cx.notify();
21271    }
21272
21273    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21274        cx.notify();
21275    }
21276
21277    fn on_debug_session_event(
21278        &mut self,
21279        _session: Entity<Session>,
21280        event: &SessionEvent,
21281        cx: &mut Context<Self>,
21282    ) {
21283        if let SessionEvent::InvalidateInlineValue = event {
21284            self.refresh_inline_values(cx);
21285        }
21286    }
21287
21288    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21289        let Some(project) = self.project.clone() else {
21290            return;
21291        };
21292
21293        if !self.inline_value_cache.enabled {
21294            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21295            self.splice_inlays(&inlays, Vec::new(), cx);
21296            return;
21297        }
21298
21299        let current_execution_position = self
21300            .highlighted_rows
21301            .get(&TypeId::of::<ActiveDebugLine>())
21302            .and_then(|lines| lines.last().map(|line| line.range.end));
21303
21304        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21305            let inline_values = editor
21306                .update(cx, |editor, cx| {
21307                    let Some(current_execution_position) = current_execution_position else {
21308                        return Some(Task::ready(Ok(Vec::new())));
21309                    };
21310
21311                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21312                        let snapshot = buffer.snapshot(cx);
21313
21314                        let excerpt = snapshot.excerpt_containing(
21315                            current_execution_position..current_execution_position,
21316                        )?;
21317
21318                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21319                    })?;
21320
21321                    let range =
21322                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21323
21324                    project.inline_values(buffer, range, cx)
21325                })
21326                .ok()
21327                .flatten()?
21328                .await
21329                .context("refreshing debugger inlays")
21330                .log_err()?;
21331
21332            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21333
21334            for (buffer_id, inline_value) in inline_values
21335                .into_iter()
21336                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21337            {
21338                buffer_inline_values
21339                    .entry(buffer_id)
21340                    .or_default()
21341                    .push(inline_value);
21342            }
21343
21344            editor
21345                .update(cx, |editor, cx| {
21346                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21347                    let mut new_inlays = Vec::default();
21348
21349                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21350                        let buffer_id = buffer_snapshot.remote_id();
21351                        buffer_inline_values
21352                            .get(&buffer_id)
21353                            .into_iter()
21354                            .flatten()
21355                            .for_each(|hint| {
21356                                let inlay = Inlay::debugger(
21357                                    post_inc(&mut editor.next_inlay_id),
21358                                    Anchor::in_buffer(excerpt_id, hint.position),
21359                                    hint.text(),
21360                                );
21361                                if !inlay.text().chars().contains(&'\n') {
21362                                    new_inlays.push(inlay);
21363                                }
21364                            });
21365                    }
21366
21367                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21368                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21369
21370                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21371                })
21372                .ok()?;
21373            Some(())
21374        });
21375    }
21376
21377    fn on_buffer_event(
21378        &mut self,
21379        multibuffer: &Entity<MultiBuffer>,
21380        event: &multi_buffer::Event,
21381        window: &mut Window,
21382        cx: &mut Context<Self>,
21383    ) {
21384        match event {
21385            multi_buffer::Event::Edited { edited_buffer } => {
21386                self.scrollbar_marker_state.dirty = true;
21387                self.active_indent_guides_state.dirty = true;
21388                self.refresh_active_diagnostics(cx);
21389                self.refresh_code_actions(window, cx);
21390                self.refresh_single_line_folds(window, cx);
21391                self.refresh_matching_bracket_highlights(window, cx);
21392                if self.has_active_edit_prediction() {
21393                    self.update_visible_edit_prediction(window, cx);
21394                }
21395
21396                if let Some(buffer) = edited_buffer {
21397                    if buffer.read(cx).file().is_none() {
21398                        cx.emit(EditorEvent::TitleChanged);
21399                    }
21400
21401                    if self.project.is_some() {
21402                        let buffer_id = buffer.read(cx).remote_id();
21403                        self.register_buffer(buffer_id, cx);
21404                        self.update_lsp_data(Some(buffer_id), window, cx);
21405                        self.refresh_inlay_hints(
21406                            InlayHintRefreshReason::BufferEdited(buffer_id),
21407                            cx,
21408                        );
21409                    }
21410                }
21411
21412                cx.emit(EditorEvent::BufferEdited);
21413                cx.emit(SearchEvent::MatchesInvalidated);
21414
21415                let Some(project) = &self.project else { return };
21416                let (telemetry, is_via_ssh) = {
21417                    let project = project.read(cx);
21418                    let telemetry = project.client().telemetry().clone();
21419                    let is_via_ssh = project.is_via_remote_server();
21420                    (telemetry, is_via_ssh)
21421                };
21422                telemetry.log_edit_event("editor", is_via_ssh);
21423            }
21424            multi_buffer::Event::ExcerptsAdded {
21425                buffer,
21426                predecessor,
21427                excerpts,
21428            } => {
21429                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21430                let buffer_id = buffer.read(cx).remote_id();
21431                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21432                    && let Some(project) = &self.project
21433                {
21434                    update_uncommitted_diff_for_buffer(
21435                        cx.entity(),
21436                        project,
21437                        [buffer.clone()],
21438                        self.buffer.clone(),
21439                        cx,
21440                    )
21441                    .detach();
21442                }
21443                self.update_lsp_data(Some(buffer_id), window, cx);
21444                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21445                self.colorize_brackets(false, cx);
21446                cx.emit(EditorEvent::ExcerptsAdded {
21447                    buffer: buffer.clone(),
21448                    predecessor: *predecessor,
21449                    excerpts: excerpts.clone(),
21450                });
21451            }
21452            multi_buffer::Event::ExcerptsRemoved {
21453                ids,
21454                removed_buffer_ids,
21455            } => {
21456                if let Some(inlay_hints) = &mut self.inlay_hints {
21457                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21458                }
21459                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21460                for buffer_id in removed_buffer_ids {
21461                    self.registered_buffers.remove(buffer_id);
21462                }
21463                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21464                cx.emit(EditorEvent::ExcerptsRemoved {
21465                    ids: ids.clone(),
21466                    removed_buffer_ids: removed_buffer_ids.clone(),
21467                });
21468            }
21469            multi_buffer::Event::ExcerptsEdited {
21470                excerpt_ids,
21471                buffer_ids,
21472            } => {
21473                self.display_map.update(cx, |map, cx| {
21474                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21475                });
21476                cx.emit(EditorEvent::ExcerptsEdited {
21477                    ids: excerpt_ids.clone(),
21478                });
21479            }
21480            multi_buffer::Event::ExcerptsExpanded { ids } => {
21481                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21482                self.refresh_document_highlights(cx);
21483                for id in ids {
21484                    self.fetched_tree_sitter_chunks.remove(id);
21485                }
21486                self.colorize_brackets(false, cx);
21487                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21488            }
21489            multi_buffer::Event::Reparsed(buffer_id) => {
21490                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21491                self.refresh_selected_text_highlights(true, window, cx);
21492                self.colorize_brackets(true, cx);
21493                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21494
21495                cx.emit(EditorEvent::Reparsed(*buffer_id));
21496            }
21497            multi_buffer::Event::DiffHunksToggled => {
21498                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21499            }
21500            multi_buffer::Event::LanguageChanged(buffer_id) => {
21501                self.registered_buffers.remove(&buffer_id);
21502                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21503                cx.emit(EditorEvent::Reparsed(*buffer_id));
21504                cx.notify();
21505            }
21506            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21507            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21508            multi_buffer::Event::FileHandleChanged
21509            | multi_buffer::Event::Reloaded
21510            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21511            multi_buffer::Event::DiagnosticsUpdated => {
21512                self.update_diagnostics_state(window, cx);
21513            }
21514            _ => {}
21515        };
21516    }
21517
21518    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21519        if !self.diagnostics_enabled() {
21520            return;
21521        }
21522        self.refresh_active_diagnostics(cx);
21523        self.refresh_inline_diagnostics(true, window, cx);
21524        self.scrollbar_marker_state.dirty = true;
21525        cx.notify();
21526    }
21527
21528    pub fn start_temporary_diff_override(&mut self) {
21529        self.load_diff_task.take();
21530        self.temporary_diff_override = true;
21531    }
21532
21533    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21534        self.temporary_diff_override = false;
21535        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21536        self.buffer.update(cx, |buffer, cx| {
21537            buffer.set_all_diff_hunks_collapsed(cx);
21538        });
21539
21540        if let Some(project) = self.project.clone() {
21541            self.load_diff_task = Some(
21542                update_uncommitted_diff_for_buffer(
21543                    cx.entity(),
21544                    &project,
21545                    self.buffer.read(cx).all_buffers(),
21546                    self.buffer.clone(),
21547                    cx,
21548                )
21549                .shared(),
21550            );
21551        }
21552    }
21553
21554    fn on_display_map_changed(
21555        &mut self,
21556        _: Entity<DisplayMap>,
21557        _: &mut Window,
21558        cx: &mut Context<Self>,
21559    ) {
21560        cx.notify();
21561    }
21562
21563    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21564        if !self.mode.is_full() {
21565            return Vec::new();
21566        }
21567
21568        let theme_settings = theme::ThemeSettings::get_global(cx);
21569
21570        theme_settings
21571            .theme_overrides
21572            .get(cx.theme().name.as_ref())
21573            .map(|theme_style| &theme_style.accents)
21574            .into_iter()
21575            .flatten()
21576            .chain(
21577                theme_settings
21578                    .experimental_theme_overrides
21579                    .as_ref()
21580                    .map(|overrides| &overrides.accents)
21581                    .into_iter()
21582                    .flatten(),
21583            )
21584            .flat_map(|accent| accent.0.clone())
21585            .collect()
21586    }
21587
21588    fn fetch_applicable_language_settings(
21589        &self,
21590        cx: &App,
21591    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21592        if !self.mode.is_full() {
21593            return HashMap::default();
21594        }
21595
21596        self.buffer().read(cx).all_buffers().into_iter().fold(
21597            HashMap::default(),
21598            |mut acc, buffer| {
21599                let buffer = buffer.read(cx);
21600                let language = buffer.language().map(|language| language.name());
21601                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21602                    let file = buffer.file();
21603                    v.insert(language_settings(language, file, cx).into_owned());
21604                }
21605                acc
21606            },
21607        )
21608    }
21609
21610    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21611        let new_language_settings = self.fetch_applicable_language_settings(cx);
21612        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21613        self.applicable_language_settings = new_language_settings;
21614
21615        let new_accent_overrides = self.fetch_accent_overrides(cx);
21616        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21617        self.accent_overrides = new_accent_overrides;
21618
21619        if self.diagnostics_enabled() {
21620            let new_severity = EditorSettings::get_global(cx)
21621                .diagnostics_max_severity
21622                .unwrap_or(DiagnosticSeverity::Hint);
21623            self.set_max_diagnostics_severity(new_severity, cx);
21624        }
21625        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21626        self.update_edit_prediction_settings(cx);
21627        self.refresh_edit_prediction(true, false, window, cx);
21628        self.refresh_inline_values(cx);
21629        self.refresh_inlay_hints(
21630            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21631                self.selections.newest_anchor().head(),
21632                &self.buffer.read(cx).snapshot(cx),
21633                cx,
21634            )),
21635            cx,
21636        );
21637
21638        let old_cursor_shape = self.cursor_shape;
21639        let old_show_breadcrumbs = self.show_breadcrumbs;
21640
21641        {
21642            let editor_settings = EditorSettings::get_global(cx);
21643            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21644            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21645            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21646            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21647        }
21648
21649        if old_cursor_shape != self.cursor_shape {
21650            cx.emit(EditorEvent::CursorShapeChanged);
21651        }
21652
21653        if old_show_breadcrumbs != self.show_breadcrumbs {
21654            cx.emit(EditorEvent::BreadcrumbsChanged);
21655        }
21656
21657        let project_settings = ProjectSettings::get_global(cx);
21658        self.buffer_serialization = self
21659            .should_serialize_buffer()
21660            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21661
21662        if self.mode.is_full() {
21663            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21664            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21665            if self.show_inline_diagnostics != show_inline_diagnostics {
21666                self.show_inline_diagnostics = show_inline_diagnostics;
21667                self.refresh_inline_diagnostics(false, window, cx);
21668            }
21669
21670            if self.git_blame_inline_enabled != inline_blame_enabled {
21671                self.toggle_git_blame_inline_internal(false, window, cx);
21672            }
21673
21674            let minimap_settings = EditorSettings::get_global(cx).minimap;
21675            if self.minimap_visibility != MinimapVisibility::Disabled {
21676                if self.minimap_visibility.settings_visibility()
21677                    != minimap_settings.minimap_enabled()
21678                {
21679                    self.set_minimap_visibility(
21680                        MinimapVisibility::for_mode(self.mode(), cx),
21681                        window,
21682                        cx,
21683                    );
21684                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21685                    minimap_entity.update(cx, |minimap_editor, cx| {
21686                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21687                    })
21688                }
21689            }
21690
21691            if language_settings_changed || accent_overrides_changed {
21692                self.colorize_brackets(true, cx);
21693            }
21694
21695            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21696                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21697            }) {
21698                if !inlay_splice.is_empty() {
21699                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21700                }
21701                self.refresh_colors_for_visible_range(None, window, cx);
21702            }
21703        }
21704
21705        cx.notify();
21706    }
21707
21708    pub fn set_searchable(&mut self, searchable: bool) {
21709        self.searchable = searchable;
21710    }
21711
21712    pub fn searchable(&self) -> bool {
21713        self.searchable
21714    }
21715
21716    pub fn open_excerpts_in_split(
21717        &mut self,
21718        _: &OpenExcerptsSplit,
21719        window: &mut Window,
21720        cx: &mut Context<Self>,
21721    ) {
21722        self.open_excerpts_common(None, true, window, cx)
21723    }
21724
21725    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21726        self.open_excerpts_common(None, false, window, cx)
21727    }
21728
21729    fn open_excerpts_common(
21730        &mut self,
21731        jump_data: Option<JumpData>,
21732        split: bool,
21733        window: &mut Window,
21734        cx: &mut Context<Self>,
21735    ) {
21736        let Some(workspace) = self.workspace() else {
21737            cx.propagate();
21738            return;
21739        };
21740
21741        if self.buffer.read(cx).is_singleton() {
21742            cx.propagate();
21743            return;
21744        }
21745
21746        let mut new_selections_by_buffer = HashMap::default();
21747        match &jump_data {
21748            Some(JumpData::MultiBufferPoint {
21749                excerpt_id,
21750                position,
21751                anchor,
21752                line_offset_from_top,
21753            }) => {
21754                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21755                if let Some(buffer) = multi_buffer_snapshot
21756                    .buffer_id_for_excerpt(*excerpt_id)
21757                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21758                {
21759                    let buffer_snapshot = buffer.read(cx).snapshot();
21760                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21761                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21762                    } else {
21763                        buffer_snapshot.clip_point(*position, Bias::Left)
21764                    };
21765                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21766                    new_selections_by_buffer.insert(
21767                        buffer,
21768                        (
21769                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21770                            Some(*line_offset_from_top),
21771                        ),
21772                    );
21773                }
21774            }
21775            Some(JumpData::MultiBufferRow {
21776                row,
21777                line_offset_from_top,
21778            }) => {
21779                let point = MultiBufferPoint::new(row.0, 0);
21780                if let Some((buffer, buffer_point, _)) =
21781                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21782                {
21783                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21784                    new_selections_by_buffer
21785                        .entry(buffer)
21786                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21787                        .0
21788                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21789                }
21790            }
21791            None => {
21792                let selections = self
21793                    .selections
21794                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21795                let multi_buffer = self.buffer.read(cx);
21796                for selection in selections {
21797                    for (snapshot, range, _, anchor) in multi_buffer
21798                        .snapshot(cx)
21799                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21800                    {
21801                        if let Some(anchor) = anchor {
21802                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21803                            else {
21804                                continue;
21805                            };
21806                            let offset = text::ToOffset::to_offset(
21807                                &anchor.text_anchor,
21808                                &buffer_handle.read(cx).snapshot(),
21809                            );
21810                            let range = BufferOffset(offset)..BufferOffset(offset);
21811                            new_selections_by_buffer
21812                                .entry(buffer_handle)
21813                                .or_insert((Vec::new(), None))
21814                                .0
21815                                .push(range)
21816                        } else {
21817                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21818                            else {
21819                                continue;
21820                            };
21821                            new_selections_by_buffer
21822                                .entry(buffer_handle)
21823                                .or_insert((Vec::new(), None))
21824                                .0
21825                                .push(range)
21826                        }
21827                    }
21828                }
21829            }
21830        }
21831
21832        new_selections_by_buffer
21833            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21834
21835        if new_selections_by_buffer.is_empty() {
21836            return;
21837        }
21838
21839        // We defer the pane interaction because we ourselves are a workspace item
21840        // and activating a new item causes the pane to call a method on us reentrantly,
21841        // which panics if we're on the stack.
21842        window.defer(cx, move |window, cx| {
21843            workspace.update(cx, |workspace, cx| {
21844                let pane = if split {
21845                    workspace.adjacent_pane(window, cx)
21846                } else {
21847                    workspace.active_pane().clone()
21848                };
21849
21850                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21851                    let editor = buffer
21852                        .read(cx)
21853                        .file()
21854                        .is_none()
21855                        .then(|| {
21856                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21857                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21858                            // Instead, we try to activate the existing editor in the pane first.
21859                            let (editor, pane_item_index) =
21860                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21861                                    let editor = item.downcast::<Editor>()?;
21862                                    let singleton_buffer =
21863                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21864                                    if singleton_buffer == buffer {
21865                                        Some((editor, i))
21866                                    } else {
21867                                        None
21868                                    }
21869                                })?;
21870                            pane.update(cx, |pane, cx| {
21871                                pane.activate_item(pane_item_index, true, true, window, cx)
21872                            });
21873                            Some(editor)
21874                        })
21875                        .flatten()
21876                        .unwrap_or_else(|| {
21877                            workspace.open_project_item::<Self>(
21878                                pane.clone(),
21879                                buffer,
21880                                true,
21881                                true,
21882                                window,
21883                                cx,
21884                            )
21885                        });
21886
21887                    editor.update(cx, |editor, cx| {
21888                        let autoscroll = match scroll_offset {
21889                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21890                            None => Autoscroll::newest(),
21891                        };
21892                        let nav_history = editor.nav_history.take();
21893                        editor.change_selections(
21894                            SelectionEffects::scroll(autoscroll),
21895                            window,
21896                            cx,
21897                            |s| {
21898                                s.select_ranges(ranges.into_iter().map(|range| {
21899                                    // we checked that the editor is a singleton editor so the offsets are valid
21900                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21901                                }));
21902                            },
21903                        );
21904                        editor.nav_history = nav_history;
21905                    });
21906                }
21907            })
21908        });
21909    }
21910
21911    // For now, don't allow opening excerpts in buffers that aren't backed by
21912    // regular project files.
21913    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21914        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21915    }
21916
21917    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21918        let snapshot = self.buffer.read(cx).read(cx);
21919        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21920        Some(
21921            ranges
21922                .iter()
21923                .map(move |range| {
21924                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21925                })
21926                .collect(),
21927        )
21928    }
21929
21930    fn selection_replacement_ranges(
21931        &self,
21932        range: Range<MultiBufferOffsetUtf16>,
21933        cx: &mut App,
21934    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21935        let selections = self
21936            .selections
21937            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21938        let newest_selection = selections
21939            .iter()
21940            .max_by_key(|selection| selection.id)
21941            .unwrap();
21942        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21943        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21944        let snapshot = self.buffer.read(cx).read(cx);
21945        selections
21946            .into_iter()
21947            .map(|mut selection| {
21948                selection.start.0.0 =
21949                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21950                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21951                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21952                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21953            })
21954            .collect()
21955    }
21956
21957    fn report_editor_event(
21958        &self,
21959        reported_event: ReportEditorEvent,
21960        file_extension: Option<String>,
21961        cx: &App,
21962    ) {
21963        if cfg!(any(test, feature = "test-support")) {
21964            return;
21965        }
21966
21967        let Some(project) = &self.project else { return };
21968
21969        // If None, we are in a file without an extension
21970        let file = self
21971            .buffer
21972            .read(cx)
21973            .as_singleton()
21974            .and_then(|b| b.read(cx).file());
21975        let file_extension = file_extension.or(file
21976            .as_ref()
21977            .and_then(|file| Path::new(file.file_name(cx)).extension())
21978            .and_then(|e| e.to_str())
21979            .map(|a| a.to_string()));
21980
21981        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21982            .map(|vim_mode| vim_mode.0)
21983            .unwrap_or(false);
21984
21985        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21986        let copilot_enabled = edit_predictions_provider
21987            == language::language_settings::EditPredictionProvider::Copilot;
21988        let copilot_enabled_for_language = self
21989            .buffer
21990            .read(cx)
21991            .language_settings(cx)
21992            .show_edit_predictions;
21993
21994        let project = project.read(cx);
21995        let event_type = reported_event.event_type();
21996
21997        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21998            telemetry::event!(
21999                event_type,
22000                type = if auto_saved {"autosave"} else {"manual"},
22001                file_extension,
22002                vim_mode,
22003                copilot_enabled,
22004                copilot_enabled_for_language,
22005                edit_predictions_provider,
22006                is_via_ssh = project.is_via_remote_server(),
22007            );
22008        } else {
22009            telemetry::event!(
22010                event_type,
22011                file_extension,
22012                vim_mode,
22013                copilot_enabled,
22014                copilot_enabled_for_language,
22015                edit_predictions_provider,
22016                is_via_ssh = project.is_via_remote_server(),
22017            );
22018        };
22019    }
22020
22021    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22022    /// with each line being an array of {text, highlight} objects.
22023    fn copy_highlight_json(
22024        &mut self,
22025        _: &CopyHighlightJson,
22026        window: &mut Window,
22027        cx: &mut Context<Self>,
22028    ) {
22029        #[derive(Serialize)]
22030        struct Chunk<'a> {
22031            text: String,
22032            highlight: Option<&'a str>,
22033        }
22034
22035        let snapshot = self.buffer.read(cx).snapshot(cx);
22036        let range = self
22037            .selected_text_range(false, window, cx)
22038            .and_then(|selection| {
22039                if selection.range.is_empty() {
22040                    None
22041                } else {
22042                    Some(
22043                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22044                            selection.range.start,
22045                        )))
22046                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22047                                selection.range.end,
22048                            ))),
22049                    )
22050                }
22051            })
22052            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22053
22054        let chunks = snapshot.chunks(range, true);
22055        let mut lines = Vec::new();
22056        let mut line: VecDeque<Chunk> = VecDeque::new();
22057
22058        let Some(style) = self.style.as_ref() else {
22059            return;
22060        };
22061
22062        for chunk in chunks {
22063            let highlight = chunk
22064                .syntax_highlight_id
22065                .and_then(|id| id.name(&style.syntax));
22066            let mut chunk_lines = chunk.text.split('\n').peekable();
22067            while let Some(text) = chunk_lines.next() {
22068                let mut merged_with_last_token = false;
22069                if let Some(last_token) = line.back_mut()
22070                    && last_token.highlight == highlight
22071                {
22072                    last_token.text.push_str(text);
22073                    merged_with_last_token = true;
22074                }
22075
22076                if !merged_with_last_token {
22077                    line.push_back(Chunk {
22078                        text: text.into(),
22079                        highlight,
22080                    });
22081                }
22082
22083                if chunk_lines.peek().is_some() {
22084                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22085                        line.pop_front();
22086                    }
22087                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22088                        line.pop_back();
22089                    }
22090
22091                    lines.push(mem::take(&mut line));
22092                }
22093            }
22094        }
22095
22096        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22097            return;
22098        };
22099        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22100    }
22101
22102    pub fn open_context_menu(
22103        &mut self,
22104        _: &OpenContextMenu,
22105        window: &mut Window,
22106        cx: &mut Context<Self>,
22107    ) {
22108        self.request_autoscroll(Autoscroll::newest(), cx);
22109        let position = self
22110            .selections
22111            .newest_display(&self.display_snapshot(cx))
22112            .start;
22113        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22114    }
22115
22116    pub fn replay_insert_event(
22117        &mut self,
22118        text: &str,
22119        relative_utf16_range: Option<Range<isize>>,
22120        window: &mut Window,
22121        cx: &mut Context<Self>,
22122    ) {
22123        if !self.input_enabled {
22124            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22125            return;
22126        }
22127        if let Some(relative_utf16_range) = relative_utf16_range {
22128            let selections = self
22129                .selections
22130                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22131            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22132                let new_ranges = selections.into_iter().map(|range| {
22133                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22134                        range
22135                            .head()
22136                            .0
22137                            .0
22138                            .saturating_add_signed(relative_utf16_range.start),
22139                    ));
22140                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22141                        range
22142                            .head()
22143                            .0
22144                            .0
22145                            .saturating_add_signed(relative_utf16_range.end),
22146                    ));
22147                    start..end
22148                });
22149                s.select_ranges(new_ranges);
22150            });
22151        }
22152
22153        self.handle_input(text, window, cx);
22154    }
22155
22156    pub fn is_focused(&self, window: &Window) -> bool {
22157        self.focus_handle.is_focused(window)
22158    }
22159
22160    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22161        cx.emit(EditorEvent::Focused);
22162
22163        if let Some(descendant) = self
22164            .last_focused_descendant
22165            .take()
22166            .and_then(|descendant| descendant.upgrade())
22167        {
22168            window.focus(&descendant);
22169        } else {
22170            if let Some(blame) = self.blame.as_ref() {
22171                blame.update(cx, GitBlame::focus)
22172            }
22173
22174            self.blink_manager.update(cx, BlinkManager::enable);
22175            self.show_cursor_names(window, cx);
22176            self.buffer.update(cx, |buffer, cx| {
22177                buffer.finalize_last_transaction(cx);
22178                if self.leader_id.is_none() {
22179                    buffer.set_active_selections(
22180                        &self.selections.disjoint_anchors_arc(),
22181                        self.selections.line_mode(),
22182                        self.cursor_shape,
22183                        cx,
22184                    );
22185                }
22186            });
22187
22188            if let Some(position_map) = self.last_position_map.clone() {
22189                EditorElement::mouse_moved(
22190                    self,
22191                    &MouseMoveEvent {
22192                        position: window.mouse_position(),
22193                        pressed_button: None,
22194                        modifiers: window.modifiers(),
22195                    },
22196                    &position_map,
22197                    window,
22198                    cx,
22199                );
22200            }
22201        }
22202    }
22203
22204    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22205        cx.emit(EditorEvent::FocusedIn)
22206    }
22207
22208    fn handle_focus_out(
22209        &mut self,
22210        event: FocusOutEvent,
22211        _window: &mut Window,
22212        cx: &mut Context<Self>,
22213    ) {
22214        if event.blurred != self.focus_handle {
22215            self.last_focused_descendant = Some(event.blurred);
22216        }
22217        self.selection_drag_state = SelectionDragState::None;
22218        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22219    }
22220
22221    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22222        self.blink_manager.update(cx, BlinkManager::disable);
22223        self.buffer
22224            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22225
22226        if let Some(blame) = self.blame.as_ref() {
22227            blame.update(cx, GitBlame::blur)
22228        }
22229        if !self.hover_state.focused(window, cx) {
22230            hide_hover(self, cx);
22231        }
22232        if !self
22233            .context_menu
22234            .borrow()
22235            .as_ref()
22236            .is_some_and(|context_menu| context_menu.focused(window, cx))
22237        {
22238            self.hide_context_menu(window, cx);
22239        }
22240        self.take_active_edit_prediction(cx);
22241        cx.emit(EditorEvent::Blurred);
22242        cx.notify();
22243    }
22244
22245    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22246        let mut pending: String = window
22247            .pending_input_keystrokes()
22248            .into_iter()
22249            .flatten()
22250            .filter_map(|keystroke| keystroke.key_char.clone())
22251            .collect();
22252
22253        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22254            pending = "".to_string();
22255        }
22256
22257        let existing_pending = self
22258            .text_highlights::<PendingInput>(cx)
22259            .map(|(_, ranges)| ranges.to_vec());
22260        if existing_pending.is_none() && pending.is_empty() {
22261            return;
22262        }
22263        let transaction =
22264            self.transact(window, cx, |this, window, cx| {
22265                let selections = this
22266                    .selections
22267                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22268                let edits = selections
22269                    .iter()
22270                    .map(|selection| (selection.end..selection.end, pending.clone()));
22271                this.edit(edits, cx);
22272                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22273                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22274                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22275                    }));
22276                });
22277                if let Some(existing_ranges) = existing_pending {
22278                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22279                    this.edit(edits, cx);
22280                }
22281            });
22282
22283        let snapshot = self.snapshot(window, cx);
22284        let ranges = self
22285            .selections
22286            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22287            .into_iter()
22288            .map(|selection| {
22289                snapshot.buffer_snapshot().anchor_after(selection.end)
22290                    ..snapshot
22291                        .buffer_snapshot()
22292                        .anchor_before(selection.end + pending.len())
22293            })
22294            .collect();
22295
22296        if pending.is_empty() {
22297            self.clear_highlights::<PendingInput>(cx);
22298        } else {
22299            self.highlight_text::<PendingInput>(
22300                ranges,
22301                HighlightStyle {
22302                    underline: Some(UnderlineStyle {
22303                        thickness: px(1.),
22304                        color: None,
22305                        wavy: false,
22306                    }),
22307                    ..Default::default()
22308                },
22309                cx,
22310            );
22311        }
22312
22313        self.ime_transaction = self.ime_transaction.or(transaction);
22314        if let Some(transaction) = self.ime_transaction {
22315            self.buffer.update(cx, |buffer, cx| {
22316                buffer.group_until_transaction(transaction, cx);
22317            });
22318        }
22319
22320        if self.text_highlights::<PendingInput>(cx).is_none() {
22321            self.ime_transaction.take();
22322        }
22323    }
22324
22325    pub fn register_action_renderer(
22326        &mut self,
22327        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22328    ) -> Subscription {
22329        let id = self.next_editor_action_id.post_inc();
22330        self.editor_actions
22331            .borrow_mut()
22332            .insert(id, Box::new(listener));
22333
22334        let editor_actions = self.editor_actions.clone();
22335        Subscription::new(move || {
22336            editor_actions.borrow_mut().remove(&id);
22337        })
22338    }
22339
22340    pub fn register_action<A: Action>(
22341        &mut self,
22342        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22343    ) -> Subscription {
22344        let id = self.next_editor_action_id.post_inc();
22345        let listener = Arc::new(listener);
22346        self.editor_actions.borrow_mut().insert(
22347            id,
22348            Box::new(move |_, window, _| {
22349                let listener = listener.clone();
22350                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22351                    let action = action.downcast_ref().unwrap();
22352                    if phase == DispatchPhase::Bubble {
22353                        listener(action, window, cx)
22354                    }
22355                })
22356            }),
22357        );
22358
22359        let editor_actions = self.editor_actions.clone();
22360        Subscription::new(move || {
22361            editor_actions.borrow_mut().remove(&id);
22362        })
22363    }
22364
22365    pub fn file_header_size(&self) -> u32 {
22366        FILE_HEADER_HEIGHT
22367    }
22368
22369    pub fn restore(
22370        &mut self,
22371        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22372        window: &mut Window,
22373        cx: &mut Context<Self>,
22374    ) {
22375        let workspace = self.workspace();
22376        let project = self.project();
22377        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22378            let mut tasks = Vec::new();
22379            for (buffer_id, changes) in revert_changes {
22380                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22381                    buffer.update(cx, |buffer, cx| {
22382                        buffer.edit(
22383                            changes
22384                                .into_iter()
22385                                .map(|(range, text)| (range, text.to_string())),
22386                            None,
22387                            cx,
22388                        );
22389                    });
22390
22391                    if let Some(project) =
22392                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22393                    {
22394                        project.update(cx, |project, cx| {
22395                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22396                        })
22397                    }
22398                }
22399            }
22400            tasks
22401        });
22402        cx.spawn_in(window, async move |_, cx| {
22403            for (buffer, task) in save_tasks {
22404                let result = task.await;
22405                if result.is_err() {
22406                    let Some(path) = buffer
22407                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22408                        .ok()
22409                    else {
22410                        continue;
22411                    };
22412                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22413                        let Some(task) = cx
22414                            .update_window_entity(workspace, |workspace, window, cx| {
22415                                workspace
22416                                    .open_path_preview(path, None, false, false, false, window, cx)
22417                            })
22418                            .ok()
22419                        else {
22420                            continue;
22421                        };
22422                        task.await.log_err();
22423                    }
22424                }
22425            }
22426        })
22427        .detach();
22428        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22429            selections.refresh()
22430        });
22431    }
22432
22433    pub fn to_pixel_point(
22434        &self,
22435        source: multi_buffer::Anchor,
22436        editor_snapshot: &EditorSnapshot,
22437        window: &mut Window,
22438    ) -> Option<gpui::Point<Pixels>> {
22439        let source_point = source.to_display_point(editor_snapshot);
22440        self.display_to_pixel_point(source_point, editor_snapshot, window)
22441    }
22442
22443    pub fn display_to_pixel_point(
22444        &self,
22445        source: DisplayPoint,
22446        editor_snapshot: &EditorSnapshot,
22447        window: &mut Window,
22448    ) -> Option<gpui::Point<Pixels>> {
22449        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22450        let text_layout_details = self.text_layout_details(window);
22451        let scroll_top = text_layout_details
22452            .scroll_anchor
22453            .scroll_position(editor_snapshot)
22454            .y;
22455
22456        if source.row().as_f64() < scroll_top.floor() {
22457            return None;
22458        }
22459        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22460        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22461        Some(gpui::Point::new(source_x, source_y))
22462    }
22463
22464    pub fn has_visible_completions_menu(&self) -> bool {
22465        !self.edit_prediction_preview_is_active()
22466            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22467                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22468            })
22469    }
22470
22471    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22472        if self.mode.is_minimap() {
22473            return;
22474        }
22475        self.addons
22476            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22477    }
22478
22479    pub fn unregister_addon<T: Addon>(&mut self) {
22480        self.addons.remove(&std::any::TypeId::of::<T>());
22481    }
22482
22483    pub fn addon<T: Addon>(&self) -> Option<&T> {
22484        let type_id = std::any::TypeId::of::<T>();
22485        self.addons
22486            .get(&type_id)
22487            .and_then(|item| item.to_any().downcast_ref::<T>())
22488    }
22489
22490    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22491        let type_id = std::any::TypeId::of::<T>();
22492        self.addons
22493            .get_mut(&type_id)
22494            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22495    }
22496
22497    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22498        let text_layout_details = self.text_layout_details(window);
22499        let style = &text_layout_details.editor_style;
22500        let font_id = window.text_system().resolve_font(&style.text.font());
22501        let font_size = style.text.font_size.to_pixels(window.rem_size());
22502        let line_height = style.text.line_height_in_pixels(window.rem_size());
22503        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22504        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22505
22506        CharacterDimensions {
22507            em_width,
22508            em_advance,
22509            line_height,
22510        }
22511    }
22512
22513    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22514        self.load_diff_task.clone()
22515    }
22516
22517    fn read_metadata_from_db(
22518        &mut self,
22519        item_id: u64,
22520        workspace_id: WorkspaceId,
22521        window: &mut Window,
22522        cx: &mut Context<Editor>,
22523    ) {
22524        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22525            && !self.mode.is_minimap()
22526            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22527        {
22528            let buffer_snapshot = OnceCell::new();
22529
22530            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22531                && !folds.is_empty()
22532            {
22533                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22534                self.fold_ranges(
22535                    folds
22536                        .into_iter()
22537                        .map(|(start, end)| {
22538                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22539                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22540                        })
22541                        .collect(),
22542                    false,
22543                    window,
22544                    cx,
22545                );
22546            }
22547
22548            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22549                && !selections.is_empty()
22550            {
22551                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22552                // skip adding the initial selection to selection history
22553                self.selection_history.mode = SelectionHistoryMode::Skipping;
22554                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22555                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22556                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22557                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22558                    }));
22559                });
22560                self.selection_history.mode = SelectionHistoryMode::Normal;
22561            };
22562        }
22563
22564        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22565    }
22566
22567    fn update_lsp_data(
22568        &mut self,
22569        for_buffer: Option<BufferId>,
22570        window: &mut Window,
22571        cx: &mut Context<'_, Self>,
22572    ) {
22573        self.pull_diagnostics(for_buffer, window, cx);
22574        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22575    }
22576
22577    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22578        if self.ignore_lsp_data() {
22579            return;
22580        }
22581        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22582            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22583        }
22584    }
22585
22586    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22587        if self.ignore_lsp_data() {
22588            return;
22589        }
22590
22591        if !self.registered_buffers.contains_key(&buffer_id)
22592            && let Some(project) = self.project.as_ref()
22593        {
22594            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22595                project.update(cx, |project, cx| {
22596                    self.registered_buffers.insert(
22597                        buffer_id,
22598                        project.register_buffer_with_language_servers(&buffer, cx),
22599                    );
22600                });
22601            } else {
22602                self.registered_buffers.remove(&buffer_id);
22603            }
22604        }
22605    }
22606
22607    fn ignore_lsp_data(&self) -> bool {
22608        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22609        // skip any LSP updates for it.
22610        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22611    }
22612}
22613
22614fn edit_for_markdown_paste<'a>(
22615    buffer: &MultiBufferSnapshot,
22616    range: Range<MultiBufferOffset>,
22617    to_insert: &'a str,
22618    url: Option<url::Url>,
22619) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22620    if url.is_none() {
22621        return (range, Cow::Borrowed(to_insert));
22622    };
22623
22624    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22625
22626    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22627        Cow::Borrowed(to_insert)
22628    } else {
22629        Cow::Owned(format!("[{old_text}]({to_insert})"))
22630    };
22631    (range, new_text)
22632}
22633
22634fn process_completion_for_edit(
22635    completion: &Completion,
22636    intent: CompletionIntent,
22637    buffer: &Entity<Buffer>,
22638    cursor_position: &text::Anchor,
22639    cx: &mut Context<Editor>,
22640) -> CompletionEdit {
22641    let buffer = buffer.read(cx);
22642    let buffer_snapshot = buffer.snapshot();
22643    let (snippet, new_text) = if completion.is_snippet() {
22644        let mut snippet_source = completion.new_text.clone();
22645        // Workaround for typescript language server issues so that methods don't expand within
22646        // strings and functions with type expressions. The previous point is used because the query
22647        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22648        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22649        let previous_point = if previous_point.column > 0 {
22650            cursor_position.to_previous_offset(&buffer_snapshot)
22651        } else {
22652            cursor_position.to_offset(&buffer_snapshot)
22653        };
22654        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22655            && scope.prefers_label_for_snippet_in_completion()
22656            && let Some(label) = completion.label()
22657            && matches!(
22658                completion.kind(),
22659                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22660            )
22661        {
22662            snippet_source = label;
22663        }
22664        match Snippet::parse(&snippet_source).log_err() {
22665            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22666            None => (None, completion.new_text.clone()),
22667        }
22668    } else {
22669        (None, completion.new_text.clone())
22670    };
22671
22672    let mut range_to_replace = {
22673        let replace_range = &completion.replace_range;
22674        if let CompletionSource::Lsp {
22675            insert_range: Some(insert_range),
22676            ..
22677        } = &completion.source
22678        {
22679            debug_assert_eq!(
22680                insert_range.start, replace_range.start,
22681                "insert_range and replace_range should start at the same position"
22682            );
22683            debug_assert!(
22684                insert_range
22685                    .start
22686                    .cmp(cursor_position, &buffer_snapshot)
22687                    .is_le(),
22688                "insert_range should start before or at cursor position"
22689            );
22690            debug_assert!(
22691                replace_range
22692                    .start
22693                    .cmp(cursor_position, &buffer_snapshot)
22694                    .is_le(),
22695                "replace_range should start before or at cursor position"
22696            );
22697
22698            let should_replace = match intent {
22699                CompletionIntent::CompleteWithInsert => false,
22700                CompletionIntent::CompleteWithReplace => true,
22701                CompletionIntent::Complete | CompletionIntent::Compose => {
22702                    let insert_mode =
22703                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22704                            .completions
22705                            .lsp_insert_mode;
22706                    match insert_mode {
22707                        LspInsertMode::Insert => false,
22708                        LspInsertMode::Replace => true,
22709                        LspInsertMode::ReplaceSubsequence => {
22710                            let mut text_to_replace = buffer.chars_for_range(
22711                                buffer.anchor_before(replace_range.start)
22712                                    ..buffer.anchor_after(replace_range.end),
22713                            );
22714                            let mut current_needle = text_to_replace.next();
22715                            for haystack_ch in completion.label.text.chars() {
22716                                if let Some(needle_ch) = current_needle
22717                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22718                                {
22719                                    current_needle = text_to_replace.next();
22720                                }
22721                            }
22722                            current_needle.is_none()
22723                        }
22724                        LspInsertMode::ReplaceSuffix => {
22725                            if replace_range
22726                                .end
22727                                .cmp(cursor_position, &buffer_snapshot)
22728                                .is_gt()
22729                            {
22730                                let range_after_cursor = *cursor_position..replace_range.end;
22731                                let text_after_cursor = buffer
22732                                    .text_for_range(
22733                                        buffer.anchor_before(range_after_cursor.start)
22734                                            ..buffer.anchor_after(range_after_cursor.end),
22735                                    )
22736                                    .collect::<String>()
22737                                    .to_ascii_lowercase();
22738                                completion
22739                                    .label
22740                                    .text
22741                                    .to_ascii_lowercase()
22742                                    .ends_with(&text_after_cursor)
22743                            } else {
22744                                true
22745                            }
22746                        }
22747                    }
22748                }
22749            };
22750
22751            if should_replace {
22752                replace_range.clone()
22753            } else {
22754                insert_range.clone()
22755            }
22756        } else {
22757            replace_range.clone()
22758        }
22759    };
22760
22761    if range_to_replace
22762        .end
22763        .cmp(cursor_position, &buffer_snapshot)
22764        .is_lt()
22765    {
22766        range_to_replace.end = *cursor_position;
22767    }
22768
22769    let replace_range = range_to_replace.to_offset(buffer);
22770    CompletionEdit {
22771        new_text,
22772        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22773        snippet,
22774    }
22775}
22776
22777struct CompletionEdit {
22778    new_text: String,
22779    replace_range: Range<BufferOffset>,
22780    snippet: Option<Snippet>,
22781}
22782
22783fn insert_extra_newline_brackets(
22784    buffer: &MultiBufferSnapshot,
22785    range: Range<MultiBufferOffset>,
22786    language: &language::LanguageScope,
22787) -> bool {
22788    let leading_whitespace_len = buffer
22789        .reversed_chars_at(range.start)
22790        .take_while(|c| c.is_whitespace() && *c != '\n')
22791        .map(|c| c.len_utf8())
22792        .sum::<usize>();
22793    let trailing_whitespace_len = buffer
22794        .chars_at(range.end)
22795        .take_while(|c| c.is_whitespace() && *c != '\n')
22796        .map(|c| c.len_utf8())
22797        .sum::<usize>();
22798    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22799
22800    language.brackets().any(|(pair, enabled)| {
22801        let pair_start = pair.start.trim_end();
22802        let pair_end = pair.end.trim_start();
22803
22804        enabled
22805            && pair.newline
22806            && buffer.contains_str_at(range.end, pair_end)
22807            && buffer.contains_str_at(
22808                range.start.saturating_sub_usize(pair_start.len()),
22809                pair_start,
22810            )
22811    })
22812}
22813
22814fn insert_extra_newline_tree_sitter(
22815    buffer: &MultiBufferSnapshot,
22816    range: Range<MultiBufferOffset>,
22817) -> bool {
22818    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22819        [(buffer, range, _)] => (*buffer, range.clone()),
22820        _ => return false,
22821    };
22822    let pair = {
22823        let mut result: Option<BracketMatch<usize>> = None;
22824
22825        for pair in buffer
22826            .all_bracket_ranges(range.start.0..range.end.0)
22827            .filter(move |pair| {
22828                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22829            })
22830        {
22831            let len = pair.close_range.end - pair.open_range.start;
22832
22833            if let Some(existing) = &result {
22834                let existing_len = existing.close_range.end - existing.open_range.start;
22835                if len > existing_len {
22836                    continue;
22837                }
22838            }
22839
22840            result = Some(pair);
22841        }
22842
22843        result
22844    };
22845    let Some(pair) = pair else {
22846        return false;
22847    };
22848    pair.newline_only
22849        && buffer
22850            .chars_for_range(pair.open_range.end..range.start.0)
22851            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22852            .all(|c| c.is_whitespace() && c != '\n')
22853}
22854
22855fn update_uncommitted_diff_for_buffer(
22856    editor: Entity<Editor>,
22857    project: &Entity<Project>,
22858    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22859    buffer: Entity<MultiBuffer>,
22860    cx: &mut App,
22861) -> Task<()> {
22862    let mut tasks = Vec::new();
22863    project.update(cx, |project, cx| {
22864        for buffer in buffers {
22865            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22866                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22867            }
22868        }
22869    });
22870    cx.spawn(async move |cx| {
22871        let diffs = future::join_all(tasks).await;
22872        if editor
22873            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22874            .unwrap_or(false)
22875        {
22876            return;
22877        }
22878
22879        buffer
22880            .update(cx, |buffer, cx| {
22881                for diff in diffs.into_iter().flatten() {
22882                    buffer.add_diff(diff, cx);
22883                }
22884            })
22885            .ok();
22886    })
22887}
22888
22889fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22890    let tab_size = tab_size.get() as usize;
22891    let mut width = offset;
22892
22893    for ch in text.chars() {
22894        width += if ch == '\t' {
22895            tab_size - (width % tab_size)
22896        } else {
22897            1
22898        };
22899    }
22900
22901    width - offset
22902}
22903
22904#[cfg(test)]
22905mod tests {
22906    use super::*;
22907
22908    #[test]
22909    fn test_string_size_with_expanded_tabs() {
22910        let nz = |val| NonZeroU32::new(val).unwrap();
22911        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22912        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22913        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22914        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22915        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22916        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22917        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22918        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22919    }
22920}
22921
22922/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22923struct WordBreakingTokenizer<'a> {
22924    input: &'a str,
22925}
22926
22927impl<'a> WordBreakingTokenizer<'a> {
22928    fn new(input: &'a str) -> Self {
22929        Self { input }
22930    }
22931}
22932
22933fn is_char_ideographic(ch: char) -> bool {
22934    use unicode_script::Script::*;
22935    use unicode_script::UnicodeScript;
22936    matches!(ch.script(), Han | Tangut | Yi)
22937}
22938
22939fn is_grapheme_ideographic(text: &str) -> bool {
22940    text.chars().any(is_char_ideographic)
22941}
22942
22943fn is_grapheme_whitespace(text: &str) -> bool {
22944    text.chars().any(|x| x.is_whitespace())
22945}
22946
22947fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22948    text.chars()
22949        .next()
22950        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22951}
22952
22953#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22954enum WordBreakToken<'a> {
22955    Word { token: &'a str, grapheme_len: usize },
22956    InlineWhitespace { token: &'a str, grapheme_len: usize },
22957    Newline,
22958}
22959
22960impl<'a> Iterator for WordBreakingTokenizer<'a> {
22961    /// Yields a span, the count of graphemes in the token, and whether it was
22962    /// whitespace. Note that it also breaks at word boundaries.
22963    type Item = WordBreakToken<'a>;
22964
22965    fn next(&mut self) -> Option<Self::Item> {
22966        use unicode_segmentation::UnicodeSegmentation;
22967        if self.input.is_empty() {
22968            return None;
22969        }
22970
22971        let mut iter = self.input.graphemes(true).peekable();
22972        let mut offset = 0;
22973        let mut grapheme_len = 0;
22974        if let Some(first_grapheme) = iter.next() {
22975            let is_newline = first_grapheme == "\n";
22976            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22977            offset += first_grapheme.len();
22978            grapheme_len += 1;
22979            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22980                if let Some(grapheme) = iter.peek().copied()
22981                    && should_stay_with_preceding_ideograph(grapheme)
22982                {
22983                    offset += grapheme.len();
22984                    grapheme_len += 1;
22985                }
22986            } else {
22987                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22988                let mut next_word_bound = words.peek().copied();
22989                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22990                    next_word_bound = words.next();
22991                }
22992                while let Some(grapheme) = iter.peek().copied() {
22993                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22994                        break;
22995                    };
22996                    if is_grapheme_whitespace(grapheme) != is_whitespace
22997                        || (grapheme == "\n") != is_newline
22998                    {
22999                        break;
23000                    };
23001                    offset += grapheme.len();
23002                    grapheme_len += 1;
23003                    iter.next();
23004                }
23005            }
23006            let token = &self.input[..offset];
23007            self.input = &self.input[offset..];
23008            if token == "\n" {
23009                Some(WordBreakToken::Newline)
23010            } else if is_whitespace {
23011                Some(WordBreakToken::InlineWhitespace {
23012                    token,
23013                    grapheme_len,
23014                })
23015            } else {
23016                Some(WordBreakToken::Word {
23017                    token,
23018                    grapheme_len,
23019                })
23020            }
23021        } else {
23022            None
23023        }
23024    }
23025}
23026
23027#[test]
23028fn test_word_breaking_tokenizer() {
23029    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23030        ("", &[]),
23031        ("  ", &[whitespace("  ", 2)]),
23032        ("Ʒ", &[word("Ʒ", 1)]),
23033        ("Ǽ", &[word("Ǽ", 1)]),
23034        ("", &[word("", 1)]),
23035        ("⋑⋑", &[word("⋑⋑", 2)]),
23036        (
23037            "原理,进而",
23038            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23039        ),
23040        (
23041            "hello world",
23042            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23043        ),
23044        (
23045            "hello, world",
23046            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23047        ),
23048        (
23049            "  hello world",
23050            &[
23051                whitespace("  ", 2),
23052                word("hello", 5),
23053                whitespace(" ", 1),
23054                word("world", 5),
23055            ],
23056        ),
23057        (
23058            "这是什么 \n 钢笔",
23059            &[
23060                word("", 1),
23061                word("", 1),
23062                word("", 1),
23063                word("", 1),
23064                whitespace(" ", 1),
23065                newline(),
23066                whitespace(" ", 1),
23067                word("", 1),
23068                word("", 1),
23069            ],
23070        ),
23071        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23072    ];
23073
23074    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23075        WordBreakToken::Word {
23076            token,
23077            grapheme_len,
23078        }
23079    }
23080
23081    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23082        WordBreakToken::InlineWhitespace {
23083            token,
23084            grapheme_len,
23085        }
23086    }
23087
23088    fn newline() -> WordBreakToken<'static> {
23089        WordBreakToken::Newline
23090    }
23091
23092    for (input, result) in tests {
23093        assert_eq!(
23094            WordBreakingTokenizer::new(input)
23095                .collect::<Vec<_>>()
23096                .as_slice(),
23097            *result,
23098        );
23099    }
23100}
23101
23102fn wrap_with_prefix(
23103    first_line_prefix: String,
23104    subsequent_lines_prefix: String,
23105    unwrapped_text: String,
23106    wrap_column: usize,
23107    tab_size: NonZeroU32,
23108    preserve_existing_whitespace: bool,
23109) -> String {
23110    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23111    let subsequent_lines_prefix_len =
23112        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23113    let mut wrapped_text = String::new();
23114    let mut current_line = first_line_prefix;
23115    let mut is_first_line = true;
23116
23117    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23118    let mut current_line_len = first_line_prefix_len;
23119    let mut in_whitespace = false;
23120    for token in tokenizer {
23121        let have_preceding_whitespace = in_whitespace;
23122        match token {
23123            WordBreakToken::Word {
23124                token,
23125                grapheme_len,
23126            } => {
23127                in_whitespace = false;
23128                let current_prefix_len = if is_first_line {
23129                    first_line_prefix_len
23130                } else {
23131                    subsequent_lines_prefix_len
23132                };
23133                if current_line_len + grapheme_len > wrap_column
23134                    && current_line_len != current_prefix_len
23135                {
23136                    wrapped_text.push_str(current_line.trim_end());
23137                    wrapped_text.push('\n');
23138                    is_first_line = false;
23139                    current_line = subsequent_lines_prefix.clone();
23140                    current_line_len = subsequent_lines_prefix_len;
23141                }
23142                current_line.push_str(token);
23143                current_line_len += grapheme_len;
23144            }
23145            WordBreakToken::InlineWhitespace {
23146                mut token,
23147                mut grapheme_len,
23148            } => {
23149                in_whitespace = true;
23150                if have_preceding_whitespace && !preserve_existing_whitespace {
23151                    continue;
23152                }
23153                if !preserve_existing_whitespace {
23154                    // Keep a single whitespace grapheme as-is
23155                    if let Some(first) =
23156                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23157                    {
23158                        token = first;
23159                    } else {
23160                        token = " ";
23161                    }
23162                    grapheme_len = 1;
23163                }
23164                let current_prefix_len = if is_first_line {
23165                    first_line_prefix_len
23166                } else {
23167                    subsequent_lines_prefix_len
23168                };
23169                if current_line_len + grapheme_len > wrap_column {
23170                    wrapped_text.push_str(current_line.trim_end());
23171                    wrapped_text.push('\n');
23172                    is_first_line = false;
23173                    current_line = subsequent_lines_prefix.clone();
23174                    current_line_len = subsequent_lines_prefix_len;
23175                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23176                    current_line.push_str(token);
23177                    current_line_len += grapheme_len;
23178                }
23179            }
23180            WordBreakToken::Newline => {
23181                in_whitespace = true;
23182                let current_prefix_len = if is_first_line {
23183                    first_line_prefix_len
23184                } else {
23185                    subsequent_lines_prefix_len
23186                };
23187                if preserve_existing_whitespace {
23188                    wrapped_text.push_str(current_line.trim_end());
23189                    wrapped_text.push('\n');
23190                    is_first_line = false;
23191                    current_line = subsequent_lines_prefix.clone();
23192                    current_line_len = subsequent_lines_prefix_len;
23193                } else if have_preceding_whitespace {
23194                    continue;
23195                } else if current_line_len + 1 > wrap_column
23196                    && current_line_len != current_prefix_len
23197                {
23198                    wrapped_text.push_str(current_line.trim_end());
23199                    wrapped_text.push('\n');
23200                    is_first_line = false;
23201                    current_line = subsequent_lines_prefix.clone();
23202                    current_line_len = subsequent_lines_prefix_len;
23203                } else if current_line_len != current_prefix_len {
23204                    current_line.push(' ');
23205                    current_line_len += 1;
23206                }
23207            }
23208        }
23209    }
23210
23211    if !current_line.is_empty() {
23212        wrapped_text.push_str(&current_line);
23213    }
23214    wrapped_text
23215}
23216
23217#[test]
23218fn test_wrap_with_prefix() {
23219    assert_eq!(
23220        wrap_with_prefix(
23221            "# ".to_string(),
23222            "# ".to_string(),
23223            "abcdefg".to_string(),
23224            4,
23225            NonZeroU32::new(4).unwrap(),
23226            false,
23227        ),
23228        "# abcdefg"
23229    );
23230    assert_eq!(
23231        wrap_with_prefix(
23232            "".to_string(),
23233            "".to_string(),
23234            "\thello world".to_string(),
23235            8,
23236            NonZeroU32::new(4).unwrap(),
23237            false,
23238        ),
23239        "hello\nworld"
23240    );
23241    assert_eq!(
23242        wrap_with_prefix(
23243            "// ".to_string(),
23244            "// ".to_string(),
23245            "xx \nyy zz aa bb cc".to_string(),
23246            12,
23247            NonZeroU32::new(4).unwrap(),
23248            false,
23249        ),
23250        "// xx yy zz\n// aa bb cc"
23251    );
23252    assert_eq!(
23253        wrap_with_prefix(
23254            String::new(),
23255            String::new(),
23256            "这是什么 \n 钢笔".to_string(),
23257            3,
23258            NonZeroU32::new(4).unwrap(),
23259            false,
23260        ),
23261        "这是什\n么 钢\n"
23262    );
23263    assert_eq!(
23264        wrap_with_prefix(
23265            String::new(),
23266            String::new(),
23267            format!("foo{}bar", '\u{2009}'), // thin space
23268            80,
23269            NonZeroU32::new(4).unwrap(),
23270            false,
23271        ),
23272        format!("foo{}bar", '\u{2009}')
23273    );
23274}
23275
23276pub trait CollaborationHub {
23277    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23278    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23279    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23280}
23281
23282impl CollaborationHub for Entity<Project> {
23283    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23284        self.read(cx).collaborators()
23285    }
23286
23287    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23288        self.read(cx).user_store().read(cx).participant_indices()
23289    }
23290
23291    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23292        let this = self.read(cx);
23293        let user_ids = this.collaborators().values().map(|c| c.user_id);
23294        this.user_store().read(cx).participant_names(user_ids, cx)
23295    }
23296}
23297
23298pub trait SemanticsProvider {
23299    fn hover(
23300        &self,
23301        buffer: &Entity<Buffer>,
23302        position: text::Anchor,
23303        cx: &mut App,
23304    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23305
23306    fn inline_values(
23307        &self,
23308        buffer_handle: Entity<Buffer>,
23309        range: Range<text::Anchor>,
23310        cx: &mut App,
23311    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23312
23313    fn applicable_inlay_chunks(
23314        &self,
23315        buffer: &Entity<Buffer>,
23316        ranges: &[Range<text::Anchor>],
23317        cx: &mut App,
23318    ) -> Vec<Range<BufferRow>>;
23319
23320    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23321
23322    fn inlay_hints(
23323        &self,
23324        invalidate: InvalidationStrategy,
23325        buffer: Entity<Buffer>,
23326        ranges: Vec<Range<text::Anchor>>,
23327        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23328        cx: &mut App,
23329    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23330
23331    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23332
23333    fn document_highlights(
23334        &self,
23335        buffer: &Entity<Buffer>,
23336        position: text::Anchor,
23337        cx: &mut App,
23338    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23339
23340    fn definitions(
23341        &self,
23342        buffer: &Entity<Buffer>,
23343        position: text::Anchor,
23344        kind: GotoDefinitionKind,
23345        cx: &mut App,
23346    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23347
23348    fn range_for_rename(
23349        &self,
23350        buffer: &Entity<Buffer>,
23351        position: text::Anchor,
23352        cx: &mut App,
23353    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23354
23355    fn perform_rename(
23356        &self,
23357        buffer: &Entity<Buffer>,
23358        position: text::Anchor,
23359        new_name: String,
23360        cx: &mut App,
23361    ) -> Option<Task<Result<ProjectTransaction>>>;
23362}
23363
23364pub trait CompletionProvider {
23365    fn completions(
23366        &self,
23367        excerpt_id: ExcerptId,
23368        buffer: &Entity<Buffer>,
23369        buffer_position: text::Anchor,
23370        trigger: CompletionContext,
23371        window: &mut Window,
23372        cx: &mut Context<Editor>,
23373    ) -> Task<Result<Vec<CompletionResponse>>>;
23374
23375    fn resolve_completions(
23376        &self,
23377        _buffer: Entity<Buffer>,
23378        _completion_indices: Vec<usize>,
23379        _completions: Rc<RefCell<Box<[Completion]>>>,
23380        _cx: &mut Context<Editor>,
23381    ) -> Task<Result<bool>> {
23382        Task::ready(Ok(false))
23383    }
23384
23385    fn apply_additional_edits_for_completion(
23386        &self,
23387        _buffer: Entity<Buffer>,
23388        _completions: Rc<RefCell<Box<[Completion]>>>,
23389        _completion_index: usize,
23390        _push_to_history: bool,
23391        _cx: &mut Context<Editor>,
23392    ) -> Task<Result<Option<language::Transaction>>> {
23393        Task::ready(Ok(None))
23394    }
23395
23396    fn is_completion_trigger(
23397        &self,
23398        buffer: &Entity<Buffer>,
23399        position: language::Anchor,
23400        text: &str,
23401        trigger_in_words: bool,
23402        menu_is_open: bool,
23403        cx: &mut Context<Editor>,
23404    ) -> bool;
23405
23406    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23407
23408    fn sort_completions(&self) -> bool {
23409        true
23410    }
23411
23412    fn filter_completions(&self) -> bool {
23413        true
23414    }
23415
23416    fn show_snippets(&self) -> bool {
23417        false
23418    }
23419}
23420
23421pub trait CodeActionProvider {
23422    fn id(&self) -> Arc<str>;
23423
23424    fn code_actions(
23425        &self,
23426        buffer: &Entity<Buffer>,
23427        range: Range<text::Anchor>,
23428        window: &mut Window,
23429        cx: &mut App,
23430    ) -> Task<Result<Vec<CodeAction>>>;
23431
23432    fn apply_code_action(
23433        &self,
23434        buffer_handle: Entity<Buffer>,
23435        action: CodeAction,
23436        excerpt_id: ExcerptId,
23437        push_to_history: bool,
23438        window: &mut Window,
23439        cx: &mut App,
23440    ) -> Task<Result<ProjectTransaction>>;
23441}
23442
23443impl CodeActionProvider for Entity<Project> {
23444    fn id(&self) -> Arc<str> {
23445        "project".into()
23446    }
23447
23448    fn code_actions(
23449        &self,
23450        buffer: &Entity<Buffer>,
23451        range: Range<text::Anchor>,
23452        _window: &mut Window,
23453        cx: &mut App,
23454    ) -> Task<Result<Vec<CodeAction>>> {
23455        self.update(cx, |project, cx| {
23456            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23457            let code_actions = project.code_actions(buffer, range, None, cx);
23458            cx.background_spawn(async move {
23459                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23460                Ok(code_lens_actions
23461                    .context("code lens fetch")?
23462                    .into_iter()
23463                    .flatten()
23464                    .chain(
23465                        code_actions
23466                            .context("code action fetch")?
23467                            .into_iter()
23468                            .flatten(),
23469                    )
23470                    .collect())
23471            })
23472        })
23473    }
23474
23475    fn apply_code_action(
23476        &self,
23477        buffer_handle: Entity<Buffer>,
23478        action: CodeAction,
23479        _excerpt_id: ExcerptId,
23480        push_to_history: bool,
23481        _window: &mut Window,
23482        cx: &mut App,
23483    ) -> Task<Result<ProjectTransaction>> {
23484        self.update(cx, |project, cx| {
23485            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23486        })
23487    }
23488}
23489
23490fn snippet_completions(
23491    project: &Project,
23492    buffer: &Entity<Buffer>,
23493    buffer_anchor: text::Anchor,
23494    classifier: CharClassifier,
23495    cx: &mut App,
23496) -> Task<Result<CompletionResponse>> {
23497    let languages = buffer.read(cx).languages_at(buffer_anchor);
23498    let snippet_store = project.snippets().read(cx);
23499
23500    let scopes: Vec<_> = languages
23501        .iter()
23502        .filter_map(|language| {
23503            let language_name = language.lsp_id();
23504            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23505
23506            if snippets.is_empty() {
23507                None
23508            } else {
23509                Some((language.default_scope(), snippets))
23510            }
23511        })
23512        .collect();
23513
23514    if scopes.is_empty() {
23515        return Task::ready(Ok(CompletionResponse {
23516            completions: vec![],
23517            display_options: CompletionDisplayOptions::default(),
23518            is_incomplete: false,
23519        }));
23520    }
23521
23522    let snapshot = buffer.read(cx).text_snapshot();
23523    let executor = cx.background_executor().clone();
23524
23525    cx.background_spawn(async move {
23526        let is_word_char = |c| classifier.is_word(c);
23527
23528        let mut is_incomplete = false;
23529        let mut completions: Vec<Completion> = Vec::new();
23530
23531        const MAX_PREFIX_LEN: usize = 128;
23532        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23533        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23534        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23535
23536        let max_buffer_window: String = snapshot
23537            .text_for_range(window_start..buffer_offset)
23538            .collect();
23539
23540        if max_buffer_window.is_empty() {
23541            return Ok(CompletionResponse {
23542                completions: vec![],
23543                display_options: CompletionDisplayOptions::default(),
23544                is_incomplete: true,
23545            });
23546        }
23547
23548        for (_scope, snippets) in scopes.into_iter() {
23549            // Sort snippets by word count to match longer snippet prefixes first.
23550            let mut sorted_snippet_candidates = snippets
23551                .iter()
23552                .enumerate()
23553                .flat_map(|(snippet_ix, snippet)| {
23554                    snippet
23555                        .prefix
23556                        .iter()
23557                        .enumerate()
23558                        .map(move |(prefix_ix, prefix)| {
23559                            let word_count =
23560                                snippet_candidate_suffixes(prefix, is_word_char).count();
23561                            ((snippet_ix, prefix_ix), prefix, word_count)
23562                        })
23563                })
23564                .collect_vec();
23565            sorted_snippet_candidates
23566                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23567
23568            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23569
23570            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23571                .take(
23572                    sorted_snippet_candidates
23573                        .first()
23574                        .map(|(_, _, word_count)| *word_count)
23575                        .unwrap_or_default(),
23576                )
23577                .collect_vec();
23578
23579            const MAX_RESULTS: usize = 100;
23580            // Each match also remembers how many characters from the buffer it consumed
23581            let mut matches: Vec<(StringMatch, usize)> = vec![];
23582
23583            let mut snippet_list_cutoff_index = 0;
23584            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23585                let word_count = buffer_index + 1;
23586                // Increase `snippet_list_cutoff_index` until we have all of the
23587                // snippets with sufficiently many words.
23588                while sorted_snippet_candidates
23589                    .get(snippet_list_cutoff_index)
23590                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23591                        *snippet_word_count >= word_count
23592                    })
23593                {
23594                    snippet_list_cutoff_index += 1;
23595                }
23596
23597                // Take only the candidates with at least `word_count` many words
23598                let snippet_candidates_at_word_len =
23599                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23600
23601                let candidates = snippet_candidates_at_word_len
23602                    .iter()
23603                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23604                    .enumerate() // index in `sorted_snippet_candidates`
23605                    // First char must match
23606                    .filter(|(_ix, prefix)| {
23607                        itertools::equal(
23608                            prefix
23609                                .chars()
23610                                .next()
23611                                .into_iter()
23612                                .flat_map(|c| c.to_lowercase()),
23613                            buffer_window
23614                                .chars()
23615                                .next()
23616                                .into_iter()
23617                                .flat_map(|c| c.to_lowercase()),
23618                        )
23619                    })
23620                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23621                    .collect::<Vec<StringMatchCandidate>>();
23622
23623                matches.extend(
23624                    fuzzy::match_strings(
23625                        &candidates,
23626                        &buffer_window,
23627                        buffer_window.chars().any(|c| c.is_uppercase()),
23628                        true,
23629                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23630                        &Default::default(),
23631                        executor.clone(),
23632                    )
23633                    .await
23634                    .into_iter()
23635                    .map(|string_match| (string_match, buffer_window.len())),
23636                );
23637
23638                if matches.len() >= MAX_RESULTS {
23639                    break;
23640                }
23641            }
23642
23643            let to_lsp = |point: &text::Anchor| {
23644                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23645                point_to_lsp(end)
23646            };
23647            let lsp_end = to_lsp(&buffer_anchor);
23648
23649            if matches.len() >= MAX_RESULTS {
23650                is_incomplete = true;
23651            }
23652
23653            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23654                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23655                    sorted_snippet_candidates[string_match.candidate_id];
23656                let snippet = &snippets[snippet_index];
23657                let start = buffer_offset - buffer_window_len;
23658                let start = snapshot.anchor_before(start);
23659                let range = start..buffer_anchor;
23660                let lsp_start = to_lsp(&start);
23661                let lsp_range = lsp::Range {
23662                    start: lsp_start,
23663                    end: lsp_end,
23664                };
23665                Completion {
23666                    replace_range: range,
23667                    new_text: snippet.body.clone(),
23668                    source: CompletionSource::Lsp {
23669                        insert_range: None,
23670                        server_id: LanguageServerId(usize::MAX),
23671                        resolved: true,
23672                        lsp_completion: Box::new(lsp::CompletionItem {
23673                            label: snippet.prefix.first().unwrap().clone(),
23674                            kind: Some(CompletionItemKind::SNIPPET),
23675                            label_details: snippet.description.as_ref().map(|description| {
23676                                lsp::CompletionItemLabelDetails {
23677                                    detail: Some(description.clone()),
23678                                    description: None,
23679                                }
23680                            }),
23681                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23682                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23683                                lsp::InsertReplaceEdit {
23684                                    new_text: snippet.body.clone(),
23685                                    insert: lsp_range,
23686                                    replace: lsp_range,
23687                                },
23688                            )),
23689                            filter_text: Some(snippet.body.clone()),
23690                            sort_text: Some(char::MAX.to_string()),
23691                            ..lsp::CompletionItem::default()
23692                        }),
23693                        lsp_defaults: None,
23694                    },
23695                    label: CodeLabel {
23696                        text: matching_prefix.clone(),
23697                        runs: Vec::new(),
23698                        filter_range: 0..matching_prefix.len(),
23699                    },
23700                    icon_path: None,
23701                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23702                        single_line: snippet.name.clone().into(),
23703                        plain_text: snippet
23704                            .description
23705                            .clone()
23706                            .map(|description| description.into()),
23707                    }),
23708                    insert_text_mode: None,
23709                    confirm: None,
23710                    match_start: Some(start),
23711                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23712                }
23713            }));
23714        }
23715
23716        Ok(CompletionResponse {
23717            completions,
23718            display_options: CompletionDisplayOptions::default(),
23719            is_incomplete,
23720        })
23721    })
23722}
23723
23724impl CompletionProvider for Entity<Project> {
23725    fn completions(
23726        &self,
23727        _excerpt_id: ExcerptId,
23728        buffer: &Entity<Buffer>,
23729        buffer_position: text::Anchor,
23730        options: CompletionContext,
23731        _window: &mut Window,
23732        cx: &mut Context<Editor>,
23733    ) -> Task<Result<Vec<CompletionResponse>>> {
23734        self.update(cx, |project, cx| {
23735            let task = project.completions(buffer, buffer_position, options, cx);
23736            cx.background_spawn(task)
23737        })
23738    }
23739
23740    fn resolve_completions(
23741        &self,
23742        buffer: Entity<Buffer>,
23743        completion_indices: Vec<usize>,
23744        completions: Rc<RefCell<Box<[Completion]>>>,
23745        cx: &mut Context<Editor>,
23746    ) -> Task<Result<bool>> {
23747        self.update(cx, |project, cx| {
23748            project.lsp_store().update(cx, |lsp_store, cx| {
23749                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23750            })
23751        })
23752    }
23753
23754    fn apply_additional_edits_for_completion(
23755        &self,
23756        buffer: Entity<Buffer>,
23757        completions: Rc<RefCell<Box<[Completion]>>>,
23758        completion_index: usize,
23759        push_to_history: bool,
23760        cx: &mut Context<Editor>,
23761    ) -> Task<Result<Option<language::Transaction>>> {
23762        self.update(cx, |project, cx| {
23763            project.lsp_store().update(cx, |lsp_store, cx| {
23764                lsp_store.apply_additional_edits_for_completion(
23765                    buffer,
23766                    completions,
23767                    completion_index,
23768                    push_to_history,
23769                    cx,
23770                )
23771            })
23772        })
23773    }
23774
23775    fn is_completion_trigger(
23776        &self,
23777        buffer: &Entity<Buffer>,
23778        position: language::Anchor,
23779        text: &str,
23780        trigger_in_words: bool,
23781        menu_is_open: bool,
23782        cx: &mut Context<Editor>,
23783    ) -> bool {
23784        let mut chars = text.chars();
23785        let char = if let Some(char) = chars.next() {
23786            char
23787        } else {
23788            return false;
23789        };
23790        if chars.next().is_some() {
23791            return false;
23792        }
23793
23794        let buffer = buffer.read(cx);
23795        let snapshot = buffer.snapshot();
23796        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23797            return false;
23798        }
23799        let classifier = snapshot
23800            .char_classifier_at(position)
23801            .scope_context(Some(CharScopeContext::Completion));
23802        if trigger_in_words && classifier.is_word(char) {
23803            return true;
23804        }
23805
23806        buffer.completion_triggers().contains(text)
23807    }
23808
23809    fn show_snippets(&self) -> bool {
23810        true
23811    }
23812}
23813
23814impl SemanticsProvider for Entity<Project> {
23815    fn hover(
23816        &self,
23817        buffer: &Entity<Buffer>,
23818        position: text::Anchor,
23819        cx: &mut App,
23820    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23821        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23822    }
23823
23824    fn document_highlights(
23825        &self,
23826        buffer: &Entity<Buffer>,
23827        position: text::Anchor,
23828        cx: &mut App,
23829    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23830        Some(self.update(cx, |project, cx| {
23831            project.document_highlights(buffer, position, cx)
23832        }))
23833    }
23834
23835    fn definitions(
23836        &self,
23837        buffer: &Entity<Buffer>,
23838        position: text::Anchor,
23839        kind: GotoDefinitionKind,
23840        cx: &mut App,
23841    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23842        Some(self.update(cx, |project, cx| match kind {
23843            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23844            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23845            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23846            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23847        }))
23848    }
23849
23850    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23851        self.update(cx, |project, cx| {
23852            if project
23853                .active_debug_session(cx)
23854                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23855            {
23856                return true;
23857            }
23858
23859            buffer.update(cx, |buffer, cx| {
23860                project.any_language_server_supports_inlay_hints(buffer, cx)
23861            })
23862        })
23863    }
23864
23865    fn inline_values(
23866        &self,
23867        buffer_handle: Entity<Buffer>,
23868        range: Range<text::Anchor>,
23869        cx: &mut App,
23870    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23871        self.update(cx, |project, cx| {
23872            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23873
23874            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23875        })
23876    }
23877
23878    fn applicable_inlay_chunks(
23879        &self,
23880        buffer: &Entity<Buffer>,
23881        ranges: &[Range<text::Anchor>],
23882        cx: &mut App,
23883    ) -> Vec<Range<BufferRow>> {
23884        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23885            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23886        })
23887    }
23888
23889    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23890        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23891            lsp_store.invalidate_inlay_hints(for_buffers)
23892        });
23893    }
23894
23895    fn inlay_hints(
23896        &self,
23897        invalidate: InvalidationStrategy,
23898        buffer: Entity<Buffer>,
23899        ranges: Vec<Range<text::Anchor>>,
23900        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23901        cx: &mut App,
23902    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23903        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23904            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23905        }))
23906    }
23907
23908    fn range_for_rename(
23909        &self,
23910        buffer: &Entity<Buffer>,
23911        position: text::Anchor,
23912        cx: &mut App,
23913    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23914        Some(self.update(cx, |project, cx| {
23915            let buffer = buffer.clone();
23916            let task = project.prepare_rename(buffer.clone(), position, cx);
23917            cx.spawn(async move |_, cx| {
23918                Ok(match task.await? {
23919                    PrepareRenameResponse::Success(range) => Some(range),
23920                    PrepareRenameResponse::InvalidPosition => None,
23921                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23922                        // Fallback on using TreeSitter info to determine identifier range
23923                        buffer.read_with(cx, |buffer, _| {
23924                            let snapshot = buffer.snapshot();
23925                            let (range, kind) = snapshot.surrounding_word(position, None);
23926                            if kind != Some(CharKind::Word) {
23927                                return None;
23928                            }
23929                            Some(
23930                                snapshot.anchor_before(range.start)
23931                                    ..snapshot.anchor_after(range.end),
23932                            )
23933                        })?
23934                    }
23935                })
23936            })
23937        }))
23938    }
23939
23940    fn perform_rename(
23941        &self,
23942        buffer: &Entity<Buffer>,
23943        position: text::Anchor,
23944        new_name: String,
23945        cx: &mut App,
23946    ) -> Option<Task<Result<ProjectTransaction>>> {
23947        Some(self.update(cx, |project, cx| {
23948            project.perform_rename(buffer.clone(), position, new_name, cx)
23949        }))
23950    }
23951}
23952
23953fn consume_contiguous_rows(
23954    contiguous_row_selections: &mut Vec<Selection<Point>>,
23955    selection: &Selection<Point>,
23956    display_map: &DisplaySnapshot,
23957    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23958) -> (MultiBufferRow, MultiBufferRow) {
23959    contiguous_row_selections.push(selection.clone());
23960    let start_row = starting_row(selection, display_map);
23961    let mut end_row = ending_row(selection, display_map);
23962
23963    while let Some(next_selection) = selections.peek() {
23964        if next_selection.start.row <= end_row.0 {
23965            end_row = ending_row(next_selection, display_map);
23966            contiguous_row_selections.push(selections.next().unwrap().clone());
23967        } else {
23968            break;
23969        }
23970    }
23971    (start_row, end_row)
23972}
23973
23974fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23975    if selection.start.column > 0 {
23976        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23977    } else {
23978        MultiBufferRow(selection.start.row)
23979    }
23980}
23981
23982fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23983    if next_selection.end.column > 0 || next_selection.is_empty() {
23984        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23985    } else {
23986        MultiBufferRow(next_selection.end.row)
23987    }
23988}
23989
23990impl EditorSnapshot {
23991    pub fn remote_selections_in_range<'a>(
23992        &'a self,
23993        range: &'a Range<Anchor>,
23994        collaboration_hub: &dyn CollaborationHub,
23995        cx: &'a App,
23996    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23997        let participant_names = collaboration_hub.user_names(cx);
23998        let participant_indices = collaboration_hub.user_participant_indices(cx);
23999        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24000        let collaborators_by_replica_id = collaborators_by_peer_id
24001            .values()
24002            .map(|collaborator| (collaborator.replica_id, collaborator))
24003            .collect::<HashMap<_, _>>();
24004        self.buffer_snapshot()
24005            .selections_in_range(range, false)
24006            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24007                if replica_id == ReplicaId::AGENT {
24008                    Some(RemoteSelection {
24009                        replica_id,
24010                        selection,
24011                        cursor_shape,
24012                        line_mode,
24013                        collaborator_id: CollaboratorId::Agent,
24014                        user_name: Some("Agent".into()),
24015                        color: cx.theme().players().agent(),
24016                    })
24017                } else {
24018                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24019                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24020                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24021                    Some(RemoteSelection {
24022                        replica_id,
24023                        selection,
24024                        cursor_shape,
24025                        line_mode,
24026                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24027                        user_name,
24028                        color: if let Some(index) = participant_index {
24029                            cx.theme().players().color_for_participant(index.0)
24030                        } else {
24031                            cx.theme().players().absent()
24032                        },
24033                    })
24034                }
24035            })
24036    }
24037
24038    pub fn hunks_for_ranges(
24039        &self,
24040        ranges: impl IntoIterator<Item = Range<Point>>,
24041    ) -> Vec<MultiBufferDiffHunk> {
24042        let mut hunks = Vec::new();
24043        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24044            HashMap::default();
24045        for query_range in ranges {
24046            let query_rows =
24047                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24048            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24049                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24050            ) {
24051                // Include deleted hunks that are adjacent to the query range, because
24052                // otherwise they would be missed.
24053                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24054                if hunk.status().is_deleted() {
24055                    intersects_range |= hunk.row_range.start == query_rows.end;
24056                    intersects_range |= hunk.row_range.end == query_rows.start;
24057                }
24058                if intersects_range {
24059                    if !processed_buffer_rows
24060                        .entry(hunk.buffer_id)
24061                        .or_default()
24062                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24063                    {
24064                        continue;
24065                    }
24066                    hunks.push(hunk);
24067                }
24068            }
24069        }
24070
24071        hunks
24072    }
24073
24074    fn display_diff_hunks_for_rows<'a>(
24075        &'a self,
24076        display_rows: Range<DisplayRow>,
24077        folded_buffers: &'a HashSet<BufferId>,
24078    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24079        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24080        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24081
24082        self.buffer_snapshot()
24083            .diff_hunks_in_range(buffer_start..buffer_end)
24084            .filter_map(|hunk| {
24085                if folded_buffers.contains(&hunk.buffer_id) {
24086                    return None;
24087                }
24088
24089                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24090                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24091
24092                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24093                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24094
24095                let display_hunk = if hunk_display_start.column() != 0 {
24096                    DisplayDiffHunk::Folded {
24097                        display_row: hunk_display_start.row(),
24098                    }
24099                } else {
24100                    let mut end_row = hunk_display_end.row();
24101                    if hunk_display_end.column() > 0 {
24102                        end_row.0 += 1;
24103                    }
24104                    let is_created_file = hunk.is_created_file();
24105                    DisplayDiffHunk::Unfolded {
24106                        status: hunk.status(),
24107                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24108                            ..hunk.diff_base_byte_range.end.0,
24109                        display_row_range: hunk_display_start.row()..end_row,
24110                        multi_buffer_range: Anchor::range_in_buffer(
24111                            hunk.excerpt_id,
24112                            hunk.buffer_range,
24113                        ),
24114                        is_created_file,
24115                    }
24116                };
24117
24118                Some(display_hunk)
24119            })
24120    }
24121
24122    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24123        self.display_snapshot
24124            .buffer_snapshot()
24125            .language_at(position)
24126    }
24127
24128    pub fn is_focused(&self) -> bool {
24129        self.is_focused
24130    }
24131
24132    pub fn placeholder_text(&self) -> Option<String> {
24133        self.placeholder_display_snapshot
24134            .as_ref()
24135            .map(|display_map| display_map.text())
24136    }
24137
24138    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24139        self.scroll_anchor.scroll_position(&self.display_snapshot)
24140    }
24141
24142    fn gutter_dimensions(
24143        &self,
24144        font_id: FontId,
24145        font_size: Pixels,
24146        max_line_number_width: Pixels,
24147        cx: &App,
24148    ) -> Option<GutterDimensions> {
24149        if !self.show_gutter {
24150            return None;
24151        }
24152
24153        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24154        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24155
24156        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24157            matches!(
24158                ProjectSettings::get_global(cx).git.git_gutter,
24159                GitGutterSetting::TrackedFiles
24160            )
24161        });
24162        let gutter_settings = EditorSettings::get_global(cx).gutter;
24163        let show_line_numbers = self
24164            .show_line_numbers
24165            .unwrap_or(gutter_settings.line_numbers);
24166        let line_gutter_width = if show_line_numbers {
24167            // Avoid flicker-like gutter resizes when the line number gains another digit by
24168            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24169            let min_width_for_number_on_gutter =
24170                ch_advance * gutter_settings.min_line_number_digits as f32;
24171            max_line_number_width.max(min_width_for_number_on_gutter)
24172        } else {
24173            0.0.into()
24174        };
24175
24176        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24177        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24178
24179        let git_blame_entries_width =
24180            self.git_blame_gutter_max_author_length
24181                .map(|max_author_length| {
24182                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24183                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24184
24185                    /// The number of characters to dedicate to gaps and margins.
24186                    const SPACING_WIDTH: usize = 4;
24187
24188                    let max_char_count = max_author_length.min(renderer.max_author_length())
24189                        + ::git::SHORT_SHA_LENGTH
24190                        + MAX_RELATIVE_TIMESTAMP.len()
24191                        + SPACING_WIDTH;
24192
24193                    ch_advance * max_char_count
24194                });
24195
24196        let is_singleton = self.buffer_snapshot().is_singleton();
24197
24198        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24199        left_padding += if !is_singleton {
24200            ch_width * 4.0
24201        } else if show_runnables || show_breakpoints {
24202            ch_width * 3.0
24203        } else if show_git_gutter && show_line_numbers {
24204            ch_width * 2.0
24205        } else if show_git_gutter || show_line_numbers {
24206            ch_width
24207        } else {
24208            px(0.)
24209        };
24210
24211        let shows_folds = is_singleton && gutter_settings.folds;
24212
24213        let right_padding = if shows_folds && show_line_numbers {
24214            ch_width * 4.0
24215        } else if shows_folds || (!is_singleton && show_line_numbers) {
24216            ch_width * 3.0
24217        } else if show_line_numbers {
24218            ch_width
24219        } else {
24220            px(0.)
24221        };
24222
24223        Some(GutterDimensions {
24224            left_padding,
24225            right_padding,
24226            width: line_gutter_width + left_padding + right_padding,
24227            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24228            git_blame_entries_width,
24229        })
24230    }
24231
24232    pub fn render_crease_toggle(
24233        &self,
24234        buffer_row: MultiBufferRow,
24235        row_contains_cursor: bool,
24236        editor: Entity<Editor>,
24237        window: &mut Window,
24238        cx: &mut App,
24239    ) -> Option<AnyElement> {
24240        let folded = self.is_line_folded(buffer_row);
24241        let mut is_foldable = false;
24242
24243        if let Some(crease) = self
24244            .crease_snapshot
24245            .query_row(buffer_row, self.buffer_snapshot())
24246        {
24247            is_foldable = true;
24248            match crease {
24249                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24250                    if let Some(render_toggle) = render_toggle {
24251                        let toggle_callback =
24252                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24253                                if folded {
24254                                    editor.update(cx, |editor, cx| {
24255                                        editor.fold_at(buffer_row, window, cx)
24256                                    });
24257                                } else {
24258                                    editor.update(cx, |editor, cx| {
24259                                        editor.unfold_at(buffer_row, window, cx)
24260                                    });
24261                                }
24262                            });
24263                        return Some((render_toggle)(
24264                            buffer_row,
24265                            folded,
24266                            toggle_callback,
24267                            window,
24268                            cx,
24269                        ));
24270                    }
24271                }
24272            }
24273        }
24274
24275        is_foldable |= self.starts_indent(buffer_row);
24276
24277        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24278            Some(
24279                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24280                    .toggle_state(folded)
24281                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24282                        if folded {
24283                            this.unfold_at(buffer_row, window, cx);
24284                        } else {
24285                            this.fold_at(buffer_row, window, cx);
24286                        }
24287                    }))
24288                    .into_any_element(),
24289            )
24290        } else {
24291            None
24292        }
24293    }
24294
24295    pub fn render_crease_trailer(
24296        &self,
24297        buffer_row: MultiBufferRow,
24298        window: &mut Window,
24299        cx: &mut App,
24300    ) -> Option<AnyElement> {
24301        let folded = self.is_line_folded(buffer_row);
24302        if let Crease::Inline { render_trailer, .. } = self
24303            .crease_snapshot
24304            .query_row(buffer_row, self.buffer_snapshot())?
24305        {
24306            let render_trailer = render_trailer.as_ref()?;
24307            Some(render_trailer(buffer_row, folded, window, cx))
24308        } else {
24309            None
24310        }
24311    }
24312}
24313
24314impl Deref for EditorSnapshot {
24315    type Target = DisplaySnapshot;
24316
24317    fn deref(&self) -> &Self::Target {
24318        &self.display_snapshot
24319    }
24320}
24321
24322#[derive(Clone, Debug, PartialEq, Eq)]
24323pub enum EditorEvent {
24324    InputIgnored {
24325        text: Arc<str>,
24326    },
24327    InputHandled {
24328        utf16_range_to_replace: Option<Range<isize>>,
24329        text: Arc<str>,
24330    },
24331    ExcerptsAdded {
24332        buffer: Entity<Buffer>,
24333        predecessor: ExcerptId,
24334        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24335    },
24336    ExcerptsRemoved {
24337        ids: Vec<ExcerptId>,
24338        removed_buffer_ids: Vec<BufferId>,
24339    },
24340    BufferFoldToggled {
24341        ids: Vec<ExcerptId>,
24342        folded: bool,
24343    },
24344    ExcerptsEdited {
24345        ids: Vec<ExcerptId>,
24346    },
24347    ExcerptsExpanded {
24348        ids: Vec<ExcerptId>,
24349    },
24350    BufferEdited,
24351    Edited {
24352        transaction_id: clock::Lamport,
24353    },
24354    Reparsed(BufferId),
24355    Focused,
24356    FocusedIn,
24357    Blurred,
24358    DirtyChanged,
24359    Saved,
24360    TitleChanged,
24361    SelectionsChanged {
24362        local: bool,
24363    },
24364    ScrollPositionChanged {
24365        local: bool,
24366        autoscroll: bool,
24367    },
24368    TransactionUndone {
24369        transaction_id: clock::Lamport,
24370    },
24371    TransactionBegun {
24372        transaction_id: clock::Lamport,
24373    },
24374    CursorShapeChanged,
24375    BreadcrumbsChanged,
24376    PushedToNavHistory {
24377        anchor: Anchor,
24378        is_deactivate: bool,
24379    },
24380}
24381
24382impl EventEmitter<EditorEvent> for Editor {}
24383
24384impl Focusable for Editor {
24385    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24386        self.focus_handle.clone()
24387    }
24388}
24389
24390impl Render for Editor {
24391    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24392        let settings = ThemeSettings::get_global(cx);
24393
24394        let mut text_style = match self.mode {
24395            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24396                color: cx.theme().colors().editor_foreground,
24397                font_family: settings.ui_font.family.clone(),
24398                font_features: settings.ui_font.features.clone(),
24399                font_fallbacks: settings.ui_font.fallbacks.clone(),
24400                font_size: rems(0.875).into(),
24401                font_weight: settings.ui_font.weight,
24402                line_height: relative(settings.buffer_line_height.value()),
24403                ..Default::default()
24404            },
24405            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24406                color: cx.theme().colors().editor_foreground,
24407                font_family: settings.buffer_font.family.clone(),
24408                font_features: settings.buffer_font.features.clone(),
24409                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24410                font_size: settings.buffer_font_size(cx).into(),
24411                font_weight: settings.buffer_font.weight,
24412                line_height: relative(settings.buffer_line_height.value()),
24413                ..Default::default()
24414            },
24415        };
24416        if let Some(text_style_refinement) = &self.text_style_refinement {
24417            text_style.refine(text_style_refinement)
24418        }
24419
24420        let background = match self.mode {
24421            EditorMode::SingleLine => cx.theme().system().transparent,
24422            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24423            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24424            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24425        };
24426
24427        EditorElement::new(
24428            &cx.entity(),
24429            EditorStyle {
24430                background,
24431                border: cx.theme().colors().border,
24432                local_player: cx.theme().players().local(),
24433                text: text_style,
24434                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24435                syntax: cx.theme().syntax().clone(),
24436                status: cx.theme().status().clone(),
24437                inlay_hints_style: make_inlay_hints_style(cx),
24438                edit_prediction_styles: make_suggestion_styles(cx),
24439                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24440                show_underlines: self.diagnostics_enabled(),
24441            },
24442        )
24443    }
24444}
24445
24446impl EntityInputHandler for Editor {
24447    fn text_for_range(
24448        &mut self,
24449        range_utf16: Range<usize>,
24450        adjusted_range: &mut Option<Range<usize>>,
24451        _: &mut Window,
24452        cx: &mut Context<Self>,
24453    ) -> Option<String> {
24454        let snapshot = self.buffer.read(cx).read(cx);
24455        let start = snapshot.clip_offset_utf16(
24456            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24457            Bias::Left,
24458        );
24459        let end = snapshot.clip_offset_utf16(
24460            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24461            Bias::Right,
24462        );
24463        if (start.0.0..end.0.0) != range_utf16 {
24464            adjusted_range.replace(start.0.0..end.0.0);
24465        }
24466        Some(snapshot.text_for_range(start..end).collect())
24467    }
24468
24469    fn selected_text_range(
24470        &mut self,
24471        ignore_disabled_input: bool,
24472        _: &mut Window,
24473        cx: &mut Context<Self>,
24474    ) -> Option<UTF16Selection> {
24475        // Prevent the IME menu from appearing when holding down an alphabetic key
24476        // while input is disabled.
24477        if !ignore_disabled_input && !self.input_enabled {
24478            return None;
24479        }
24480
24481        let selection = self
24482            .selections
24483            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24484        let range = selection.range();
24485
24486        Some(UTF16Selection {
24487            range: range.start.0.0..range.end.0.0,
24488            reversed: selection.reversed,
24489        })
24490    }
24491
24492    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24493        let snapshot = self.buffer.read(cx).read(cx);
24494        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24495        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24496    }
24497
24498    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24499        self.clear_highlights::<InputComposition>(cx);
24500        self.ime_transaction.take();
24501    }
24502
24503    fn replace_text_in_range(
24504        &mut self,
24505        range_utf16: Option<Range<usize>>,
24506        text: &str,
24507        window: &mut Window,
24508        cx: &mut Context<Self>,
24509    ) {
24510        if !self.input_enabled {
24511            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24512            return;
24513        }
24514
24515        self.transact(window, cx, |this, window, cx| {
24516            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24517                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24518                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24519                Some(this.selection_replacement_ranges(range_utf16, cx))
24520            } else {
24521                this.marked_text_ranges(cx)
24522            };
24523
24524            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24525                let newest_selection_id = this.selections.newest_anchor().id;
24526                this.selections
24527                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24528                    .iter()
24529                    .zip(ranges_to_replace.iter())
24530                    .find_map(|(selection, range)| {
24531                        if selection.id == newest_selection_id {
24532                            Some(
24533                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24534                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24535                            )
24536                        } else {
24537                            None
24538                        }
24539                    })
24540            });
24541
24542            cx.emit(EditorEvent::InputHandled {
24543                utf16_range_to_replace: range_to_replace,
24544                text: text.into(),
24545            });
24546
24547            if let Some(new_selected_ranges) = new_selected_ranges {
24548                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24549                    selections.select_ranges(new_selected_ranges)
24550                });
24551                this.backspace(&Default::default(), window, cx);
24552            }
24553
24554            this.handle_input(text, window, cx);
24555        });
24556
24557        if let Some(transaction) = self.ime_transaction {
24558            self.buffer.update(cx, |buffer, cx| {
24559                buffer.group_until_transaction(transaction, cx);
24560            });
24561        }
24562
24563        self.unmark_text(window, cx);
24564    }
24565
24566    fn replace_and_mark_text_in_range(
24567        &mut self,
24568        range_utf16: Option<Range<usize>>,
24569        text: &str,
24570        new_selected_range_utf16: Option<Range<usize>>,
24571        window: &mut Window,
24572        cx: &mut Context<Self>,
24573    ) {
24574        if !self.input_enabled {
24575            return;
24576        }
24577
24578        let transaction = self.transact(window, cx, |this, window, cx| {
24579            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24580                let snapshot = this.buffer.read(cx).read(cx);
24581                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24582                    for marked_range in &mut marked_ranges {
24583                        marked_range.end = marked_range.start + relative_range_utf16.end;
24584                        marked_range.start += relative_range_utf16.start;
24585                        marked_range.start =
24586                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24587                        marked_range.end =
24588                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24589                    }
24590                }
24591                Some(marked_ranges)
24592            } else if let Some(range_utf16) = range_utf16 {
24593                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24594                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24595                Some(this.selection_replacement_ranges(range_utf16, cx))
24596            } else {
24597                None
24598            };
24599
24600            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24601                let newest_selection_id = this.selections.newest_anchor().id;
24602                this.selections
24603                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24604                    .iter()
24605                    .zip(ranges_to_replace.iter())
24606                    .find_map(|(selection, range)| {
24607                        if selection.id == newest_selection_id {
24608                            Some(
24609                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24610                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24611                            )
24612                        } else {
24613                            None
24614                        }
24615                    })
24616            });
24617
24618            cx.emit(EditorEvent::InputHandled {
24619                utf16_range_to_replace: range_to_replace,
24620                text: text.into(),
24621            });
24622
24623            if let Some(ranges) = ranges_to_replace {
24624                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24625                    s.select_ranges(ranges)
24626                });
24627            }
24628
24629            let marked_ranges = {
24630                let snapshot = this.buffer.read(cx).read(cx);
24631                this.selections
24632                    .disjoint_anchors_arc()
24633                    .iter()
24634                    .map(|selection| {
24635                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24636                    })
24637                    .collect::<Vec<_>>()
24638            };
24639
24640            if text.is_empty() {
24641                this.unmark_text(window, cx);
24642            } else {
24643                this.highlight_text::<InputComposition>(
24644                    marked_ranges.clone(),
24645                    HighlightStyle {
24646                        underline: Some(UnderlineStyle {
24647                            thickness: px(1.),
24648                            color: None,
24649                            wavy: false,
24650                        }),
24651                        ..Default::default()
24652                    },
24653                    cx,
24654                );
24655            }
24656
24657            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24658            let use_autoclose = this.use_autoclose;
24659            let use_auto_surround = this.use_auto_surround;
24660            this.set_use_autoclose(false);
24661            this.set_use_auto_surround(false);
24662            this.handle_input(text, window, cx);
24663            this.set_use_autoclose(use_autoclose);
24664            this.set_use_auto_surround(use_auto_surround);
24665
24666            if let Some(new_selected_range) = new_selected_range_utf16 {
24667                let snapshot = this.buffer.read(cx).read(cx);
24668                let new_selected_ranges = marked_ranges
24669                    .into_iter()
24670                    .map(|marked_range| {
24671                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24672                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24673                            insertion_start.0 + new_selected_range.start,
24674                        ));
24675                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24676                            insertion_start.0 + new_selected_range.end,
24677                        ));
24678                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24679                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24680                    })
24681                    .collect::<Vec<_>>();
24682
24683                drop(snapshot);
24684                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24685                    selections.select_ranges(new_selected_ranges)
24686                });
24687            }
24688        });
24689
24690        self.ime_transaction = self.ime_transaction.or(transaction);
24691        if let Some(transaction) = self.ime_transaction {
24692            self.buffer.update(cx, |buffer, cx| {
24693                buffer.group_until_transaction(transaction, cx);
24694            });
24695        }
24696
24697        if self.text_highlights::<InputComposition>(cx).is_none() {
24698            self.ime_transaction.take();
24699        }
24700    }
24701
24702    fn bounds_for_range(
24703        &mut self,
24704        range_utf16: Range<usize>,
24705        element_bounds: gpui::Bounds<Pixels>,
24706        window: &mut Window,
24707        cx: &mut Context<Self>,
24708    ) -> Option<gpui::Bounds<Pixels>> {
24709        let text_layout_details = self.text_layout_details(window);
24710        let CharacterDimensions {
24711            em_width,
24712            em_advance,
24713            line_height,
24714        } = self.character_dimensions(window);
24715
24716        let snapshot = self.snapshot(window, cx);
24717        let scroll_position = snapshot.scroll_position();
24718        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24719
24720        let start =
24721            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24722        let x = Pixels::from(
24723            ScrollOffset::from(
24724                snapshot.x_for_display_point(start, &text_layout_details)
24725                    + self.gutter_dimensions.full_width(),
24726            ) - scroll_left,
24727        );
24728        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24729
24730        Some(Bounds {
24731            origin: element_bounds.origin + point(x, y),
24732            size: size(em_width, line_height),
24733        })
24734    }
24735
24736    fn character_index_for_point(
24737        &mut self,
24738        point: gpui::Point<Pixels>,
24739        _window: &mut Window,
24740        _cx: &mut Context<Self>,
24741    ) -> Option<usize> {
24742        let position_map = self.last_position_map.as_ref()?;
24743        if !position_map.text_hitbox.contains(&point) {
24744            return None;
24745        }
24746        let display_point = position_map.point_for_position(point).previous_valid;
24747        let anchor = position_map
24748            .snapshot
24749            .display_point_to_anchor(display_point, Bias::Left);
24750        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24751        Some(utf16_offset.0.0)
24752    }
24753
24754    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24755        self.input_enabled
24756    }
24757}
24758
24759trait SelectionExt {
24760    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24761    fn spanned_rows(
24762        &self,
24763        include_end_if_at_line_start: bool,
24764        map: &DisplaySnapshot,
24765    ) -> Range<MultiBufferRow>;
24766}
24767
24768impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24769    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24770        let start = self
24771            .start
24772            .to_point(map.buffer_snapshot())
24773            .to_display_point(map);
24774        let end = self
24775            .end
24776            .to_point(map.buffer_snapshot())
24777            .to_display_point(map);
24778        if self.reversed {
24779            end..start
24780        } else {
24781            start..end
24782        }
24783    }
24784
24785    fn spanned_rows(
24786        &self,
24787        include_end_if_at_line_start: bool,
24788        map: &DisplaySnapshot,
24789    ) -> Range<MultiBufferRow> {
24790        let start = self.start.to_point(map.buffer_snapshot());
24791        let mut end = self.end.to_point(map.buffer_snapshot());
24792        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24793            end.row -= 1;
24794        }
24795
24796        let buffer_start = map.prev_line_boundary(start).0;
24797        let buffer_end = map.next_line_boundary(end).0;
24798        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24799    }
24800}
24801
24802impl<T: InvalidationRegion> InvalidationStack<T> {
24803    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24804    where
24805        S: Clone + ToOffset,
24806    {
24807        while let Some(region) = self.last() {
24808            let all_selections_inside_invalidation_ranges =
24809                if selections.len() == region.ranges().len() {
24810                    selections
24811                        .iter()
24812                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24813                        .all(|(selection, invalidation_range)| {
24814                            let head = selection.head().to_offset(buffer);
24815                            invalidation_range.start <= head && invalidation_range.end >= head
24816                        })
24817                } else {
24818                    false
24819                };
24820
24821            if all_selections_inside_invalidation_ranges {
24822                break;
24823            } else {
24824                self.pop();
24825            }
24826        }
24827    }
24828}
24829
24830impl<T> Default for InvalidationStack<T> {
24831    fn default() -> Self {
24832        Self(Default::default())
24833    }
24834}
24835
24836impl<T> Deref for InvalidationStack<T> {
24837    type Target = Vec<T>;
24838
24839    fn deref(&self) -> &Self::Target {
24840        &self.0
24841    }
24842}
24843
24844impl<T> DerefMut for InvalidationStack<T> {
24845    fn deref_mut(&mut self) -> &mut Self::Target {
24846        &mut self.0
24847    }
24848}
24849
24850impl InvalidationRegion for SnippetState {
24851    fn ranges(&self) -> &[Range<Anchor>] {
24852        &self.ranges[self.active_index]
24853    }
24854}
24855
24856fn edit_prediction_edit_text(
24857    current_snapshot: &BufferSnapshot,
24858    edits: &[(Range<Anchor>, impl AsRef<str>)],
24859    edit_preview: &EditPreview,
24860    include_deletions: bool,
24861    cx: &App,
24862) -> HighlightedText {
24863    let edits = edits
24864        .iter()
24865        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24866        .collect::<Vec<_>>();
24867
24868    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24869}
24870
24871fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24872    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24873    // Just show the raw edit text with basic styling
24874    let mut text = String::new();
24875    let mut highlights = Vec::new();
24876
24877    let insertion_highlight_style = HighlightStyle {
24878        color: Some(cx.theme().colors().text),
24879        ..Default::default()
24880    };
24881
24882    for (_, edit_text) in edits {
24883        let start_offset = text.len();
24884        text.push_str(edit_text);
24885        let end_offset = text.len();
24886
24887        if start_offset < end_offset {
24888            highlights.push((start_offset..end_offset, insertion_highlight_style));
24889        }
24890    }
24891
24892    HighlightedText {
24893        text: text.into(),
24894        highlights,
24895    }
24896}
24897
24898pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24899    match severity {
24900        lsp::DiagnosticSeverity::ERROR => colors.error,
24901        lsp::DiagnosticSeverity::WARNING => colors.warning,
24902        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24903        lsp::DiagnosticSeverity::HINT => colors.info,
24904        _ => colors.ignored,
24905    }
24906}
24907
24908pub fn styled_runs_for_code_label<'a>(
24909    label: &'a CodeLabel,
24910    syntax_theme: &'a theme::SyntaxTheme,
24911) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24912    let fade_out = HighlightStyle {
24913        fade_out: Some(0.35),
24914        ..Default::default()
24915    };
24916
24917    let mut prev_end = label.filter_range.end;
24918    label
24919        .runs
24920        .iter()
24921        .enumerate()
24922        .flat_map(move |(ix, (range, highlight_id))| {
24923            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24924                style
24925            } else {
24926                return Default::default();
24927            };
24928            let muted_style = style.highlight(fade_out);
24929
24930            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24931            if range.start >= label.filter_range.end {
24932                if range.start > prev_end {
24933                    runs.push((prev_end..range.start, fade_out));
24934                }
24935                runs.push((range.clone(), muted_style));
24936            } else if range.end <= label.filter_range.end {
24937                runs.push((range.clone(), style));
24938            } else {
24939                runs.push((range.start..label.filter_range.end, style));
24940                runs.push((label.filter_range.end..range.end, muted_style));
24941            }
24942            prev_end = cmp::max(prev_end, range.end);
24943
24944            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24945                runs.push((prev_end..label.text.len(), fade_out));
24946            }
24947
24948            runs
24949        })
24950}
24951
24952pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24953    let mut prev_index = 0;
24954    let mut prev_codepoint: Option<char> = None;
24955    text.char_indices()
24956        .chain([(text.len(), '\0')])
24957        .filter_map(move |(index, codepoint)| {
24958            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24959            let is_boundary = index == text.len()
24960                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24961                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24962            if is_boundary {
24963                let chunk = &text[prev_index..index];
24964                prev_index = index;
24965                Some(chunk)
24966            } else {
24967                None
24968            }
24969        })
24970}
24971
24972/// Given a string of text immediately before the cursor, iterates over possible
24973/// strings a snippet could match to. More precisely: returns an iterator over
24974/// suffixes of `text` created by splitting at word boundaries (before & after
24975/// every non-word character).
24976///
24977/// Shorter suffixes are returned first.
24978pub(crate) fn snippet_candidate_suffixes(
24979    text: &str,
24980    is_word_char: impl Fn(char) -> bool,
24981) -> impl std::iter::Iterator<Item = &str> {
24982    let mut prev_index = text.len();
24983    let mut prev_codepoint = None;
24984    text.char_indices()
24985        .rev()
24986        .chain([(0, '\0')])
24987        .filter_map(move |(index, codepoint)| {
24988            let prev_index = std::mem::replace(&mut prev_index, index);
24989            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24990            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24991                None
24992            } else {
24993                let chunk = &text[prev_index..]; // go to end of string
24994                Some(chunk)
24995            }
24996        })
24997}
24998
24999pub trait RangeToAnchorExt: Sized {
25000    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25001
25002    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25003        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25004        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25005    }
25006}
25007
25008impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25009    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25010        let start_offset = self.start.to_offset(snapshot);
25011        let end_offset = self.end.to_offset(snapshot);
25012        if start_offset == end_offset {
25013            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25014        } else {
25015            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25016        }
25017    }
25018}
25019
25020pub trait RowExt {
25021    fn as_f64(&self) -> f64;
25022
25023    fn next_row(&self) -> Self;
25024
25025    fn previous_row(&self) -> Self;
25026
25027    fn minus(&self, other: Self) -> u32;
25028}
25029
25030impl RowExt for DisplayRow {
25031    fn as_f64(&self) -> f64 {
25032        self.0 as _
25033    }
25034
25035    fn next_row(&self) -> Self {
25036        Self(self.0 + 1)
25037    }
25038
25039    fn previous_row(&self) -> Self {
25040        Self(self.0.saturating_sub(1))
25041    }
25042
25043    fn minus(&self, other: Self) -> u32 {
25044        self.0 - other.0
25045    }
25046}
25047
25048impl RowExt for MultiBufferRow {
25049    fn as_f64(&self) -> f64 {
25050        self.0 as _
25051    }
25052
25053    fn next_row(&self) -> Self {
25054        Self(self.0 + 1)
25055    }
25056
25057    fn previous_row(&self) -> Self {
25058        Self(self.0.saturating_sub(1))
25059    }
25060
25061    fn minus(&self, other: Self) -> u32 {
25062        self.0 - other.0
25063    }
25064}
25065
25066trait RowRangeExt {
25067    type Row;
25068
25069    fn len(&self) -> usize;
25070
25071    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25072}
25073
25074impl RowRangeExt for Range<MultiBufferRow> {
25075    type Row = MultiBufferRow;
25076
25077    fn len(&self) -> usize {
25078        (self.end.0 - self.start.0) as usize
25079    }
25080
25081    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25082        (self.start.0..self.end.0).map(MultiBufferRow)
25083    }
25084}
25085
25086impl RowRangeExt for Range<DisplayRow> {
25087    type Row = DisplayRow;
25088
25089    fn len(&self) -> usize {
25090        (self.end.0 - self.start.0) as usize
25091    }
25092
25093    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25094        (self.start.0..self.end.0).map(DisplayRow)
25095    }
25096}
25097
25098/// If select range has more than one line, we
25099/// just point the cursor to range.start.
25100fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25101    if range.start.row == range.end.row {
25102        range
25103    } else {
25104        range.start..range.start
25105    }
25106}
25107pub struct KillRing(ClipboardItem);
25108impl Global for KillRing {}
25109
25110const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25111
25112enum BreakpointPromptEditAction {
25113    Log,
25114    Condition,
25115    HitCondition,
25116}
25117
25118struct BreakpointPromptEditor {
25119    pub(crate) prompt: Entity<Editor>,
25120    editor: WeakEntity<Editor>,
25121    breakpoint_anchor: Anchor,
25122    breakpoint: Breakpoint,
25123    edit_action: BreakpointPromptEditAction,
25124    block_ids: HashSet<CustomBlockId>,
25125    editor_margins: Arc<Mutex<EditorMargins>>,
25126    _subscriptions: Vec<Subscription>,
25127}
25128
25129impl BreakpointPromptEditor {
25130    const MAX_LINES: u8 = 4;
25131
25132    fn new(
25133        editor: WeakEntity<Editor>,
25134        breakpoint_anchor: Anchor,
25135        breakpoint: Breakpoint,
25136        edit_action: BreakpointPromptEditAction,
25137        window: &mut Window,
25138        cx: &mut Context<Self>,
25139    ) -> Self {
25140        let base_text = match edit_action {
25141            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25142            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25143            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25144        }
25145        .map(|msg| msg.to_string())
25146        .unwrap_or_default();
25147
25148        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25149        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25150
25151        let prompt = cx.new(|cx| {
25152            let mut prompt = Editor::new(
25153                EditorMode::AutoHeight {
25154                    min_lines: 1,
25155                    max_lines: Some(Self::MAX_LINES as usize),
25156                },
25157                buffer,
25158                None,
25159                window,
25160                cx,
25161            );
25162            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25163            prompt.set_show_cursor_when_unfocused(false, cx);
25164            prompt.set_placeholder_text(
25165                match edit_action {
25166                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25167                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25168                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25169                },
25170                window,
25171                cx,
25172            );
25173
25174            prompt
25175        });
25176
25177        Self {
25178            prompt,
25179            editor,
25180            breakpoint_anchor,
25181            breakpoint,
25182            edit_action,
25183            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25184            block_ids: Default::default(),
25185            _subscriptions: vec![],
25186        }
25187    }
25188
25189    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25190        self.block_ids.extend(block_ids)
25191    }
25192
25193    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25194        if let Some(editor) = self.editor.upgrade() {
25195            let message = self
25196                .prompt
25197                .read(cx)
25198                .buffer
25199                .read(cx)
25200                .as_singleton()
25201                .expect("A multi buffer in breakpoint prompt isn't possible")
25202                .read(cx)
25203                .as_rope()
25204                .to_string();
25205
25206            editor.update(cx, |editor, cx| {
25207                editor.edit_breakpoint_at_anchor(
25208                    self.breakpoint_anchor,
25209                    self.breakpoint.clone(),
25210                    match self.edit_action {
25211                        BreakpointPromptEditAction::Log => {
25212                            BreakpointEditAction::EditLogMessage(message.into())
25213                        }
25214                        BreakpointPromptEditAction::Condition => {
25215                            BreakpointEditAction::EditCondition(message.into())
25216                        }
25217                        BreakpointPromptEditAction::HitCondition => {
25218                            BreakpointEditAction::EditHitCondition(message.into())
25219                        }
25220                    },
25221                    cx,
25222                );
25223
25224                editor.remove_blocks(self.block_ids.clone(), None, cx);
25225                cx.focus_self(window);
25226            });
25227        }
25228    }
25229
25230    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25231        self.editor
25232            .update(cx, |editor, cx| {
25233                editor.remove_blocks(self.block_ids.clone(), None, cx);
25234                window.focus(&editor.focus_handle);
25235            })
25236            .log_err();
25237    }
25238
25239    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25240        let settings = ThemeSettings::get_global(cx);
25241        let text_style = TextStyle {
25242            color: if self.prompt.read(cx).read_only(cx) {
25243                cx.theme().colors().text_disabled
25244            } else {
25245                cx.theme().colors().text
25246            },
25247            font_family: settings.buffer_font.family.clone(),
25248            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25249            font_size: settings.buffer_font_size(cx).into(),
25250            font_weight: settings.buffer_font.weight,
25251            line_height: relative(settings.buffer_line_height.value()),
25252            ..Default::default()
25253        };
25254        EditorElement::new(
25255            &self.prompt,
25256            EditorStyle {
25257                background: cx.theme().colors().editor_background,
25258                local_player: cx.theme().players().local(),
25259                text: text_style,
25260                ..Default::default()
25261            },
25262        )
25263    }
25264}
25265
25266impl Render for BreakpointPromptEditor {
25267    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25268        let editor_margins = *self.editor_margins.lock();
25269        let gutter_dimensions = editor_margins.gutter;
25270        h_flex()
25271            .key_context("Editor")
25272            .bg(cx.theme().colors().editor_background)
25273            .border_y_1()
25274            .border_color(cx.theme().status().info_border)
25275            .size_full()
25276            .py(window.line_height() / 2.5)
25277            .on_action(cx.listener(Self::confirm))
25278            .on_action(cx.listener(Self::cancel))
25279            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25280            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25281    }
25282}
25283
25284impl Focusable for BreakpointPromptEditor {
25285    fn focus_handle(&self, cx: &App) -> FocusHandle {
25286        self.prompt.focus_handle(cx)
25287    }
25288}
25289
25290fn all_edits_insertions_or_deletions(
25291    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25292    snapshot: &MultiBufferSnapshot,
25293) -> bool {
25294    let mut all_insertions = true;
25295    let mut all_deletions = true;
25296
25297    for (range, new_text) in edits.iter() {
25298        let range_is_empty = range.to_offset(snapshot).is_empty();
25299        let text_is_empty = new_text.is_empty();
25300
25301        if range_is_empty != text_is_empty {
25302            if range_is_empty {
25303                all_deletions = false;
25304            } else {
25305                all_insertions = false;
25306            }
25307        } else {
25308            return false;
25309        }
25310
25311        if !all_insertions && !all_deletions {
25312            return false;
25313        }
25314    }
25315    all_insertions || all_deletions
25316}
25317
25318struct MissingEditPredictionKeybindingTooltip;
25319
25320impl Render for MissingEditPredictionKeybindingTooltip {
25321    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25322        ui::tooltip_container(cx, |container, cx| {
25323            container
25324                .flex_shrink_0()
25325                .max_w_80()
25326                .min_h(rems_from_px(124.))
25327                .justify_between()
25328                .child(
25329                    v_flex()
25330                        .flex_1()
25331                        .text_ui_sm(cx)
25332                        .child(Label::new("Conflict with Accept Keybinding"))
25333                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25334                )
25335                .child(
25336                    h_flex()
25337                        .pb_1()
25338                        .gap_1()
25339                        .items_end()
25340                        .w_full()
25341                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25342                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25343                        }))
25344                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25345                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25346                        })),
25347                )
25348        })
25349    }
25350}
25351
25352#[derive(Debug, Clone, Copy, PartialEq)]
25353pub struct LineHighlight {
25354    pub background: Background,
25355    pub border: Option<gpui::Hsla>,
25356    pub include_gutter: bool,
25357    pub type_id: Option<TypeId>,
25358}
25359
25360struct LineManipulationResult {
25361    pub new_text: String,
25362    pub line_count_before: usize,
25363    pub line_count_after: usize,
25364}
25365
25366fn render_diff_hunk_controls(
25367    row: u32,
25368    status: &DiffHunkStatus,
25369    hunk_range: Range<Anchor>,
25370    is_created_file: bool,
25371    line_height: Pixels,
25372    editor: &Entity<Editor>,
25373    _window: &mut Window,
25374    cx: &mut App,
25375) -> AnyElement {
25376    h_flex()
25377        .h(line_height)
25378        .mr_1()
25379        .gap_1()
25380        .px_0p5()
25381        .pb_1()
25382        .border_x_1()
25383        .border_b_1()
25384        .border_color(cx.theme().colors().border_variant)
25385        .rounded_b_lg()
25386        .bg(cx.theme().colors().editor_background)
25387        .gap_1()
25388        .block_mouse_except_scroll()
25389        .shadow_md()
25390        .child(if status.has_secondary_hunk() {
25391            Button::new(("stage", row as u64), "Stage")
25392                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25393                .tooltip({
25394                    let focus_handle = editor.focus_handle(cx);
25395                    move |_window, cx| {
25396                        Tooltip::for_action_in(
25397                            "Stage Hunk",
25398                            &::git::ToggleStaged,
25399                            &focus_handle,
25400                            cx,
25401                        )
25402                    }
25403                })
25404                .on_click({
25405                    let editor = editor.clone();
25406                    move |_event, _window, cx| {
25407                        editor.update(cx, |editor, cx| {
25408                            editor.stage_or_unstage_diff_hunks(
25409                                true,
25410                                vec![hunk_range.start..hunk_range.start],
25411                                cx,
25412                            );
25413                        });
25414                    }
25415                })
25416        } else {
25417            Button::new(("unstage", row as u64), "Unstage")
25418                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25419                .tooltip({
25420                    let focus_handle = editor.focus_handle(cx);
25421                    move |_window, cx| {
25422                        Tooltip::for_action_in(
25423                            "Unstage Hunk",
25424                            &::git::ToggleStaged,
25425                            &focus_handle,
25426                            cx,
25427                        )
25428                    }
25429                })
25430                .on_click({
25431                    let editor = editor.clone();
25432                    move |_event, _window, cx| {
25433                        editor.update(cx, |editor, cx| {
25434                            editor.stage_or_unstage_diff_hunks(
25435                                false,
25436                                vec![hunk_range.start..hunk_range.start],
25437                                cx,
25438                            );
25439                        });
25440                    }
25441                })
25442        })
25443        .child(
25444            Button::new(("restore", row as u64), "Restore")
25445                .tooltip({
25446                    let focus_handle = editor.focus_handle(cx);
25447                    move |_window, cx| {
25448                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25449                    }
25450                })
25451                .on_click({
25452                    let editor = editor.clone();
25453                    move |_event, window, cx| {
25454                        editor.update(cx, |editor, cx| {
25455                            let snapshot = editor.snapshot(window, cx);
25456                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25457                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25458                        });
25459                    }
25460                })
25461                .disabled(is_created_file),
25462        )
25463        .when(
25464            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25465            |el| {
25466                el.child(
25467                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25468                        .shape(IconButtonShape::Square)
25469                        .icon_size(IconSize::Small)
25470                        // .disabled(!has_multiple_hunks)
25471                        .tooltip({
25472                            let focus_handle = editor.focus_handle(cx);
25473                            move |_window, cx| {
25474                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25475                            }
25476                        })
25477                        .on_click({
25478                            let editor = editor.clone();
25479                            move |_event, window, cx| {
25480                                editor.update(cx, |editor, cx| {
25481                                    let snapshot = editor.snapshot(window, cx);
25482                                    let position =
25483                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25484                                    editor.go_to_hunk_before_or_after_position(
25485                                        &snapshot,
25486                                        position,
25487                                        Direction::Next,
25488                                        window,
25489                                        cx,
25490                                    );
25491                                    editor.expand_selected_diff_hunks(cx);
25492                                });
25493                            }
25494                        }),
25495                )
25496                .child(
25497                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25498                        .shape(IconButtonShape::Square)
25499                        .icon_size(IconSize::Small)
25500                        // .disabled(!has_multiple_hunks)
25501                        .tooltip({
25502                            let focus_handle = editor.focus_handle(cx);
25503                            move |_window, cx| {
25504                                Tooltip::for_action_in(
25505                                    "Previous Hunk",
25506                                    &GoToPreviousHunk,
25507                                    &focus_handle,
25508                                    cx,
25509                                )
25510                            }
25511                        })
25512                        .on_click({
25513                            let editor = editor.clone();
25514                            move |_event, window, cx| {
25515                                editor.update(cx, |editor, cx| {
25516                                    let snapshot = editor.snapshot(window, cx);
25517                                    let point =
25518                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25519                                    editor.go_to_hunk_before_or_after_position(
25520                                        &snapshot,
25521                                        point,
25522                                        Direction::Prev,
25523                                        window,
25524                                        cx,
25525                                    );
25526                                    editor.expand_selected_diff_hunks(cx);
25527                                });
25528                            }
25529                        }),
25530                )
25531            },
25532        )
25533        .into_any_element()
25534}
25535
25536pub fn multibuffer_context_lines(cx: &App) -> u32 {
25537    EditorSettings::try_get(cx)
25538        .map(|settings| settings.excerpt_context_lines)
25539        .unwrap_or(2)
25540        .min(32)
25541}