editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod split_editor_view;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction_types::Direction;
   56pub use editor_settings::{
   57    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   58    HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use element::{
   61    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, OverlayPainter,
   62    OverlayPainterData, PointForPosition, render_breadcrumb_text,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use inlays::Inlay;
   67pub use items::MAX_TAB_TITLE_LEN;
   68pub use lsp::CompletionContext;
   69pub use lsp_ext::lsp_tasks;
   70pub use multi_buffer::{
   71    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   72    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   73    ToPoint,
   74};
   75pub use split::{SplitDiffFeatureFlag, SplittableEditor, ToggleLockedCursors, ToggleSplitDiff};
   76pub use split_editor_view::SplitEditorView;
   77pub use text::Bias;
   78
   79use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   80use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   81use anyhow::{Context as _, Result, anyhow, bail};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::ReplicaId;
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction_types::{
   95    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   96    SuggestionDisplayType,
   97};
   98use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   99use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  100use futures::{
  101    FutureExt,
  102    future::{self, Shared, join},
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  112    Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task,
  113    TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  114    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  115    pulsating_between, px, relative, size,
  116};
  117use hover_links::{HoverLink, HoveredLinkState, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  127    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  128    TreeSitterOptions, WordsQuery,
  129    language_settings::{
  130        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  131        all_language_settings, language_settings,
  132    },
  133    point_from_lsp, point_to_lsp, text_diff_with_options,
  134};
  135use linked_editing_ranges::refresh_linked_ranges;
  136use lsp::{
  137    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  138    LanguageServerId,
  139};
  140use lsp_colors::LspColorData;
  141use markdown::Markdown;
  142use mouse_context_menu::MouseContextMenu;
  143use movement::TextLayoutDetails;
  144use multi_buffer::{
  145    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  152    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  153    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::GitStoreEvent,
  162    lsp_store::{
  163        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  164        OpenLspBufferHandle,
  165    },
  166    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  167};
  168use rand::seq::SliceRandom;
  169use regex::Regex;
  170use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  171use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  172use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  173use serde::{Deserialize, Serialize};
  174use settings::{
  175    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  176    update_settings_file,
  177};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::{
  181    any::{Any, TypeId},
  182    borrow::Cow,
  183    cell::{OnceCell, RefCell},
  184    cmp::{self, Ordering, Reverse},
  185    collections::hash_map,
  186    iter::{self, Peekable},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    sync::Arc,
  193    time::{Duration, Instant},
  194};
  195use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  197use theme::{
  198    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  199    ThemeSettings, observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  203    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  204};
  205use ui_input::ErasedEditor;
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  209    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  210    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::{CollapseDirection, SearchEvent},
  214};
  215use zed_actions::editor::{MoveDown, MoveUp};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    editor_settings::MultiCursorModifier,
  220    hover_links::{find_url, find_url_from_range},
  221    inlays::{
  222        InlineValueCache,
  223        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  224    },
  225    scroll::{ScrollOffset, ScrollPixelOffset},
  226    selections_collection::resolve_selections_wrapping_blocks,
  227    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  228};
  229
  230pub const FILE_HEADER_HEIGHT: u32 = 2;
  231pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  232const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  233const MAX_LINE_LEN: usize = 1024;
  234const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  235const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  236pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  237#[doc(hidden)]
  238pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  239pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  240
  241pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  242pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  243pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  244pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  245
  246pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  247pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  248pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  249
  250pub type RenderDiffHunkControlsFn = Arc<
  251    dyn Fn(
  252        u32,
  253        &DiffHunkStatus,
  254        Range<Anchor>,
  255        bool,
  256        Pixels,
  257        &Entity<Editor>,
  258        &mut Window,
  259        &mut App,
  260    ) -> AnyElement,
  261>;
  262
  263enum ReportEditorEvent {
  264    Saved { auto_saved: bool },
  265    EditorOpened,
  266    Closed,
  267}
  268
  269impl ReportEditorEvent {
  270    pub fn event_type(&self) -> &'static str {
  271        match self {
  272            Self::Saved { .. } => "Editor Saved",
  273            Self::EditorOpened => "Editor Opened",
  274            Self::Closed => "Editor Closed",
  275        }
  276    }
  277}
  278
  279pub enum ActiveDebugLine {}
  280pub enum DebugStackFrameLine {}
  281enum DocumentHighlightRead {}
  282enum DocumentHighlightWrite {}
  283enum InputComposition {}
  284pub enum PendingInput {}
  285enum SelectedTextHighlight {}
  286
  287pub enum ConflictsOuter {}
  288pub enum ConflictsOurs {}
  289pub enum ConflictsTheirs {}
  290pub enum ConflictsOursMarker {}
  291pub enum ConflictsTheirsMarker {}
  292
  293pub struct HunkAddedColor;
  294pub struct HunkRemovedColor;
  295
  296#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  297pub enum Navigated {
  298    Yes,
  299    No,
  300}
  301
  302impl Navigated {
  303    pub fn from_bool(yes: bool) -> Navigated {
  304        if yes { Navigated::Yes } else { Navigated::No }
  305    }
  306}
  307
  308#[derive(Debug, Clone, PartialEq, Eq)]
  309enum DisplayDiffHunk {
  310    Folded {
  311        display_row: DisplayRow,
  312    },
  313    Unfolded {
  314        is_created_file: bool,
  315        diff_base_byte_range: Range<usize>,
  316        display_row_range: Range<DisplayRow>,
  317        multi_buffer_range: Range<Anchor>,
  318        status: DiffHunkStatus,
  319        word_diffs: Vec<Range<MultiBufferOffset>>,
  320    },
  321}
  322
  323pub enum HideMouseCursorOrigin {
  324    TypingAction,
  325    MovementAction,
  326}
  327
  328pub fn init(cx: &mut App) {
  329    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  330
  331    workspace::register_project_item::<Editor>(cx);
  332    workspace::FollowableViewRegistry::register::<Editor>(cx);
  333    workspace::register_serializable_item::<Editor>(cx);
  334
  335    cx.observe_new(
  336        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  337            workspace.register_action(Editor::new_file);
  338            workspace.register_action(Editor::new_file_split);
  339            workspace.register_action(Editor::new_file_vertical);
  340            workspace.register_action(Editor::new_file_horizontal);
  341            workspace.register_action(Editor::cancel_language_server_work);
  342            workspace.register_action(Editor::toggle_focus);
  343        },
  344    )
  345    .detach();
  346
  347    cx.on_action(move |_: &workspace::NewFile, cx| {
  348        let app_state = workspace::AppState::global(cx);
  349        if let Some(app_state) = app_state.upgrade() {
  350            workspace::open_new(
  351                Default::default(),
  352                app_state,
  353                cx,
  354                |workspace, window, cx| {
  355                    Editor::new_file(workspace, &Default::default(), window, cx)
  356                },
  357            )
  358            .detach();
  359        }
  360    })
  361    .on_action(move |_: &workspace::NewWindow, cx| {
  362        let app_state = workspace::AppState::global(cx);
  363        if let Some(app_state) = app_state.upgrade() {
  364            workspace::open_new(
  365                Default::default(),
  366                app_state,
  367                cx,
  368                |workspace, window, cx| {
  369                    cx.activate(true);
  370                    Editor::new_file(workspace, &Default::default(), window, cx)
  371                },
  372            )
  373            .detach();
  374        }
  375    });
  376    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  377        Arc::new(ErasedEditorImpl(
  378            cx.new(|cx| Editor::single_line(window, cx)),
  379        )) as Arc<dyn ErasedEditor>
  380    });
  381    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  382}
  383
  384pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  385    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  386}
  387
  388pub trait DiagnosticRenderer {
  389    fn render_group(
  390        &self,
  391        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  392        buffer_id: BufferId,
  393        snapshot: EditorSnapshot,
  394        editor: WeakEntity<Editor>,
  395        language_registry: Option<Arc<LanguageRegistry>>,
  396        cx: &mut App,
  397    ) -> Vec<BlockProperties<Anchor>>;
  398
  399    fn render_hover(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  402        range: Range<Point>,
  403        buffer_id: BufferId,
  404        language_registry: Option<Arc<LanguageRegistry>>,
  405        cx: &mut App,
  406    ) -> Option<Entity<markdown::Markdown>>;
  407
  408    fn open_link(
  409        &self,
  410        editor: &mut Editor,
  411        link: SharedString,
  412        window: &mut Window,
  413        cx: &mut Context<Editor>,
  414    );
  415}
  416
  417pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  418
  419impl GlobalDiagnosticRenderer {
  420    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  421        cx.try_global::<Self>().map(|g| g.0.clone())
  422    }
  423}
  424
  425impl gpui::Global for GlobalDiagnosticRenderer {}
  426pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  427    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  428}
  429
  430pub struct SearchWithinRange;
  431
  432trait InvalidationRegion {
  433    fn ranges(&self) -> &[Range<Anchor>];
  434}
  435
  436#[derive(Clone, Debug, PartialEq)]
  437pub enum SelectPhase {
  438    Begin {
  439        position: DisplayPoint,
  440        add: bool,
  441        click_count: usize,
  442    },
  443    BeginColumnar {
  444        position: DisplayPoint,
  445        reset: bool,
  446        mode: ColumnarMode,
  447        goal_column: u32,
  448    },
  449    Extend {
  450        position: DisplayPoint,
  451        click_count: usize,
  452    },
  453    Update {
  454        position: DisplayPoint,
  455        goal_column: u32,
  456        scroll_delta: gpui::Point<f32>,
  457    },
  458    End,
  459}
  460
  461#[derive(Clone, Debug, PartialEq)]
  462pub enum ColumnarMode {
  463    FromMouse,
  464    FromSelection,
  465}
  466
  467#[derive(Clone, Debug)]
  468pub enum SelectMode {
  469    Character,
  470    Word(Range<Anchor>),
  471    Line(Range<Anchor>),
  472    All,
  473}
  474
  475#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  476pub enum SizingBehavior {
  477    /// The editor will layout itself using `size_full` and will include the vertical
  478    /// scroll margin as requested by user settings.
  479    #[default]
  480    Default,
  481    /// The editor will layout itself using `size_full`, but will not have any
  482    /// vertical overscroll.
  483    ExcludeOverscrollMargin,
  484    /// The editor will request a vertical size according to its content and will be
  485    /// layouted without a vertical scroll margin.
  486    SizeByContent,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// Determines the sizing behavior for this editor
  502        sizing_behavior: SizingBehavior,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sizing_behavior: SizingBehavior::Default,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, Arc<str>)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (
  742    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  743    Arc<[Range<Anchor>]>,
  744);
  745type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  746
  747#[derive(Default)]
  748struct ScrollbarMarkerState {
  749    scrollbar_size: Size<Pixels>,
  750    dirty: bool,
  751    markers: Arc<[PaintQuad]>,
  752    pending_refresh: Option<Task<Result<()>>>,
  753}
  754
  755impl ScrollbarMarkerState {
  756    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  757        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  758    }
  759}
  760
  761#[derive(Clone, Copy, PartialEq, Eq)]
  762pub enum MinimapVisibility {
  763    Disabled,
  764    Enabled {
  765        /// The configuration currently present in the users settings.
  766        setting_configuration: bool,
  767        /// Whether to override the currently set visibility from the users setting.
  768        toggle_override: bool,
  769    },
  770}
  771
  772impl MinimapVisibility {
  773    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  774        if mode.is_full() {
  775            Self::Enabled {
  776                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  777                toggle_override: false,
  778            }
  779        } else {
  780            Self::Disabled
  781        }
  782    }
  783
  784    fn hidden(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                setting_configuration,
  788                ..
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: setting_configuration,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796
  797    fn disabled(&self) -> bool {
  798        matches!(*self, Self::Disabled)
  799    }
  800
  801    fn settings_visibility(&self) -> bool {
  802        match *self {
  803            Self::Enabled {
  804                setting_configuration,
  805                ..
  806            } => setting_configuration,
  807            _ => false,
  808        }
  809    }
  810
  811    fn visible(&self) -> bool {
  812        match *self {
  813            Self::Enabled {
  814                setting_configuration,
  815                toggle_override,
  816            } => setting_configuration ^ toggle_override,
  817            _ => false,
  818        }
  819    }
  820
  821    fn toggle_visibility(&self) -> Self {
  822        match *self {
  823            Self::Enabled {
  824                toggle_override,
  825                setting_configuration,
  826            } => Self::Enabled {
  827                setting_configuration,
  828                toggle_override: !toggle_override,
  829            },
  830            Self::Disabled => Self::Disabled,
  831        }
  832    }
  833}
  834
  835#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  836pub enum BufferSerialization {
  837    All,
  838    NonDirtyBuffers,
  839}
  840
  841impl BufferSerialization {
  842    fn new(restore_unsaved_buffers: bool) -> Self {
  843        if restore_unsaved_buffers {
  844            Self::All
  845        } else {
  846            Self::NonDirtyBuffers
  847        }
  848    }
  849}
  850
  851#[derive(Clone, Debug)]
  852struct RunnableTasks {
  853    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  854    offset: multi_buffer::Anchor,
  855    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  856    column: u32,
  857    // Values of all named captures, including those starting with '_'
  858    extra_variables: HashMap<String, String>,
  859    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  860    context_range: Range<BufferOffset>,
  861}
  862
  863impl RunnableTasks {
  864    fn resolve<'a>(
  865        &'a self,
  866        cx: &'a task::TaskContext,
  867    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  868        self.templates.iter().filter_map(|(kind, template)| {
  869            template
  870                .resolve_task(&kind.to_id_base(), cx)
  871                .map(|task| (kind.clone(), task))
  872        })
  873    }
  874}
  875
  876#[derive(Clone)]
  877pub struct ResolvedTasks {
  878    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  879    position: Anchor,
  880}
  881
  882/// Addons allow storing per-editor state in other crates (e.g. Vim)
  883pub trait Addon: 'static {
  884    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  885
  886    fn render_buffer_header_controls(
  887        &self,
  888        _: &ExcerptInfo,
  889        _: &Window,
  890        _: &App,
  891    ) -> Option<AnyElement> {
  892        None
  893    }
  894
  895    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  896        None
  897    }
  898
  899    fn to_any(&self) -> &dyn std::any::Any;
  900
  901    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  902        None
  903    }
  904}
  905
  906struct ChangeLocation {
  907    current: Option<Vec<Anchor>>,
  908    original: Vec<Anchor>,
  909}
  910impl ChangeLocation {
  911    fn locations(&self) -> &[Anchor] {
  912        self.current.as_ref().unwrap_or(&self.original)
  913    }
  914}
  915
  916/// A set of caret positions, registered when the editor was edited.
  917pub struct ChangeList {
  918    changes: Vec<ChangeLocation>,
  919    /// Currently "selected" change.
  920    position: Option<usize>,
  921}
  922
  923impl ChangeList {
  924    pub fn new() -> Self {
  925        Self {
  926            changes: Vec::new(),
  927            position: None,
  928        }
  929    }
  930
  931    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  932    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  933    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  934        if self.changes.is_empty() {
  935            return None;
  936        }
  937
  938        let prev = self.position.unwrap_or(self.changes.len());
  939        let next = if direction == Direction::Prev {
  940            prev.saturating_sub(count)
  941        } else {
  942            (prev + count).min(self.changes.len() - 1)
  943        };
  944        self.position = Some(next);
  945        self.changes.get(next).map(|change| change.locations())
  946    }
  947
  948    /// Adds a new change to the list, resetting the change list position.
  949    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  950        self.position.take();
  951        if let Some(last) = self.changes.last_mut()
  952            && group
  953        {
  954            last.current = Some(new_positions)
  955        } else {
  956            self.changes.push(ChangeLocation {
  957                original: new_positions,
  958                current: None,
  959            });
  960        }
  961    }
  962
  963    pub fn last(&self) -> Option<&[Anchor]> {
  964        self.changes.last().map(|change| change.locations())
  965    }
  966
  967    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  968        self.changes.last().map(|change| change.original.as_slice())
  969    }
  970
  971    pub fn invert_last_group(&mut self) {
  972        if let Some(last) = self.changes.last_mut()
  973            && let Some(current) = last.current.as_mut()
  974        {
  975            mem::swap(&mut last.original, current);
  976        }
  977    }
  978}
  979
  980#[derive(Clone)]
  981struct InlineBlamePopoverState {
  982    scroll_handle: ScrollHandle,
  983    commit_message: Option<ParsedCommitMessage>,
  984    markdown: Entity<Markdown>,
  985}
  986
  987struct InlineBlamePopover {
  988    position: gpui::Point<Pixels>,
  989    hide_task: Option<Task<()>>,
  990    popover_bounds: Option<Bounds<Pixels>>,
  991    popover_state: InlineBlamePopoverState,
  992    keyboard_grace: bool,
  993}
  994
  995enum SelectionDragState {
  996    /// State when no drag related activity is detected.
  997    None,
  998    /// State when the mouse is down on a selection that is about to be dragged.
  999    ReadyToDrag {
 1000        selection: Selection<Anchor>,
 1001        click_position: gpui::Point<Pixels>,
 1002        mouse_down_time: Instant,
 1003    },
 1004    /// State when the mouse is dragging the selection in the editor.
 1005    Dragging {
 1006        selection: Selection<Anchor>,
 1007        drop_cursor: Selection<Anchor>,
 1008        hide_drop_cursor: bool,
 1009    },
 1010}
 1011
 1012enum ColumnarSelectionState {
 1013    FromMouse {
 1014        selection_tail: Anchor,
 1015        display_point: Option<DisplayPoint>,
 1016    },
 1017    FromSelection {
 1018        selection_tail: Anchor,
 1019    },
 1020}
 1021
 1022/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1023/// a breakpoint on them.
 1024#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1025struct PhantomBreakpointIndicator {
 1026    display_row: DisplayRow,
 1027    /// There's a small debounce between hovering over the line and showing the indicator.
 1028    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1029    is_active: bool,
 1030    collides_with_existing_breakpoint: bool,
 1031}
 1032
 1033/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1034/// in diff view mode.
 1035#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1036pub(crate) struct PhantomDiffReviewIndicator {
 1037    /// The starting anchor of the selection (or the only row if not dragging).
 1038    pub start: Anchor,
 1039    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1040    pub end: Anchor,
 1041    /// There's a small debounce between hovering over the line and showing the indicator.
 1042    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1043    pub is_active: bool,
 1044}
 1045
 1046#[derive(Clone, Debug)]
 1047pub(crate) struct DiffReviewDragState {
 1048    pub start_anchor: Anchor,
 1049    pub current_anchor: Anchor,
 1050}
 1051
 1052impl DiffReviewDragState {
 1053    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1054        let start = self.start_anchor.to_display_point(snapshot).row();
 1055        let current = self.current_anchor.to_display_point(snapshot).row();
 1056
 1057        (start..=current).sorted()
 1058    }
 1059}
 1060
 1061/// Identifies a specific hunk in the diff buffer.
 1062/// Used as a key to group comments by their location.
 1063#[derive(Clone, Debug)]
 1064pub struct DiffHunkKey {
 1065    /// The file path (relative to worktree) this hunk belongs to.
 1066    pub file_path: Arc<util::rel_path::RelPath>,
 1067    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1068    pub hunk_start_anchor: Anchor,
 1069}
 1070
 1071/// A review comment stored locally before being sent to the Agent panel.
 1072#[derive(Clone)]
 1073pub struct StoredReviewComment {
 1074    /// Unique identifier for this comment (for edit/delete operations).
 1075    pub id: usize,
 1076    /// The comment text entered by the user.
 1077    pub comment: String,
 1078    /// Anchors for the code range being reviewed.
 1079    pub range: Range<Anchor>,
 1080    /// Timestamp when the comment was created (for chronological ordering).
 1081    pub created_at: Instant,
 1082    /// Whether this comment is currently being edited inline.
 1083    pub is_editing: bool,
 1084}
 1085
 1086impl StoredReviewComment {
 1087    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1088        Self {
 1089            id,
 1090            comment,
 1091            range: anchor_range,
 1092            created_at: Instant::now(),
 1093            is_editing: false,
 1094        }
 1095    }
 1096}
 1097
 1098/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1099pub(crate) struct DiffReviewOverlay {
 1100    pub anchor_range: Range<Anchor>,
 1101    /// The block ID for the overlay.
 1102    pub block_id: CustomBlockId,
 1103    /// The editor entity for the review input.
 1104    pub prompt_editor: Entity<Editor>,
 1105    /// The hunk key this overlay belongs to.
 1106    pub hunk_key: DiffHunkKey,
 1107    /// Whether the comments section is expanded.
 1108    pub comments_expanded: bool,
 1109    /// Editors for comments currently being edited inline.
 1110    /// Key: comment ID, Value: Editor entity for inline editing.
 1111    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1112    /// Subscriptions for inline edit editors' action handlers.
 1113    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1114    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1115    /// The current user's avatar URI for display in comment rows.
 1116    pub user_avatar_uri: Option<SharedUri>,
 1117    /// Subscription to keep the action handler alive.
 1118    _subscription: Subscription,
 1119}
 1120
 1121/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1122///
 1123/// See the [module level documentation](self) for more information.
 1124pub struct Editor {
 1125    focus_handle: FocusHandle,
 1126    last_focused_descendant: Option<WeakFocusHandle>,
 1127    /// The text buffer being edited
 1128    buffer: Entity<MultiBuffer>,
 1129    /// Map of how text in the buffer should be displayed.
 1130    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1131    pub display_map: Entity<DisplayMap>,
 1132    placeholder_display_map: Option<Entity<DisplayMap>>,
 1133    pub selections: SelectionsCollection,
 1134    pub scroll_manager: ScrollManager,
 1135    /// When inline assist editors are linked, they all render cursors because
 1136    /// typing enters text into each of them, even the ones that aren't focused.
 1137    pub(crate) show_cursor_when_unfocused: bool,
 1138    columnar_selection_state: Option<ColumnarSelectionState>,
 1139    add_selections_state: Option<AddSelectionsState>,
 1140    select_next_state: Option<SelectNextState>,
 1141    select_prev_state: Option<SelectNextState>,
 1142    selection_history: SelectionHistory,
 1143    defer_selection_effects: bool,
 1144    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1145    autoclose_regions: Vec<AutocloseRegion>,
 1146    snippet_stack: InvalidationStack<SnippetState>,
 1147    select_syntax_node_history: SelectSyntaxNodeHistory,
 1148    ime_transaction: Option<TransactionId>,
 1149    pub diagnostics_max_severity: DiagnosticSeverity,
 1150    active_diagnostics: ActiveDiagnostic,
 1151    show_inline_diagnostics: bool,
 1152    inline_diagnostics_update: Task<()>,
 1153    inline_diagnostics_enabled: bool,
 1154    diagnostics_enabled: bool,
 1155    word_completions_enabled: bool,
 1156    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1157    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1158    hard_wrap: Option<usize>,
 1159    project: Option<Entity<Project>>,
 1160    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1161    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1162    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1163    blink_manager: Entity<BlinkManager>,
 1164    show_cursor_names: bool,
 1165    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1166    pub show_local_selections: bool,
 1167    mode: EditorMode,
 1168    show_breadcrumbs: bool,
 1169    show_gutter: bool,
 1170    show_scrollbars: ScrollbarAxes,
 1171    minimap_visibility: MinimapVisibility,
 1172    offset_content: bool,
 1173    disable_expand_excerpt_buttons: bool,
 1174    delegate_expand_excerpts: bool,
 1175    show_line_numbers: Option<bool>,
 1176    use_relative_line_numbers: Option<bool>,
 1177    show_git_diff_gutter: Option<bool>,
 1178    show_code_actions: Option<bool>,
 1179    show_runnables: Option<bool>,
 1180    show_breakpoints: Option<bool>,
 1181    show_diff_review_button: bool,
 1182    show_wrap_guides: Option<bool>,
 1183    show_indent_guides: Option<bool>,
 1184    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1185    highlight_order: usize,
 1186    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1187    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1188    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1189    scrollbar_marker_state: ScrollbarMarkerState,
 1190    active_indent_guides_state: ActiveIndentGuidesState,
 1191    nav_history: Option<ItemNavHistory>,
 1192    context_menu: RefCell<Option<CodeContextMenu>>,
 1193    context_menu_options: Option<ContextMenuOptions>,
 1194    mouse_context_menu: Option<MouseContextMenu>,
 1195    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1196    inline_blame_popover: Option<InlineBlamePopover>,
 1197    inline_blame_popover_show_task: Option<Task<()>>,
 1198    signature_help_state: SignatureHelpState,
 1199    auto_signature_help: Option<bool>,
 1200    find_all_references_task_sources: Vec<Anchor>,
 1201    next_completion_id: CompletionId,
 1202    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1203    code_actions_task: Option<Task<Result<()>>>,
 1204    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1205    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1206    debounced_selection_highlight_complete: bool,
 1207    document_highlights_task: Option<Task<()>>,
 1208    linked_editing_range_task: Option<Task<Option<()>>>,
 1209    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1210    pending_rename: Option<RenameState>,
 1211    searchable: bool,
 1212    cursor_shape: CursorShape,
 1213    /// Whether the cursor is offset one character to the left when something is
 1214    /// selected (needed for vim visual mode)
 1215    cursor_offset_on_selection: bool,
 1216    current_line_highlight: Option<CurrentLineHighlight>,
 1217    /// Whether to collapse search match ranges to just their start position.
 1218    /// When true, navigating to a match positions the cursor at the match
 1219    /// without selecting the matched text.
 1220    collapse_matches: bool,
 1221    autoindent_mode: Option<AutoindentMode>,
 1222    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1223    input_enabled: bool,
 1224    use_modal_editing: bool,
 1225    read_only: bool,
 1226    leader_id: Option<CollaboratorId>,
 1227    remote_id: Option<ViewId>,
 1228    pub hover_state: HoverState,
 1229    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1230    prev_pressure_stage: Option<PressureStage>,
 1231    gutter_hovered: bool,
 1232    hovered_link_state: Option<HoveredLinkState>,
 1233    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1234    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1235    active_edit_prediction: Option<EditPredictionState>,
 1236    /// Used to prevent flickering as the user types while the menu is open
 1237    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1238    edit_prediction_settings: EditPredictionSettings,
 1239    edit_predictions_hidden_for_vim_mode: bool,
 1240    show_edit_predictions_override: Option<bool>,
 1241    show_completions_on_input_override: Option<bool>,
 1242    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1243    edit_prediction_preview: EditPredictionPreview,
 1244    edit_prediction_indent_conflict: bool,
 1245    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1246    next_inlay_id: usize,
 1247    next_color_inlay_id: usize,
 1248    _subscriptions: Vec<Subscription>,
 1249    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1250    gutter_dimensions: GutterDimensions,
 1251    style: Option<EditorStyle>,
 1252    text_style_refinement: Option<TextStyleRefinement>,
 1253    next_editor_action_id: EditorActionId,
 1254    editor_actions: Rc<
 1255        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1256    >,
 1257    use_autoclose: bool,
 1258    use_auto_surround: bool,
 1259    auto_replace_emoji_shortcode: bool,
 1260    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1261    show_git_blame_gutter: bool,
 1262    show_git_blame_inline: bool,
 1263    show_git_blame_inline_delay_task: Option<Task<()>>,
 1264    git_blame_inline_enabled: bool,
 1265    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1266    buffer_serialization: Option<BufferSerialization>,
 1267    show_selection_menu: Option<bool>,
 1268    blame: Option<Entity<GitBlame>>,
 1269    blame_subscription: Option<Subscription>,
 1270    custom_context_menu: Option<
 1271        Box<
 1272            dyn 'static
 1273                + Fn(
 1274                    &mut Self,
 1275                    DisplayPoint,
 1276                    &mut Window,
 1277                    &mut Context<Self>,
 1278                ) -> Option<Entity<ui::ContextMenu>>,
 1279        >,
 1280    >,
 1281    last_bounds: Option<Bounds<Pixels>>,
 1282    last_position_map: Option<Rc<PositionMap>>,
 1283    expect_bounds_change: Option<Bounds<Pixels>>,
 1284    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1285    tasks_update_task: Option<Task<()>>,
 1286    breakpoint_store: Option<Entity<BreakpointStore>>,
 1287    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1288    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1289    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1290    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1291    /// when hunks have comments stored.
 1292    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1293    /// Stored review comments grouped by hunk.
 1294    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1295    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1296    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1297    /// Counter for generating unique comment IDs.
 1298    next_review_comment_id: usize,
 1299    hovered_diff_hunk_row: Option<DisplayRow>,
 1300    pull_diagnostics_task: Task<()>,
 1301    in_project_search: bool,
 1302    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1303    breadcrumb_header: Option<String>,
 1304    focused_block: Option<FocusedBlock>,
 1305    next_scroll_position: NextScrollCursorCenterTopBottom,
 1306    addons: HashMap<TypeId, Box<dyn Addon>>,
 1307    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1308    load_diff_task: Option<Shared<Task<()>>>,
 1309    /// Whether we are temporarily displaying a diff other than git's
 1310    temporary_diff_override: bool,
 1311    selection_mark_mode: bool,
 1312    toggle_fold_multiple_buffers: Task<()>,
 1313    _scroll_cursor_center_top_bottom_task: Task<()>,
 1314    serialize_selections: Task<()>,
 1315    serialize_folds: Task<()>,
 1316    mouse_cursor_hidden: bool,
 1317    minimap: Option<Entity<Self>>,
 1318    hide_mouse_mode: HideMouseMode,
 1319    pub change_list: ChangeList,
 1320    inline_value_cache: InlineValueCache,
 1321    number_deleted_lines: bool,
 1322
 1323    selection_drag_state: SelectionDragState,
 1324    colors: Option<LspColorData>,
 1325    post_scroll_update: Task<()>,
 1326    refresh_colors_task: Task<()>,
 1327    inlay_hints: Option<LspInlayHintData>,
 1328    folding_newlines: Task<()>,
 1329    select_next_is_case_sensitive: Option<bool>,
 1330    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1331    scroll_companion: Option<WeakEntity<Editor>>,
 1332    on_local_selections_changed:
 1333        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1334    suppress_selection_callback: bool,
 1335    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1336    accent_data: Option<AccentData>,
 1337    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1338}
 1339
 1340#[derive(Debug, PartialEq)]
 1341struct AccentData {
 1342    colors: AccentColors,
 1343    overrides: Vec<SharedString>,
 1344}
 1345
 1346fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1347    if debounce_ms > 0 {
 1348        Some(Duration::from_millis(debounce_ms))
 1349    } else {
 1350        None
 1351    }
 1352}
 1353
 1354#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1355enum NextScrollCursorCenterTopBottom {
 1356    #[default]
 1357    Center,
 1358    Top,
 1359    Bottom,
 1360}
 1361
 1362impl NextScrollCursorCenterTopBottom {
 1363    fn next(&self) -> Self {
 1364        match self {
 1365            Self::Center => Self::Top,
 1366            Self::Top => Self::Bottom,
 1367            Self::Bottom => Self::Center,
 1368        }
 1369    }
 1370}
 1371
 1372#[derive(Clone)]
 1373pub struct EditorSnapshot {
 1374    pub mode: EditorMode,
 1375    show_gutter: bool,
 1376    offset_content: bool,
 1377    show_line_numbers: Option<bool>,
 1378    number_deleted_lines: bool,
 1379    show_git_diff_gutter: Option<bool>,
 1380    show_code_actions: Option<bool>,
 1381    show_runnables: Option<bool>,
 1382    show_breakpoints: Option<bool>,
 1383    git_blame_gutter_max_author_length: Option<usize>,
 1384    pub display_snapshot: DisplaySnapshot,
 1385    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1386    is_focused: bool,
 1387    scroll_anchor: ScrollAnchor,
 1388    ongoing_scroll: OngoingScroll,
 1389    current_line_highlight: CurrentLineHighlight,
 1390    gutter_hovered: bool,
 1391}
 1392
 1393#[derive(Default, Debug, Clone, Copy)]
 1394pub struct GutterDimensions {
 1395    pub left_padding: Pixels,
 1396    pub right_padding: Pixels,
 1397    pub width: Pixels,
 1398    pub margin: Pixels,
 1399    pub git_blame_entries_width: Option<Pixels>,
 1400}
 1401
 1402impl GutterDimensions {
 1403    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1404        Self {
 1405            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1406            ..Default::default()
 1407        }
 1408    }
 1409
 1410    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1411        -cx.text_system().descent(font_id, font_size)
 1412    }
 1413    /// The full width of the space taken up by the gutter.
 1414    pub fn full_width(&self) -> Pixels {
 1415        self.margin + self.width
 1416    }
 1417
 1418    /// The width of the space reserved for the fold indicators,
 1419    /// use alongside 'justify_end' and `gutter_width` to
 1420    /// right align content with the line numbers
 1421    pub fn fold_area_width(&self) -> Pixels {
 1422        self.margin + self.right_padding
 1423    }
 1424}
 1425
 1426struct CharacterDimensions {
 1427    em_width: Pixels,
 1428    em_advance: Pixels,
 1429    line_height: Pixels,
 1430}
 1431
 1432#[derive(Debug)]
 1433pub struct RemoteSelection {
 1434    pub replica_id: ReplicaId,
 1435    pub selection: Selection<Anchor>,
 1436    pub cursor_shape: CursorShape,
 1437    pub collaborator_id: CollaboratorId,
 1438    pub line_mode: bool,
 1439    pub user_name: Option<SharedString>,
 1440    pub color: PlayerColor,
 1441}
 1442
 1443#[derive(Clone, Debug)]
 1444struct SelectionHistoryEntry {
 1445    selections: Arc<[Selection<Anchor>]>,
 1446    select_next_state: Option<SelectNextState>,
 1447    select_prev_state: Option<SelectNextState>,
 1448    add_selections_state: Option<AddSelectionsState>,
 1449}
 1450
 1451#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1452enum SelectionHistoryMode {
 1453    #[default]
 1454    Normal,
 1455    Undoing,
 1456    Redoing,
 1457    Skipping,
 1458}
 1459
 1460#[derive(Clone, PartialEq, Eq, Hash)]
 1461struct HoveredCursor {
 1462    replica_id: ReplicaId,
 1463    selection_id: usize,
 1464}
 1465
 1466#[derive(Debug)]
 1467/// SelectionEffects controls the side-effects of updating the selection.
 1468///
 1469/// The default behaviour does "what you mostly want":
 1470/// - it pushes to the nav history if the cursor moved by >10 lines
 1471/// - it re-triggers completion requests
 1472/// - it scrolls to fit
 1473///
 1474/// You might want to modify these behaviours. For example when doing a "jump"
 1475/// like go to definition, we always want to add to nav history; but when scrolling
 1476/// in vim mode we never do.
 1477///
 1478/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1479/// move.
 1480#[derive(Clone)]
 1481pub struct SelectionEffects {
 1482    nav_history: Option<bool>,
 1483    completions: bool,
 1484    scroll: Option<Autoscroll>,
 1485}
 1486
 1487impl Default for SelectionEffects {
 1488    fn default() -> Self {
 1489        Self {
 1490            nav_history: None,
 1491            completions: true,
 1492            scroll: Some(Autoscroll::fit()),
 1493        }
 1494    }
 1495}
 1496impl SelectionEffects {
 1497    pub fn scroll(scroll: Autoscroll) -> Self {
 1498        Self {
 1499            scroll: Some(scroll),
 1500            ..Default::default()
 1501        }
 1502    }
 1503
 1504    pub fn no_scroll() -> Self {
 1505        Self {
 1506            scroll: None,
 1507            ..Default::default()
 1508        }
 1509    }
 1510
 1511    pub fn completions(self, completions: bool) -> Self {
 1512        Self {
 1513            completions,
 1514            ..self
 1515        }
 1516    }
 1517
 1518    pub fn nav_history(self, nav_history: bool) -> Self {
 1519        Self {
 1520            nav_history: Some(nav_history),
 1521            ..self
 1522        }
 1523    }
 1524}
 1525
 1526struct DeferredSelectionEffectsState {
 1527    changed: bool,
 1528    effects: SelectionEffects,
 1529    old_cursor_position: Anchor,
 1530    history_entry: SelectionHistoryEntry,
 1531}
 1532
 1533#[derive(Default)]
 1534struct SelectionHistory {
 1535    #[allow(clippy::type_complexity)]
 1536    selections_by_transaction:
 1537        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1538    mode: SelectionHistoryMode,
 1539    undo_stack: VecDeque<SelectionHistoryEntry>,
 1540    redo_stack: VecDeque<SelectionHistoryEntry>,
 1541}
 1542
 1543impl SelectionHistory {
 1544    #[track_caller]
 1545    fn insert_transaction(
 1546        &mut self,
 1547        transaction_id: TransactionId,
 1548        selections: Arc<[Selection<Anchor>]>,
 1549    ) {
 1550        if selections.is_empty() {
 1551            log::error!(
 1552                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1553                std::panic::Location::caller()
 1554            );
 1555            return;
 1556        }
 1557        self.selections_by_transaction
 1558            .insert(transaction_id, (selections, None));
 1559    }
 1560
 1561    #[allow(clippy::type_complexity)]
 1562    fn transaction(
 1563        &self,
 1564        transaction_id: TransactionId,
 1565    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1566        self.selections_by_transaction.get(&transaction_id)
 1567    }
 1568
 1569    #[allow(clippy::type_complexity)]
 1570    fn transaction_mut(
 1571        &mut self,
 1572        transaction_id: TransactionId,
 1573    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1574        self.selections_by_transaction.get_mut(&transaction_id)
 1575    }
 1576
 1577    fn push(&mut self, entry: SelectionHistoryEntry) {
 1578        if !entry.selections.is_empty() {
 1579            match self.mode {
 1580                SelectionHistoryMode::Normal => {
 1581                    self.push_undo(entry);
 1582                    self.redo_stack.clear();
 1583                }
 1584                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1585                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1586                SelectionHistoryMode::Skipping => {}
 1587            }
 1588        }
 1589    }
 1590
 1591    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1592        if self
 1593            .undo_stack
 1594            .back()
 1595            .is_none_or(|e| e.selections != entry.selections)
 1596        {
 1597            self.undo_stack.push_back(entry);
 1598            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1599                self.undo_stack.pop_front();
 1600            }
 1601        }
 1602    }
 1603
 1604    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1605        if self
 1606            .redo_stack
 1607            .back()
 1608            .is_none_or(|e| e.selections != entry.selections)
 1609        {
 1610            self.redo_stack.push_back(entry);
 1611            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1612                self.redo_stack.pop_front();
 1613            }
 1614        }
 1615    }
 1616}
 1617
 1618#[derive(Clone, Copy)]
 1619pub struct RowHighlightOptions {
 1620    pub autoscroll: bool,
 1621    pub include_gutter: bool,
 1622}
 1623
 1624impl Default for RowHighlightOptions {
 1625    fn default() -> Self {
 1626        Self {
 1627            autoscroll: Default::default(),
 1628            include_gutter: true,
 1629        }
 1630    }
 1631}
 1632
 1633struct RowHighlight {
 1634    index: usize,
 1635    range: Range<Anchor>,
 1636    color: Hsla,
 1637    options: RowHighlightOptions,
 1638    type_id: TypeId,
 1639}
 1640
 1641#[derive(Clone, Debug)]
 1642struct AddSelectionsState {
 1643    groups: Vec<AddSelectionsGroup>,
 1644}
 1645
 1646#[derive(Clone, Debug)]
 1647struct AddSelectionsGroup {
 1648    above: bool,
 1649    stack: Vec<usize>,
 1650}
 1651
 1652#[derive(Clone)]
 1653struct SelectNextState {
 1654    query: AhoCorasick,
 1655    wordwise: bool,
 1656    done: bool,
 1657}
 1658
 1659impl std::fmt::Debug for SelectNextState {
 1660    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1661        f.debug_struct(std::any::type_name::<Self>())
 1662            .field("wordwise", &self.wordwise)
 1663            .field("done", &self.done)
 1664            .finish()
 1665    }
 1666}
 1667
 1668#[derive(Debug)]
 1669struct AutocloseRegion {
 1670    selection_id: usize,
 1671    range: Range<Anchor>,
 1672    pair: BracketPair,
 1673}
 1674
 1675#[derive(Debug)]
 1676struct SnippetState {
 1677    ranges: Vec<Vec<Range<Anchor>>>,
 1678    active_index: usize,
 1679    choices: Vec<Option<Vec<String>>>,
 1680}
 1681
 1682#[doc(hidden)]
 1683pub struct RenameState {
 1684    pub range: Range<Anchor>,
 1685    pub old_name: Arc<str>,
 1686    pub editor: Entity<Editor>,
 1687    block_id: CustomBlockId,
 1688}
 1689
 1690struct InvalidationStack<T>(Vec<T>);
 1691
 1692struct RegisteredEditPredictionDelegate {
 1693    provider: Arc<dyn EditPredictionDelegateHandle>,
 1694    _subscription: Subscription,
 1695}
 1696
 1697#[derive(Debug, PartialEq, Eq)]
 1698pub struct ActiveDiagnosticGroup {
 1699    pub active_range: Range<Anchor>,
 1700    pub active_message: String,
 1701    pub group_id: usize,
 1702    pub blocks: HashSet<CustomBlockId>,
 1703}
 1704
 1705#[derive(Debug, PartialEq, Eq)]
 1706
 1707pub(crate) enum ActiveDiagnostic {
 1708    None,
 1709    All,
 1710    Group(ActiveDiagnosticGroup),
 1711}
 1712
 1713#[derive(Serialize, Deserialize, Clone, Debug)]
 1714pub struct ClipboardSelection {
 1715    /// The number of bytes in this selection.
 1716    pub len: usize,
 1717    /// Whether this was a full-line selection.
 1718    pub is_entire_line: bool,
 1719    /// The indentation of the first line when this content was originally copied.
 1720    pub first_line_indent: u32,
 1721    #[serde(default)]
 1722    pub file_path: Option<PathBuf>,
 1723    #[serde(default)]
 1724    pub line_range: Option<RangeInclusive<u32>>,
 1725}
 1726
 1727impl ClipboardSelection {
 1728    pub fn for_buffer(
 1729        len: usize,
 1730        is_entire_line: bool,
 1731        range: Range<Point>,
 1732        buffer: &MultiBufferSnapshot,
 1733        project: Option<&Entity<Project>>,
 1734        cx: &App,
 1735    ) -> Self {
 1736        let first_line_indent = buffer
 1737            .indent_size_for_line(MultiBufferRow(range.start.row))
 1738            .len;
 1739
 1740        let file_path = util::maybe!({
 1741            let project = project?.read(cx);
 1742            let file = buffer.file_at(range.start)?;
 1743            let project_path = ProjectPath {
 1744                worktree_id: file.worktree_id(cx),
 1745                path: file.path().clone(),
 1746            };
 1747            project.absolute_path(&project_path, cx)
 1748        });
 1749
 1750        let line_range = file_path.as_ref().and_then(|_| {
 1751            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1752            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1753            if start_excerpt_id == end_excerpt_id {
 1754                Some(start_point.row..=end_point.row)
 1755            } else {
 1756                None
 1757            }
 1758        });
 1759
 1760        Self {
 1761            len,
 1762            is_entire_line,
 1763            first_line_indent,
 1764            file_path,
 1765            line_range,
 1766        }
 1767    }
 1768}
 1769
 1770// selections, scroll behavior, was newest selection reversed
 1771type SelectSyntaxNodeHistoryState = (
 1772    Box<[Selection<MultiBufferOffset>]>,
 1773    SelectSyntaxNodeScrollBehavior,
 1774    bool,
 1775);
 1776
 1777#[derive(Default)]
 1778struct SelectSyntaxNodeHistory {
 1779    stack: Vec<SelectSyntaxNodeHistoryState>,
 1780    // disable temporarily to allow changing selections without losing the stack
 1781    pub disable_clearing: bool,
 1782}
 1783
 1784impl SelectSyntaxNodeHistory {
 1785    pub fn try_clear(&mut self) {
 1786        if !self.disable_clearing {
 1787            self.stack.clear();
 1788        }
 1789    }
 1790
 1791    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1792        self.stack.push(selection);
 1793    }
 1794
 1795    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1796        self.stack.pop()
 1797    }
 1798}
 1799
 1800enum SelectSyntaxNodeScrollBehavior {
 1801    CursorTop,
 1802    FitSelection,
 1803    CursorBottom,
 1804}
 1805
 1806#[derive(Debug, Clone, Copy)]
 1807pub(crate) struct NavigationData {
 1808    cursor_anchor: Anchor,
 1809    cursor_position: Point,
 1810    scroll_anchor: ScrollAnchor,
 1811    scroll_top_row: u32,
 1812}
 1813
 1814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1815pub enum GotoDefinitionKind {
 1816    Symbol,
 1817    Declaration,
 1818    Type,
 1819    Implementation,
 1820}
 1821
 1822pub enum FormatTarget {
 1823    Buffers(HashSet<Entity<Buffer>>),
 1824    Ranges(Vec<Range<MultiBufferPoint>>),
 1825}
 1826
 1827pub(crate) struct FocusedBlock {
 1828    id: BlockId,
 1829    focus_handle: WeakFocusHandle,
 1830}
 1831
 1832#[derive(Clone, Debug)]
 1833pub enum JumpData {
 1834    MultiBufferRow {
 1835        row: MultiBufferRow,
 1836        line_offset_from_top: u32,
 1837    },
 1838    MultiBufferPoint {
 1839        excerpt_id: ExcerptId,
 1840        position: Point,
 1841        anchor: text::Anchor,
 1842        line_offset_from_top: u32,
 1843    },
 1844}
 1845
 1846pub enum MultibufferSelectionMode {
 1847    First,
 1848    All,
 1849}
 1850
 1851#[derive(Clone, Copy, Debug, Default)]
 1852pub struct RewrapOptions {
 1853    pub override_language_settings: bool,
 1854    pub preserve_existing_whitespace: bool,
 1855}
 1856
 1857impl Editor {
 1858    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1859        let buffer = cx.new(|cx| Buffer::local("", cx));
 1860        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1861        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1862    }
 1863
 1864    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1865        let buffer = cx.new(|cx| Buffer::local("", cx));
 1866        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1867        Self::new(EditorMode::full(), buffer, None, window, cx)
 1868    }
 1869
 1870    pub fn auto_height(
 1871        min_lines: usize,
 1872        max_lines: usize,
 1873        window: &mut Window,
 1874        cx: &mut Context<Self>,
 1875    ) -> Self {
 1876        let buffer = cx.new(|cx| Buffer::local("", cx));
 1877        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1878        Self::new(
 1879            EditorMode::AutoHeight {
 1880                min_lines,
 1881                max_lines: Some(max_lines),
 1882            },
 1883            buffer,
 1884            None,
 1885            window,
 1886            cx,
 1887        )
 1888    }
 1889
 1890    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1891    /// The editor grows as tall as needed to fit its content.
 1892    pub fn auto_height_unbounded(
 1893        min_lines: usize,
 1894        window: &mut Window,
 1895        cx: &mut Context<Self>,
 1896    ) -> Self {
 1897        let buffer = cx.new(|cx| Buffer::local("", cx));
 1898        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1899        Self::new(
 1900            EditorMode::AutoHeight {
 1901                min_lines,
 1902                max_lines: None,
 1903            },
 1904            buffer,
 1905            None,
 1906            window,
 1907            cx,
 1908        )
 1909    }
 1910
 1911    pub fn for_buffer(
 1912        buffer: Entity<Buffer>,
 1913        project: Option<Entity<Project>>,
 1914        window: &mut Window,
 1915        cx: &mut Context<Self>,
 1916    ) -> Self {
 1917        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1918        Self::new(EditorMode::full(), buffer, project, window, cx)
 1919    }
 1920
 1921    pub fn for_multibuffer(
 1922        buffer: Entity<MultiBuffer>,
 1923        project: Option<Entity<Project>>,
 1924        window: &mut Window,
 1925        cx: &mut Context<Self>,
 1926    ) -> Self {
 1927        Self::new(EditorMode::full(), buffer, project, window, cx)
 1928    }
 1929
 1930    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1931        let mut clone = Self::new(
 1932            self.mode.clone(),
 1933            self.buffer.clone(),
 1934            self.project.clone(),
 1935            window,
 1936            cx,
 1937        );
 1938        self.display_map.update(cx, |display_map, cx| {
 1939            let snapshot = display_map.snapshot(cx);
 1940            clone.display_map.update(cx, |display_map, cx| {
 1941                display_map.set_state(&snapshot, cx);
 1942            });
 1943        });
 1944        clone.folds_did_change(cx);
 1945        clone.selections.clone_state(&self.selections);
 1946        clone.scroll_manager.clone_state(&self.scroll_manager);
 1947        clone.searchable = self.searchable;
 1948        clone.read_only = self.read_only;
 1949        clone
 1950    }
 1951
 1952    pub fn new(
 1953        mode: EditorMode,
 1954        buffer: Entity<MultiBuffer>,
 1955        project: Option<Entity<Project>>,
 1956        window: &mut Window,
 1957        cx: &mut Context<Self>,
 1958    ) -> Self {
 1959        Editor::new_internal(mode, buffer, project, None, window, cx)
 1960    }
 1961
 1962    pub fn sticky_headers(
 1963        &self,
 1964        style: &EditorStyle,
 1965        cx: &App,
 1966    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1967        let multi_buffer = self.buffer().read(cx);
 1968        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1969        let multi_buffer_visible_start = self
 1970            .scroll_manager
 1971            .anchor()
 1972            .anchor
 1973            .to_point(&multi_buffer_snapshot);
 1974        let max_row = multi_buffer_snapshot.max_point().row;
 1975
 1976        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1977        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1978
 1979        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1980            let outline_items = buffer
 1981                .outline_items_containing(
 1982                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1983                    true,
 1984                    Some(style.syntax.as_ref()),
 1985                )
 1986                .into_iter()
 1987                .map(|outline_item| OutlineItem {
 1988                    depth: outline_item.depth,
 1989                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1990                    source_range_for_text: Anchor::range_in_buffer(
 1991                        *excerpt_id,
 1992                        outline_item.source_range_for_text,
 1993                    ),
 1994                    text: outline_item.text,
 1995                    highlight_ranges: outline_item.highlight_ranges,
 1996                    name_ranges: outline_item.name_ranges,
 1997                    body_range: outline_item
 1998                        .body_range
 1999                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 2000                    annotation_range: outline_item
 2001                        .annotation_range
 2002                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 2003                });
 2004            return Some(outline_items.collect());
 2005        }
 2006
 2007        None
 2008    }
 2009
 2010    fn new_internal(
 2011        mode: EditorMode,
 2012        multi_buffer: Entity<MultiBuffer>,
 2013        project: Option<Entity<Project>>,
 2014        display_map: Option<Entity<DisplayMap>>,
 2015        window: &mut Window,
 2016        cx: &mut Context<Self>,
 2017    ) -> Self {
 2018        debug_assert!(
 2019            display_map.is_none() || mode.is_minimap(),
 2020            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2021        );
 2022
 2023        let full_mode = mode.is_full();
 2024        let is_minimap = mode.is_minimap();
 2025        let diagnostics_max_severity = if full_mode {
 2026            EditorSettings::get_global(cx)
 2027                .diagnostics_max_severity
 2028                .unwrap_or(DiagnosticSeverity::Hint)
 2029        } else {
 2030            DiagnosticSeverity::Off
 2031        };
 2032        let style = window.text_style();
 2033        let font_size = style.font_size.to_pixels(window.rem_size());
 2034        let editor = cx.entity().downgrade();
 2035        let fold_placeholder = FoldPlaceholder {
 2036            constrain_width: false,
 2037            render: Arc::new(move |fold_id, fold_range, cx| {
 2038                let editor = editor.clone();
 2039                div()
 2040                    .id(fold_id)
 2041                    .bg(cx.theme().colors().ghost_element_background)
 2042                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 2043                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 2044                    .rounded_xs()
 2045                    .size_full()
 2046                    .cursor_pointer()
 2047                    .child("")
 2048                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2049                    .on_click(move |_, _window, cx| {
 2050                        editor
 2051                            .update(cx, |editor, cx| {
 2052                                editor.unfold_ranges(
 2053                                    &[fold_range.start..fold_range.end],
 2054                                    true,
 2055                                    false,
 2056                                    cx,
 2057                                );
 2058                                cx.stop_propagation();
 2059                            })
 2060                            .ok();
 2061                    })
 2062                    .into_any()
 2063            }),
 2064            merge_adjacent: true,
 2065            ..FoldPlaceholder::default()
 2066        };
 2067        let display_map = display_map.unwrap_or_else(|| {
 2068            cx.new(|cx| {
 2069                DisplayMap::new(
 2070                    multi_buffer.clone(),
 2071                    style.font(),
 2072                    font_size,
 2073                    None,
 2074                    FILE_HEADER_HEIGHT,
 2075                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2076                    fold_placeholder,
 2077                    diagnostics_max_severity,
 2078                    cx,
 2079                )
 2080            })
 2081        });
 2082
 2083        let selections = SelectionsCollection::new();
 2084
 2085        let blink_manager = cx.new(|cx| {
 2086            let mut blink_manager = BlinkManager::new(
 2087                CURSOR_BLINK_INTERVAL,
 2088                |cx| EditorSettings::get_global(cx).cursor_blink,
 2089                cx,
 2090            );
 2091            if is_minimap {
 2092                blink_manager.disable(cx);
 2093            }
 2094            blink_manager
 2095        });
 2096
 2097        let soft_wrap_mode_override =
 2098            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2099
 2100        let mut project_subscriptions = Vec::new();
 2101        if full_mode && let Some(project) = project.as_ref() {
 2102            project_subscriptions.push(cx.subscribe_in(
 2103                project,
 2104                window,
 2105                |editor, _, event, window, cx| match event {
 2106                    project::Event::RefreshCodeLens => {
 2107                        // we always query lens with actions, without storing them, always refreshing them
 2108                    }
 2109                    project::Event::RefreshInlayHints {
 2110                        server_id,
 2111                        request_id,
 2112                    } => {
 2113                        editor.refresh_inlay_hints(
 2114                            InlayHintRefreshReason::RefreshRequested {
 2115                                server_id: *server_id,
 2116                                request_id: *request_id,
 2117                            },
 2118                            cx,
 2119                        );
 2120                    }
 2121                    project::Event::LanguageServerRemoved(..) => {
 2122                        if editor.tasks_update_task.is_none() {
 2123                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2124                        }
 2125                        editor.registered_buffers.clear();
 2126                        editor.register_visible_buffers(cx);
 2127                    }
 2128                    project::Event::LanguageServerAdded(..) => {
 2129                        if editor.tasks_update_task.is_none() {
 2130                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2131                        }
 2132                    }
 2133                    project::Event::SnippetEdit(id, snippet_edits) => {
 2134                        // todo(lw): Non singletons
 2135                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2136                            let snapshot = buffer.read(cx).snapshot();
 2137                            let focus_handle = editor.focus_handle(cx);
 2138                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2139                                for (range, snippet) in snippet_edits {
 2140                                    let buffer_range =
 2141                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2142                                    editor
 2143                                        .insert_snippet(
 2144                                            &[MultiBufferOffset(buffer_range.start)
 2145                                                ..MultiBufferOffset(buffer_range.end)],
 2146                                            snippet.clone(),
 2147                                            window,
 2148                                            cx,
 2149                                        )
 2150                                        .ok();
 2151                                }
 2152                            }
 2153                        }
 2154                    }
 2155                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2156                        let buffer_id = *buffer_id;
 2157                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2158                            editor.register_buffer(buffer_id, cx);
 2159                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2160                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2161                            refresh_linked_ranges(editor, window, cx);
 2162                            editor.refresh_code_actions(window, cx);
 2163                            editor.refresh_document_highlights(cx);
 2164                        }
 2165                    }
 2166
 2167                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2168                        let Some(workspace) = editor.workspace() else {
 2169                            return;
 2170                        };
 2171                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2172                        else {
 2173                            return;
 2174                        };
 2175
 2176                        if active_editor.entity_id() == cx.entity_id() {
 2177                            let entity_id = cx.entity_id();
 2178                            workspace.update(cx, |this, cx| {
 2179                                this.panes_mut()
 2180                                    .iter_mut()
 2181                                    .filter(|pane| pane.entity_id() != entity_id)
 2182                                    .for_each(|p| {
 2183                                        p.update(cx, |pane, _| {
 2184                                            pane.nav_history_mut().rename_item(
 2185                                                entity_id,
 2186                                                project_path.clone(),
 2187                                                abs_path.clone().into(),
 2188                                            );
 2189                                        })
 2190                                    });
 2191                            });
 2192
 2193                            Self::open_transaction_for_hidden_buffers(
 2194                                workspace,
 2195                                transaction.clone(),
 2196                                "Rename".to_string(),
 2197                                window,
 2198                                cx,
 2199                            );
 2200                        }
 2201                    }
 2202
 2203                    project::Event::WorkspaceEditApplied(transaction) => {
 2204                        let Some(workspace) = editor.workspace() else {
 2205                            return;
 2206                        };
 2207                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2208                        else {
 2209                            return;
 2210                        };
 2211
 2212                        if active_editor.entity_id() == cx.entity_id() {
 2213                            Self::open_transaction_for_hidden_buffers(
 2214                                workspace,
 2215                                transaction.clone(),
 2216                                "LSP Edit".to_string(),
 2217                                window,
 2218                                cx,
 2219                            );
 2220                        }
 2221                    }
 2222
 2223                    _ => {}
 2224                },
 2225            ));
 2226            if let Some(task_inventory) = project
 2227                .read(cx)
 2228                .task_store()
 2229                .read(cx)
 2230                .task_inventory()
 2231                .cloned()
 2232            {
 2233                project_subscriptions.push(cx.observe_in(
 2234                    &task_inventory,
 2235                    window,
 2236                    |editor, _, window, cx| {
 2237                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2238                    },
 2239                ));
 2240            };
 2241
 2242            project_subscriptions.push(cx.subscribe_in(
 2243                &project.read(cx).breakpoint_store(),
 2244                window,
 2245                |editor, _, event, window, cx| match event {
 2246                    BreakpointStoreEvent::ClearDebugLines => {
 2247                        editor.clear_row_highlights::<ActiveDebugLine>();
 2248                        editor.refresh_inline_values(cx);
 2249                    }
 2250                    BreakpointStoreEvent::SetDebugLine => {
 2251                        if editor.go_to_active_debug_line(window, cx) {
 2252                            cx.stop_propagation();
 2253                        }
 2254
 2255                        editor.refresh_inline_values(cx);
 2256                    }
 2257                    _ => {}
 2258                },
 2259            ));
 2260            let git_store = project.read(cx).git_store().clone();
 2261            let project = project.clone();
 2262            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2263                if let GitStoreEvent::RepositoryAdded = event {
 2264                    this.load_diff_task = Some(
 2265                        update_uncommitted_diff_for_buffer(
 2266                            cx.entity(),
 2267                            &project,
 2268                            this.buffer.read(cx).all_buffers(),
 2269                            this.buffer.clone(),
 2270                            cx,
 2271                        )
 2272                        .shared(),
 2273                    );
 2274                }
 2275            }));
 2276        }
 2277
 2278        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2279
 2280        let inlay_hint_settings =
 2281            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2282        let focus_handle = cx.focus_handle();
 2283        if !is_minimap {
 2284            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2285                .detach();
 2286            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2287                .detach();
 2288            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2289                .detach();
 2290            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2291                .detach();
 2292            cx.observe_pending_input(window, Self::observe_pending_input)
 2293                .detach();
 2294        }
 2295
 2296        let show_indent_guides =
 2297            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2298                Some(false)
 2299            } else {
 2300                None
 2301            };
 2302
 2303        let breakpoint_store = match (&mode, project.as_ref()) {
 2304            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2305            _ => None,
 2306        };
 2307
 2308        let mut code_action_providers = Vec::new();
 2309        let mut load_uncommitted_diff = None;
 2310        if let Some(project) = project.clone() {
 2311            load_uncommitted_diff = Some(
 2312                update_uncommitted_diff_for_buffer(
 2313                    cx.entity(),
 2314                    &project,
 2315                    multi_buffer.read(cx).all_buffers(),
 2316                    multi_buffer.clone(),
 2317                    cx,
 2318                )
 2319                .shared(),
 2320            );
 2321            code_action_providers.push(Rc::new(project) as Rc<_>);
 2322        }
 2323
 2324        let mut editor = Self {
 2325            focus_handle,
 2326            show_cursor_when_unfocused: false,
 2327            last_focused_descendant: None,
 2328            buffer: multi_buffer.clone(),
 2329            display_map: display_map.clone(),
 2330            placeholder_display_map: None,
 2331            selections,
 2332            scroll_manager: ScrollManager::new(cx),
 2333            columnar_selection_state: None,
 2334            add_selections_state: None,
 2335            select_next_state: None,
 2336            select_prev_state: None,
 2337            selection_history: SelectionHistory::default(),
 2338            defer_selection_effects: false,
 2339            deferred_selection_effects_state: None,
 2340            autoclose_regions: Vec::new(),
 2341            snippet_stack: InvalidationStack::default(),
 2342            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2343            ime_transaction: None,
 2344            active_diagnostics: ActiveDiagnostic::None,
 2345            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2346            inline_diagnostics_update: Task::ready(()),
 2347            inline_diagnostics: Vec::new(),
 2348            soft_wrap_mode_override,
 2349            diagnostics_max_severity,
 2350            hard_wrap: None,
 2351            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2352            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2353            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2354            project,
 2355            blink_manager: blink_manager.clone(),
 2356            show_local_selections: true,
 2357            show_scrollbars: ScrollbarAxes {
 2358                horizontal: full_mode,
 2359                vertical: full_mode,
 2360            },
 2361            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2362            offset_content: !matches!(mode, EditorMode::SingleLine),
 2363            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2364            show_gutter: full_mode,
 2365            show_line_numbers: (!full_mode).then_some(false),
 2366            use_relative_line_numbers: None,
 2367            disable_expand_excerpt_buttons: !full_mode,
 2368            delegate_expand_excerpts: false,
 2369            show_git_diff_gutter: None,
 2370            show_code_actions: None,
 2371            show_runnables: None,
 2372            show_breakpoints: None,
 2373            show_diff_review_button: false,
 2374            show_wrap_guides: None,
 2375            show_indent_guides,
 2376            buffers_with_disabled_indent_guides: HashSet::default(),
 2377            highlight_order: 0,
 2378            highlighted_rows: HashMap::default(),
 2379            background_highlights: HashMap::default(),
 2380            gutter_highlights: HashMap::default(),
 2381            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2382            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2383            nav_history: None,
 2384            context_menu: RefCell::new(None),
 2385            context_menu_options: None,
 2386            mouse_context_menu: None,
 2387            completion_tasks: Vec::new(),
 2388            inline_blame_popover: None,
 2389            inline_blame_popover_show_task: None,
 2390            signature_help_state: SignatureHelpState::default(),
 2391            auto_signature_help: None,
 2392            find_all_references_task_sources: Vec::new(),
 2393            next_completion_id: 0,
 2394            next_inlay_id: 0,
 2395            code_action_providers,
 2396            available_code_actions: None,
 2397            code_actions_task: None,
 2398            quick_selection_highlight_task: None,
 2399            debounced_selection_highlight_task: None,
 2400            debounced_selection_highlight_complete: false,
 2401            document_highlights_task: None,
 2402            linked_editing_range_task: None,
 2403            pending_rename: None,
 2404            searchable: !is_minimap,
 2405            cursor_shape: EditorSettings::get_global(cx)
 2406                .cursor_shape
 2407                .unwrap_or_default(),
 2408            cursor_offset_on_selection: false,
 2409            current_line_highlight: None,
 2410            autoindent_mode: Some(AutoindentMode::EachLine),
 2411            collapse_matches: false,
 2412            workspace: None,
 2413            input_enabled: !is_minimap,
 2414            use_modal_editing: full_mode,
 2415            read_only: is_minimap,
 2416            use_autoclose: true,
 2417            use_auto_surround: true,
 2418            auto_replace_emoji_shortcode: false,
 2419            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2420            leader_id: None,
 2421            remote_id: None,
 2422            hover_state: HoverState::default(),
 2423            pending_mouse_down: None,
 2424            prev_pressure_stage: None,
 2425            hovered_link_state: None,
 2426            edit_prediction_provider: None,
 2427            active_edit_prediction: None,
 2428            stale_edit_prediction_in_menu: None,
 2429            edit_prediction_preview: EditPredictionPreview::Inactive {
 2430                released_too_fast: false,
 2431            },
 2432            inline_diagnostics_enabled: full_mode,
 2433            diagnostics_enabled: full_mode,
 2434            word_completions_enabled: full_mode,
 2435            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2436            gutter_hovered: false,
 2437            pixel_position_of_newest_cursor: None,
 2438            last_bounds: None,
 2439            last_position_map: None,
 2440            expect_bounds_change: None,
 2441            gutter_dimensions: GutterDimensions::default(),
 2442            style: None,
 2443            show_cursor_names: false,
 2444            hovered_cursors: HashMap::default(),
 2445            next_editor_action_id: EditorActionId::default(),
 2446            editor_actions: Rc::default(),
 2447            edit_predictions_hidden_for_vim_mode: false,
 2448            show_edit_predictions_override: None,
 2449            show_completions_on_input_override: None,
 2450            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2451            edit_prediction_settings: EditPredictionSettings::Disabled,
 2452            edit_prediction_indent_conflict: false,
 2453            edit_prediction_requires_modifier_in_indent_conflict: true,
 2454            custom_context_menu: None,
 2455            show_git_blame_gutter: false,
 2456            show_git_blame_inline: false,
 2457            show_selection_menu: None,
 2458            show_git_blame_inline_delay_task: None,
 2459            git_blame_inline_enabled: full_mode
 2460                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2461            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2462            buffer_serialization: is_minimap.not().then(|| {
 2463                BufferSerialization::new(
 2464                    ProjectSettings::get_global(cx)
 2465                        .session
 2466                        .restore_unsaved_buffers,
 2467                )
 2468            }),
 2469            blame: None,
 2470            blame_subscription: None,
 2471            tasks: BTreeMap::default(),
 2472
 2473            breakpoint_store,
 2474            gutter_breakpoint_indicator: (None, None),
 2475            gutter_diff_review_indicator: (None, None),
 2476            diff_review_drag_state: None,
 2477            diff_review_overlays: Vec::new(),
 2478            stored_review_comments: Vec::new(),
 2479            next_review_comment_id: 0,
 2480            hovered_diff_hunk_row: None,
 2481            _subscriptions: (!is_minimap)
 2482                .then(|| {
 2483                    vec![
 2484                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2485                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2486                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2487                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2488                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2489                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2490                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2491                        cx.observe_window_activation(window, |editor, window, cx| {
 2492                            let active = window.is_window_active();
 2493                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2494                                if active {
 2495                                    blink_manager.enable(cx);
 2496                                } else {
 2497                                    blink_manager.disable(cx);
 2498                                }
 2499                            });
 2500                            if active {
 2501                                editor.show_mouse_cursor(cx);
 2502                            }
 2503                        }),
 2504                    ]
 2505                })
 2506                .unwrap_or_default(),
 2507            tasks_update_task: None,
 2508            pull_diagnostics_task: Task::ready(()),
 2509            colors: None,
 2510            refresh_colors_task: Task::ready(()),
 2511            inlay_hints: None,
 2512            next_color_inlay_id: 0,
 2513            post_scroll_update: Task::ready(()),
 2514            linked_edit_ranges: Default::default(),
 2515            in_project_search: false,
 2516            previous_search_ranges: None,
 2517            breadcrumb_header: None,
 2518            focused_block: None,
 2519            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2520            addons: HashMap::default(),
 2521            registered_buffers: HashMap::default(),
 2522            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2523            selection_mark_mode: false,
 2524            toggle_fold_multiple_buffers: Task::ready(()),
 2525            serialize_selections: Task::ready(()),
 2526            serialize_folds: Task::ready(()),
 2527            text_style_refinement: None,
 2528            load_diff_task: load_uncommitted_diff,
 2529            temporary_diff_override: false,
 2530            mouse_cursor_hidden: false,
 2531            minimap: None,
 2532            hide_mouse_mode: EditorSettings::get_global(cx)
 2533                .hide_mouse
 2534                .unwrap_or_default(),
 2535            change_list: ChangeList::new(),
 2536            mode,
 2537            selection_drag_state: SelectionDragState::None,
 2538            folding_newlines: Task::ready(()),
 2539            lookup_key: None,
 2540            select_next_is_case_sensitive: None,
 2541            scroll_companion: None,
 2542            on_local_selections_changed: None,
 2543            suppress_selection_callback: false,
 2544            applicable_language_settings: HashMap::default(),
 2545            accent_data: None,
 2546            fetched_tree_sitter_chunks: HashMap::default(),
 2547            number_deleted_lines: false,
 2548        };
 2549
 2550        if is_minimap {
 2551            return editor;
 2552        }
 2553
 2554        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2555        editor.accent_data = editor.fetch_accent_data(cx);
 2556
 2557        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2558            editor
 2559                ._subscriptions
 2560                .push(cx.observe(breakpoints, |_, _, cx| {
 2561                    cx.notify();
 2562                }));
 2563        }
 2564        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2565        editor._subscriptions.extend(project_subscriptions);
 2566
 2567        editor._subscriptions.push(cx.subscribe_in(
 2568            &cx.entity(),
 2569            window,
 2570            |editor, _, e: &EditorEvent, window, cx| match e {
 2571                EditorEvent::ScrollPositionChanged { local, .. } => {
 2572                    if *local {
 2573                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2574                        editor.inline_blame_popover.take();
 2575                        let new_anchor = editor.scroll_manager.anchor();
 2576                        let snapshot = editor.snapshot(window, cx);
 2577                        editor.update_restoration_data(cx, move |data| {
 2578                            data.scroll_position = (
 2579                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2580                                new_anchor.offset,
 2581                            );
 2582                        });
 2583
 2584                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2585                            cx.background_executor()
 2586                                .timer(Duration::from_millis(50))
 2587                                .await;
 2588                            editor
 2589                                .update_in(cx, |editor, window, cx| {
 2590                                    editor.register_visible_buffers(cx);
 2591                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2592                                    editor.refresh_inlay_hints(
 2593                                        InlayHintRefreshReason::NewLinesShown,
 2594                                        cx,
 2595                                    );
 2596                                    editor.colorize_brackets(false, cx);
 2597                                })
 2598                                .ok();
 2599                        });
 2600                    }
 2601                }
 2602                EditorEvent::Edited { .. } => {
 2603                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2604                        .map(|vim_mode| vim_mode.0)
 2605                        .unwrap_or(false);
 2606                    if !vim_mode {
 2607                        let display_map = editor.display_snapshot(cx);
 2608                        let selections = editor.selections.all_adjusted_display(&display_map);
 2609                        let pop_state = editor
 2610                            .change_list
 2611                            .last()
 2612                            .map(|previous| {
 2613                                previous.len() == selections.len()
 2614                                    && previous.iter().enumerate().all(|(ix, p)| {
 2615                                        p.to_display_point(&display_map).row()
 2616                                            == selections[ix].head().row()
 2617                                    })
 2618                            })
 2619                            .unwrap_or(false);
 2620                        let new_positions = selections
 2621                            .into_iter()
 2622                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2623                            .collect();
 2624                        editor
 2625                            .change_list
 2626                            .push_to_change_list(pop_state, new_positions);
 2627                    }
 2628                }
 2629                _ => (),
 2630            },
 2631        ));
 2632
 2633        if let Some(dap_store) = editor
 2634            .project
 2635            .as_ref()
 2636            .map(|project| project.read(cx).dap_store())
 2637        {
 2638            let weak_editor = cx.weak_entity();
 2639
 2640            editor
 2641                ._subscriptions
 2642                .push(
 2643                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2644                        let session_entity = cx.entity();
 2645                        weak_editor
 2646                            .update(cx, |editor, cx| {
 2647                                editor._subscriptions.push(
 2648                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2649                                );
 2650                            })
 2651                            .ok();
 2652                    }),
 2653                );
 2654
 2655            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2656                editor
 2657                    ._subscriptions
 2658                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2659            }
 2660        }
 2661
 2662        // skip adding the initial selection to selection history
 2663        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2664        editor.end_selection(window, cx);
 2665        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2666
 2667        editor.scroll_manager.show_scrollbars(window, cx);
 2668        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2669
 2670        if full_mode {
 2671            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2672            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2673
 2674            if editor.git_blame_inline_enabled {
 2675                editor.start_git_blame_inline(false, window, cx);
 2676            }
 2677
 2678            editor.go_to_active_debug_line(window, cx);
 2679
 2680            editor.minimap =
 2681                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2682            editor.colors = Some(LspColorData::new(cx));
 2683            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2684
 2685            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2686                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2687            }
 2688            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2689        }
 2690
 2691        editor
 2692    }
 2693
 2694    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2695        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2696    }
 2697
 2698    pub fn deploy_mouse_context_menu(
 2699        &mut self,
 2700        position: gpui::Point<Pixels>,
 2701        context_menu: Entity<ContextMenu>,
 2702        window: &mut Window,
 2703        cx: &mut Context<Self>,
 2704    ) {
 2705        self.mouse_context_menu = Some(MouseContextMenu::new(
 2706            self,
 2707            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2708            context_menu,
 2709            window,
 2710            cx,
 2711        ));
 2712    }
 2713
 2714    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2715        self.mouse_context_menu
 2716            .as_ref()
 2717            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2718    }
 2719
 2720    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2721        if self
 2722            .selections
 2723            .pending_anchor()
 2724            .is_some_and(|pending_selection| {
 2725                let snapshot = self.buffer().read(cx).snapshot(cx);
 2726                pending_selection.range().includes(range, &snapshot)
 2727            })
 2728        {
 2729            return true;
 2730        }
 2731
 2732        self.selections
 2733            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2734            .into_iter()
 2735            .any(|selection| {
 2736                // This is needed to cover a corner case, if we just check for an existing
 2737                // selection in the fold range, having a cursor at the start of the fold
 2738                // marks it as selected. Non-empty selections don't cause this.
 2739                let length = selection.end - selection.start;
 2740                length > 0
 2741            })
 2742    }
 2743
 2744    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2745        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2746    }
 2747
 2748    fn key_context_internal(
 2749        &self,
 2750        has_active_edit_prediction: bool,
 2751        window: &mut Window,
 2752        cx: &mut App,
 2753    ) -> KeyContext {
 2754        let mut key_context = KeyContext::new_with_defaults();
 2755        key_context.add("Editor");
 2756        let mode = match self.mode {
 2757            EditorMode::SingleLine => "single_line",
 2758            EditorMode::AutoHeight { .. } => "auto_height",
 2759            EditorMode::Minimap { .. } => "minimap",
 2760            EditorMode::Full { .. } => "full",
 2761        };
 2762
 2763        if EditorSettings::jupyter_enabled(cx) {
 2764            key_context.add("jupyter");
 2765        }
 2766
 2767        key_context.set("mode", mode);
 2768        if self.pending_rename.is_some() {
 2769            key_context.add("renaming");
 2770        }
 2771
 2772        if let Some(snippet_stack) = self.snippet_stack.last() {
 2773            key_context.add("in_snippet");
 2774
 2775            if snippet_stack.active_index > 0 {
 2776                key_context.add("has_previous_tabstop");
 2777            }
 2778
 2779            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2780                key_context.add("has_next_tabstop");
 2781            }
 2782        }
 2783
 2784        match self.context_menu.borrow().as_ref() {
 2785            Some(CodeContextMenu::Completions(menu)) => {
 2786                if menu.visible() {
 2787                    key_context.add("menu");
 2788                    key_context.add("showing_completions");
 2789                }
 2790            }
 2791            Some(CodeContextMenu::CodeActions(menu)) => {
 2792                if menu.visible() {
 2793                    key_context.add("menu");
 2794                    key_context.add("showing_code_actions")
 2795                }
 2796            }
 2797            None => {}
 2798        }
 2799
 2800        if self.signature_help_state.has_multiple_signatures() {
 2801            key_context.add("showing_signature_help");
 2802        }
 2803
 2804        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2805        if !self.focus_handle(cx).contains_focused(window, cx)
 2806            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2807        {
 2808            for addon in self.addons.values() {
 2809                addon.extend_key_context(&mut key_context, cx)
 2810            }
 2811        }
 2812
 2813        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2814            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2815                Some(
 2816                    file.full_path(cx)
 2817                        .extension()?
 2818                        .to_string_lossy()
 2819                        .to_lowercase(),
 2820                )
 2821            }) {
 2822                key_context.set("extension", extension);
 2823            }
 2824        } else {
 2825            key_context.add("multibuffer");
 2826        }
 2827
 2828        if has_active_edit_prediction {
 2829            if self.edit_prediction_in_conflict() {
 2830                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2831            } else {
 2832                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2833                key_context.add("copilot_suggestion");
 2834            }
 2835        }
 2836
 2837        if self.selection_mark_mode {
 2838            key_context.add("selection_mode");
 2839        }
 2840
 2841        let disjoint = self.selections.disjoint_anchors();
 2842        let snapshot = self.snapshot(window, cx);
 2843        let snapshot = snapshot.buffer_snapshot();
 2844        if self.mode == EditorMode::SingleLine
 2845            && let [selection] = disjoint
 2846            && selection.start == selection.end
 2847            && selection.end.to_offset(snapshot) == snapshot.len()
 2848        {
 2849            key_context.add("end_of_input");
 2850        }
 2851
 2852        if self.has_any_expanded_diff_hunks(cx) {
 2853            key_context.add("diffs_expanded");
 2854        }
 2855
 2856        key_context
 2857    }
 2858
 2859    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2860        self.last_bounds.as_ref()
 2861    }
 2862
 2863    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2864        if self.mouse_cursor_hidden {
 2865            self.mouse_cursor_hidden = false;
 2866            cx.notify();
 2867        }
 2868    }
 2869
 2870    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2871        let hide_mouse_cursor = match origin {
 2872            HideMouseCursorOrigin::TypingAction => {
 2873                matches!(
 2874                    self.hide_mouse_mode,
 2875                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2876                )
 2877            }
 2878            HideMouseCursorOrigin::MovementAction => {
 2879                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2880            }
 2881        };
 2882        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2883            self.mouse_cursor_hidden = hide_mouse_cursor;
 2884            cx.notify();
 2885        }
 2886    }
 2887
 2888    pub fn edit_prediction_in_conflict(&self) -> bool {
 2889        if !self.show_edit_predictions_in_menu() {
 2890            return false;
 2891        }
 2892
 2893        let showing_completions = self
 2894            .context_menu
 2895            .borrow()
 2896            .as_ref()
 2897            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2898
 2899        showing_completions
 2900            || self.edit_prediction_requires_modifier()
 2901            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2902            // bindings to insert tab characters.
 2903            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2904    }
 2905
 2906    pub fn accept_edit_prediction_keybind(
 2907        &self,
 2908        granularity: EditPredictionGranularity,
 2909        window: &mut Window,
 2910        cx: &mut App,
 2911    ) -> AcceptEditPredictionBinding {
 2912        let key_context = self.key_context_internal(true, window, cx);
 2913        let in_conflict = self.edit_prediction_in_conflict();
 2914
 2915        let bindings =
 2916            match granularity {
 2917                EditPredictionGranularity::Word => window
 2918                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2919                EditPredictionGranularity::Line => window
 2920                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2921                EditPredictionGranularity::Full => {
 2922                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2923                }
 2924            };
 2925
 2926        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2927            !in_conflict
 2928                || binding
 2929                    .keystrokes()
 2930                    .first()
 2931                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2932        }))
 2933    }
 2934
 2935    pub fn new_file(
 2936        workspace: &mut Workspace,
 2937        _: &workspace::NewFile,
 2938        window: &mut Window,
 2939        cx: &mut Context<Workspace>,
 2940    ) {
 2941        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2942            "Failed to create buffer",
 2943            window,
 2944            cx,
 2945            |e, _, _| match e.error_code() {
 2946                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2947                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2948                e.error_tag("required").unwrap_or("the latest version")
 2949            )),
 2950                _ => None,
 2951            },
 2952        );
 2953    }
 2954
 2955    pub fn new_in_workspace(
 2956        workspace: &mut Workspace,
 2957        window: &mut Window,
 2958        cx: &mut Context<Workspace>,
 2959    ) -> Task<Result<Entity<Editor>>> {
 2960        let project = workspace.project().clone();
 2961        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 2962
 2963        cx.spawn_in(window, async move |workspace, cx| {
 2964            let buffer = create.await?;
 2965            workspace.update_in(cx, |workspace, window, cx| {
 2966                let editor =
 2967                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2968                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2969                editor
 2970            })
 2971        })
 2972    }
 2973
 2974    fn new_file_vertical(
 2975        workspace: &mut Workspace,
 2976        _: &workspace::NewFileSplitVertical,
 2977        window: &mut Window,
 2978        cx: &mut Context<Workspace>,
 2979    ) {
 2980        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2981    }
 2982
 2983    fn new_file_horizontal(
 2984        workspace: &mut Workspace,
 2985        _: &workspace::NewFileSplitHorizontal,
 2986        window: &mut Window,
 2987        cx: &mut Context<Workspace>,
 2988    ) {
 2989        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2990    }
 2991
 2992    fn new_file_split(
 2993        workspace: &mut Workspace,
 2994        action: &workspace::NewFileSplit,
 2995        window: &mut Window,
 2996        cx: &mut Context<Workspace>,
 2997    ) {
 2998        Self::new_file_in_direction(workspace, action.0, window, cx)
 2999    }
 3000
 3001    fn new_file_in_direction(
 3002        workspace: &mut Workspace,
 3003        direction: SplitDirection,
 3004        window: &mut Window,
 3005        cx: &mut Context<Workspace>,
 3006    ) {
 3007        let project = workspace.project().clone();
 3008        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3009
 3010        cx.spawn_in(window, async move |workspace, cx| {
 3011            let buffer = create.await?;
 3012            workspace.update_in(cx, move |workspace, window, cx| {
 3013                workspace.split_item(
 3014                    direction,
 3015                    Box::new(
 3016                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3017                    ),
 3018                    window,
 3019                    cx,
 3020                )
 3021            })?;
 3022            anyhow::Ok(())
 3023        })
 3024        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3025            match e.error_code() {
 3026                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3027                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3028                e.error_tag("required").unwrap_or("the latest version")
 3029            )),
 3030                _ => None,
 3031            }
 3032        });
 3033    }
 3034
 3035    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3036        self.leader_id
 3037    }
 3038
 3039    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3040        &self.buffer
 3041    }
 3042
 3043    pub fn project(&self) -> Option<&Entity<Project>> {
 3044        self.project.as_ref()
 3045    }
 3046
 3047    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3048        self.workspace.as_ref()?.0.upgrade()
 3049    }
 3050
 3051    /// Returns the workspace serialization ID if this editor should be serialized.
 3052    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3053        self.workspace
 3054            .as_ref()
 3055            .filter(|_| self.should_serialize_buffer())
 3056            .and_then(|workspace| workspace.1)
 3057    }
 3058
 3059    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3060        self.buffer().read(cx).title(cx)
 3061    }
 3062
 3063    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3064        let git_blame_gutter_max_author_length = self
 3065            .render_git_blame_gutter(cx)
 3066            .then(|| {
 3067                if let Some(blame) = self.blame.as_ref() {
 3068                    let max_author_length =
 3069                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3070                    Some(max_author_length)
 3071                } else {
 3072                    None
 3073                }
 3074            })
 3075            .flatten();
 3076
 3077        EditorSnapshot {
 3078            mode: self.mode.clone(),
 3079            show_gutter: self.show_gutter,
 3080            offset_content: self.offset_content,
 3081            show_line_numbers: self.show_line_numbers,
 3082            number_deleted_lines: self.number_deleted_lines,
 3083            show_git_diff_gutter: self.show_git_diff_gutter,
 3084            show_code_actions: self.show_code_actions,
 3085            show_runnables: self.show_runnables,
 3086            show_breakpoints: self.show_breakpoints,
 3087            git_blame_gutter_max_author_length,
 3088            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 3089            placeholder_display_snapshot: self
 3090                .placeholder_display_map
 3091                .as_ref()
 3092                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3093            scroll_anchor: self.scroll_manager.anchor(),
 3094            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3095            is_focused: self.focus_handle.is_focused(window),
 3096            current_line_highlight: self
 3097                .current_line_highlight
 3098                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3099            gutter_hovered: self.gutter_hovered,
 3100        }
 3101    }
 3102
 3103    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3104        self.buffer.read(cx).language_at(point, cx)
 3105    }
 3106
 3107    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3108        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3109    }
 3110
 3111    pub fn active_excerpt(
 3112        &self,
 3113        cx: &App,
 3114    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3115        self.buffer
 3116            .read(cx)
 3117            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3118    }
 3119
 3120    pub fn mode(&self) -> &EditorMode {
 3121        &self.mode
 3122    }
 3123
 3124    pub fn set_mode(&mut self, mode: EditorMode) {
 3125        self.mode = mode;
 3126    }
 3127
 3128    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3129        self.collaboration_hub.as_deref()
 3130    }
 3131
 3132    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3133        self.collaboration_hub = Some(hub);
 3134    }
 3135
 3136    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3137        self.in_project_search = in_project_search;
 3138    }
 3139
 3140    pub fn set_custom_context_menu(
 3141        &mut self,
 3142        f: impl 'static
 3143        + Fn(
 3144            &mut Self,
 3145            DisplayPoint,
 3146            &mut Window,
 3147            &mut Context<Self>,
 3148        ) -> Option<Entity<ui::ContextMenu>>,
 3149    ) {
 3150        self.custom_context_menu = Some(Box::new(f))
 3151    }
 3152
 3153    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3154        self.completion_provider = provider;
 3155    }
 3156
 3157    #[cfg(any(test, feature = "test-support"))]
 3158    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3159        self.completion_provider.clone()
 3160    }
 3161
 3162    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3163        self.semantics_provider.clone()
 3164    }
 3165
 3166    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3167        self.semantics_provider = provider;
 3168    }
 3169
 3170    pub fn set_edit_prediction_provider<T>(
 3171        &mut self,
 3172        provider: Option<Entity<T>>,
 3173        window: &mut Window,
 3174        cx: &mut Context<Self>,
 3175    ) where
 3176        T: EditPredictionDelegate,
 3177    {
 3178        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3179            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3180                if this.focus_handle.is_focused(window) {
 3181                    this.update_visible_edit_prediction(window, cx);
 3182                }
 3183            }),
 3184            provider: Arc::new(provider),
 3185        });
 3186        self.update_edit_prediction_settings(cx);
 3187        self.refresh_edit_prediction(false, false, window, cx);
 3188    }
 3189
 3190    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3191        self.placeholder_display_map
 3192            .as_ref()
 3193            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3194    }
 3195
 3196    pub fn set_placeholder_text(
 3197        &mut self,
 3198        placeholder_text: &str,
 3199        window: &mut Window,
 3200        cx: &mut Context<Self>,
 3201    ) {
 3202        let multibuffer = cx
 3203            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3204
 3205        let style = window.text_style();
 3206
 3207        self.placeholder_display_map = Some(cx.new(|cx| {
 3208            DisplayMap::new(
 3209                multibuffer,
 3210                style.font(),
 3211                style.font_size.to_pixels(window.rem_size()),
 3212                None,
 3213                FILE_HEADER_HEIGHT,
 3214                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3215                Default::default(),
 3216                DiagnosticSeverity::Off,
 3217                cx,
 3218            )
 3219        }));
 3220        cx.notify();
 3221    }
 3222
 3223    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3224        self.cursor_shape = cursor_shape;
 3225
 3226        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3227        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3228
 3229        cx.notify();
 3230    }
 3231
 3232    pub fn cursor_shape(&self) -> CursorShape {
 3233        self.cursor_shape
 3234    }
 3235
 3236    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3237        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3238    }
 3239
 3240    pub fn set_current_line_highlight(
 3241        &mut self,
 3242        current_line_highlight: Option<CurrentLineHighlight>,
 3243    ) {
 3244        self.current_line_highlight = current_line_highlight;
 3245    }
 3246
 3247    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3248        self.collapse_matches = collapse_matches;
 3249    }
 3250
 3251    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3252        if self.collapse_matches {
 3253            return range.start..range.start;
 3254        }
 3255        range.clone()
 3256    }
 3257
 3258    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3259        self.display_map.read(cx).clip_at_line_ends
 3260    }
 3261
 3262    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3263        if self.display_map.read(cx).clip_at_line_ends != clip {
 3264            self.display_map
 3265                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3266        }
 3267    }
 3268
 3269    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3270        self.input_enabled = input_enabled;
 3271    }
 3272
 3273    pub fn set_edit_predictions_hidden_for_vim_mode(
 3274        &mut self,
 3275        hidden: bool,
 3276        window: &mut Window,
 3277        cx: &mut Context<Self>,
 3278    ) {
 3279        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3280            self.edit_predictions_hidden_for_vim_mode = hidden;
 3281            if hidden {
 3282                self.update_visible_edit_prediction(window, cx);
 3283            } else {
 3284                self.refresh_edit_prediction(true, false, window, cx);
 3285            }
 3286        }
 3287    }
 3288
 3289    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3290        self.menu_edit_predictions_policy = value;
 3291    }
 3292
 3293    pub fn set_autoindent(&mut self, autoindent: bool) {
 3294        if autoindent {
 3295            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3296        } else {
 3297            self.autoindent_mode = None;
 3298        }
 3299    }
 3300
 3301    pub fn capability(&self, cx: &App) -> Capability {
 3302        if self.read_only {
 3303            Capability::ReadOnly
 3304        } else {
 3305            self.buffer.read(cx).capability()
 3306        }
 3307    }
 3308
 3309    pub fn read_only(&self, cx: &App) -> bool {
 3310        self.read_only || self.buffer.read(cx).read_only()
 3311    }
 3312
 3313    pub fn set_read_only(&mut self, read_only: bool) {
 3314        self.read_only = read_only;
 3315    }
 3316
 3317    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3318        self.use_autoclose = autoclose;
 3319    }
 3320
 3321    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3322        self.use_auto_surround = auto_surround;
 3323    }
 3324
 3325    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3326        self.auto_replace_emoji_shortcode = auto_replace;
 3327    }
 3328
 3329    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3330        self.buffer_serialization = should_serialize.then(|| {
 3331            BufferSerialization::new(
 3332                ProjectSettings::get_global(cx)
 3333                    .session
 3334                    .restore_unsaved_buffers,
 3335            )
 3336        })
 3337    }
 3338
 3339    fn should_serialize_buffer(&self) -> bool {
 3340        self.buffer_serialization.is_some()
 3341    }
 3342
 3343    pub fn toggle_edit_predictions(
 3344        &mut self,
 3345        _: &ToggleEditPrediction,
 3346        window: &mut Window,
 3347        cx: &mut Context<Self>,
 3348    ) {
 3349        if self.show_edit_predictions_override.is_some() {
 3350            self.set_show_edit_predictions(None, window, cx);
 3351        } else {
 3352            let show_edit_predictions = !self.edit_predictions_enabled();
 3353            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3354        }
 3355    }
 3356
 3357    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3358        self.show_completions_on_input_override = show_completions_on_input;
 3359    }
 3360
 3361    pub fn set_show_edit_predictions(
 3362        &mut self,
 3363        show_edit_predictions: Option<bool>,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366    ) {
 3367        self.show_edit_predictions_override = show_edit_predictions;
 3368        self.update_edit_prediction_settings(cx);
 3369
 3370        if let Some(false) = show_edit_predictions {
 3371            self.discard_edit_prediction(false, cx);
 3372        } else {
 3373            self.refresh_edit_prediction(false, true, window, cx);
 3374        }
 3375    }
 3376
 3377    fn edit_predictions_disabled_in_scope(
 3378        &self,
 3379        buffer: &Entity<Buffer>,
 3380        buffer_position: language::Anchor,
 3381        cx: &App,
 3382    ) -> bool {
 3383        let snapshot = buffer.read(cx).snapshot();
 3384        let settings = snapshot.settings_at(buffer_position, cx);
 3385
 3386        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3387            return false;
 3388        };
 3389
 3390        scope.override_name().is_some_and(|scope_name| {
 3391            settings
 3392                .edit_predictions_disabled_in
 3393                .iter()
 3394                .any(|s| s == scope_name)
 3395        })
 3396    }
 3397
 3398    pub fn set_use_modal_editing(&mut self, to: bool) {
 3399        self.use_modal_editing = to;
 3400    }
 3401
 3402    pub fn use_modal_editing(&self) -> bool {
 3403        self.use_modal_editing
 3404    }
 3405
 3406    fn selections_did_change(
 3407        &mut self,
 3408        local: bool,
 3409        old_cursor_position: &Anchor,
 3410        effects: SelectionEffects,
 3411        window: &mut Window,
 3412        cx: &mut Context<Self>,
 3413    ) {
 3414        window.invalidate_character_coordinates();
 3415
 3416        // Copy selections to primary selection buffer
 3417        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3418        if local {
 3419            let selections = self
 3420                .selections
 3421                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3422            let buffer_handle = self.buffer.read(cx).read(cx);
 3423
 3424            let mut text = String::new();
 3425            for (index, selection) in selections.iter().enumerate() {
 3426                let text_for_selection = buffer_handle
 3427                    .text_for_range(selection.start..selection.end)
 3428                    .collect::<String>();
 3429
 3430                text.push_str(&text_for_selection);
 3431                if index != selections.len() - 1 {
 3432                    text.push('\n');
 3433                }
 3434            }
 3435
 3436            if !text.is_empty() {
 3437                cx.write_to_primary(ClipboardItem::new_string(text));
 3438            }
 3439        }
 3440
 3441        let selection_anchors = self.selections.disjoint_anchors_arc();
 3442
 3443        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3444            self.buffer.update(cx, |buffer, cx| {
 3445                buffer.set_active_selections(
 3446                    &selection_anchors,
 3447                    self.selections.line_mode(),
 3448                    self.cursor_shape,
 3449                    cx,
 3450                )
 3451            });
 3452        }
 3453        let display_map = self
 3454            .display_map
 3455            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3456        let buffer = display_map.buffer_snapshot();
 3457        if self.selections.count() == 1 {
 3458            self.add_selections_state = None;
 3459        }
 3460        self.select_next_state = None;
 3461        self.select_prev_state = None;
 3462        self.select_syntax_node_history.try_clear();
 3463        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3464        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3465        self.take_rename(false, window, cx);
 3466
 3467        let newest_selection = self.selections.newest_anchor();
 3468        let new_cursor_position = newest_selection.head();
 3469        let selection_start = newest_selection.start;
 3470
 3471        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3472            self.push_to_nav_history(
 3473                *old_cursor_position,
 3474                Some(new_cursor_position.to_point(buffer)),
 3475                false,
 3476                effects.nav_history == Some(true),
 3477                cx,
 3478            );
 3479        }
 3480
 3481        if local {
 3482            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3483                self.register_buffer(buffer_id, cx);
 3484            }
 3485
 3486            let mut context_menu = self.context_menu.borrow_mut();
 3487            let completion_menu = match context_menu.as_ref() {
 3488                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3489                Some(CodeContextMenu::CodeActions(_)) => {
 3490                    *context_menu = None;
 3491                    None
 3492                }
 3493                None => None,
 3494            };
 3495            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3496            drop(context_menu);
 3497
 3498            if effects.completions
 3499                && let Some(completion_position) = completion_position
 3500            {
 3501                let start_offset = selection_start.to_offset(buffer);
 3502                let position_matches = start_offset == completion_position.to_offset(buffer);
 3503                let continue_showing = if let Some((snap, ..)) =
 3504                    buffer.point_to_buffer_offset(completion_position)
 3505                    && !snap.capability.editable()
 3506                {
 3507                    false
 3508                } else if position_matches {
 3509                    if self.snippet_stack.is_empty() {
 3510                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3511                            == Some(CharKind::Word)
 3512                    } else {
 3513                        // Snippet choices can be shown even when the cursor is in whitespace.
 3514                        // Dismissing the menu with actions like backspace is handled by
 3515                        // invalidation regions.
 3516                        true
 3517                    }
 3518                } else {
 3519                    false
 3520                };
 3521
 3522                if continue_showing {
 3523                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3524                } else {
 3525                    self.hide_context_menu(window, cx);
 3526                }
 3527            }
 3528
 3529            hide_hover(self, cx);
 3530
 3531            if old_cursor_position.to_display_point(&display_map).row()
 3532                != new_cursor_position.to_display_point(&display_map).row()
 3533            {
 3534                self.available_code_actions.take();
 3535            }
 3536            self.refresh_code_actions(window, cx);
 3537            self.refresh_document_highlights(cx);
 3538            refresh_linked_ranges(self, window, cx);
 3539
 3540            self.refresh_selected_text_highlights(false, window, cx);
 3541            self.refresh_matching_bracket_highlights(window, cx);
 3542            self.update_visible_edit_prediction(window, cx);
 3543            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3544            self.inline_blame_popover.take();
 3545            if self.git_blame_inline_enabled {
 3546                self.start_inline_blame_timer(window, cx);
 3547            }
 3548        }
 3549
 3550        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3551
 3552        if local && !self.suppress_selection_callback {
 3553            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3554                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3555                callback(cursor_position, window, cx);
 3556            }
 3557        }
 3558
 3559        cx.emit(EditorEvent::SelectionsChanged { local });
 3560
 3561        let selections = &self.selections.disjoint_anchors_arc();
 3562        if selections.len() == 1 {
 3563            cx.emit(SearchEvent::ActiveMatchChanged)
 3564        }
 3565        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3566            let inmemory_selections = selections
 3567                .iter()
 3568                .map(|s| {
 3569                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3570                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3571                })
 3572                .collect();
 3573            self.update_restoration_data(cx, |data| {
 3574                data.selections = inmemory_selections;
 3575            });
 3576
 3577            if WorkspaceSettings::get(None, cx).restore_on_startup
 3578                != RestoreOnStartupBehavior::EmptyTab
 3579                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3580            {
 3581                let snapshot = self.buffer().read(cx).snapshot(cx);
 3582                let selections = selections.clone();
 3583                let background_executor = cx.background_executor().clone();
 3584                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3585                self.serialize_selections = cx.background_spawn(async move {
 3586                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3587                    let db_selections = selections
 3588                        .iter()
 3589                        .map(|selection| {
 3590                            (
 3591                                selection.start.to_offset(&snapshot).0,
 3592                                selection.end.to_offset(&snapshot).0,
 3593                            )
 3594                        })
 3595                        .collect();
 3596
 3597                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3598                        .await
 3599                        .with_context(|| {
 3600                            format!(
 3601                                "persisting editor selections for editor {editor_id}, \
 3602                                workspace {workspace_id:?}"
 3603                            )
 3604                        })
 3605                        .log_err();
 3606                });
 3607            }
 3608        }
 3609
 3610        cx.notify();
 3611    }
 3612
 3613    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3614        use text::ToOffset as _;
 3615        use text::ToPoint as _;
 3616
 3617        if self.mode.is_minimap()
 3618            || WorkspaceSettings::get(None, cx).restore_on_startup
 3619                == RestoreOnStartupBehavior::EmptyTab
 3620        {
 3621            return;
 3622        }
 3623
 3624        if !self.buffer().read(cx).is_singleton() {
 3625            return;
 3626        }
 3627
 3628        let display_snapshot = self
 3629            .display_map
 3630            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3631        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3632            return;
 3633        };
 3634        let inmemory_folds = display_snapshot
 3635            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3636            .map(|fold| {
 3637                fold.range.start.text_anchor.to_point(&snapshot)
 3638                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3639            })
 3640            .collect();
 3641        self.update_restoration_data(cx, |data| {
 3642            data.folds = inmemory_folds;
 3643        });
 3644
 3645        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3646            return;
 3647        };
 3648        let background_executor = cx.background_executor().clone();
 3649        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3650        const FINGERPRINT_LEN: usize = 32;
 3651        let db_folds = display_snapshot
 3652            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3653            .map(|fold| {
 3654                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3655                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3656
 3657                // Extract fingerprints - content at fold boundaries for validation on restore
 3658                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3659                // content that might change independently.
 3660                // start_fp: first min(32, fold_len) bytes of fold content
 3661                // end_fp: last min(32, fold_len) bytes of fold content
 3662                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3663                let fold_len = end - start;
 3664                let start_fp_end = snapshot
 3665                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3666                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3667                let end_fp_start = snapshot
 3668                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3669                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3670
 3671                (start, end, start_fp, end_fp)
 3672            })
 3673            .collect::<Vec<_>>();
 3674        self.serialize_folds = cx.background_spawn(async move {
 3675            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3676            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3677                .await
 3678                .with_context(|| {
 3679                    format!(
 3680                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3681                    )
 3682                })
 3683                .log_err();
 3684        });
 3685    }
 3686
 3687    pub fn sync_selections(
 3688        &mut self,
 3689        other: Entity<Editor>,
 3690        cx: &mut Context<Self>,
 3691    ) -> gpui::Subscription {
 3692        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3693        if !other_selections.is_empty() {
 3694            self.selections
 3695                .change_with(&self.display_snapshot(cx), |selections| {
 3696                    selections.select_anchors(other_selections);
 3697                });
 3698        }
 3699
 3700        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3701            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3702                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3703                if other_selections.is_empty() {
 3704                    return;
 3705                }
 3706                let snapshot = this.display_snapshot(cx);
 3707                this.selections.change_with(&snapshot, |selections| {
 3708                    selections.select_anchors(other_selections);
 3709                });
 3710            }
 3711        });
 3712
 3713        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3714            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3715                let these_selections = this.selections.disjoint_anchors().to_vec();
 3716                if these_selections.is_empty() {
 3717                    return;
 3718                }
 3719                other.update(cx, |other_editor, cx| {
 3720                    let snapshot = other_editor.display_snapshot(cx);
 3721                    other_editor
 3722                        .selections
 3723                        .change_with(&snapshot, |selections| {
 3724                            selections.select_anchors(these_selections);
 3725                        })
 3726                });
 3727            }
 3728        });
 3729
 3730        Subscription::join(other_subscription, this_subscription)
 3731    }
 3732
 3733    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3734        if self.buffer().read(cx).is_singleton() {
 3735            return;
 3736        }
 3737        let snapshot = self.buffer.read(cx).snapshot(cx);
 3738        let buffer_ids: HashSet<BufferId> = self
 3739            .selections
 3740            .disjoint_anchor_ranges()
 3741            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3742            .collect();
 3743        for buffer_id in buffer_ids {
 3744            self.unfold_buffer(buffer_id, cx);
 3745        }
 3746    }
 3747
 3748    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3749    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3750    /// effects of selection change occur at the end of the transaction.
 3751    pub fn change_selections<R>(
 3752        &mut self,
 3753        effects: SelectionEffects,
 3754        window: &mut Window,
 3755        cx: &mut Context<Self>,
 3756        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3757    ) -> R {
 3758        let snapshot = self.display_snapshot(cx);
 3759        if let Some(state) = &mut self.deferred_selection_effects_state {
 3760            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3761            state.effects.completions = effects.completions;
 3762            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3763            let (changed, result) = self.selections.change_with(&snapshot, change);
 3764            state.changed |= changed;
 3765            return result;
 3766        }
 3767        let mut state = DeferredSelectionEffectsState {
 3768            changed: false,
 3769            effects,
 3770            old_cursor_position: self.selections.newest_anchor().head(),
 3771            history_entry: SelectionHistoryEntry {
 3772                selections: self.selections.disjoint_anchors_arc(),
 3773                select_next_state: self.select_next_state.clone(),
 3774                select_prev_state: self.select_prev_state.clone(),
 3775                add_selections_state: self.add_selections_state.clone(),
 3776            },
 3777        };
 3778        let (changed, result) = self.selections.change_with(&snapshot, change);
 3779        state.changed = state.changed || changed;
 3780        if self.defer_selection_effects {
 3781            self.deferred_selection_effects_state = Some(state);
 3782        } else {
 3783            self.apply_selection_effects(state, window, cx);
 3784        }
 3785        result
 3786    }
 3787
 3788    /// Defers the effects of selection change, so that the effects of multiple calls to
 3789    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3790    /// to selection history and the state of popovers based on selection position aren't
 3791    /// erroneously updated.
 3792    pub fn with_selection_effects_deferred<R>(
 3793        &mut self,
 3794        window: &mut Window,
 3795        cx: &mut Context<Self>,
 3796        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3797    ) -> R {
 3798        let already_deferred = self.defer_selection_effects;
 3799        self.defer_selection_effects = true;
 3800        let result = update(self, window, cx);
 3801        if !already_deferred {
 3802            self.defer_selection_effects = false;
 3803            if let Some(state) = self.deferred_selection_effects_state.take() {
 3804                self.apply_selection_effects(state, window, cx);
 3805            }
 3806        }
 3807        result
 3808    }
 3809
 3810    fn apply_selection_effects(
 3811        &mut self,
 3812        state: DeferredSelectionEffectsState,
 3813        window: &mut Window,
 3814        cx: &mut Context<Self>,
 3815    ) {
 3816        if state.changed {
 3817            self.selection_history.push(state.history_entry);
 3818
 3819            if let Some(autoscroll) = state.effects.scroll {
 3820                self.request_autoscroll(autoscroll, cx);
 3821            }
 3822
 3823            let old_cursor_position = &state.old_cursor_position;
 3824
 3825            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3826
 3827            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3828                self.show_signature_help_auto(window, cx);
 3829            }
 3830        }
 3831    }
 3832
 3833    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3834    where
 3835        I: IntoIterator<Item = (Range<S>, T)>,
 3836        S: ToOffset,
 3837        T: Into<Arc<str>>,
 3838    {
 3839        if self.read_only(cx) {
 3840            return;
 3841        }
 3842
 3843        self.buffer
 3844            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3845    }
 3846
 3847    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3848    where
 3849        I: IntoIterator<Item = (Range<S>, T)>,
 3850        S: ToOffset,
 3851        T: Into<Arc<str>>,
 3852    {
 3853        if self.read_only(cx) {
 3854            return;
 3855        }
 3856
 3857        self.buffer.update(cx, |buffer, cx| {
 3858            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3859        });
 3860    }
 3861
 3862    pub fn edit_with_block_indent<I, S, T>(
 3863        &mut self,
 3864        edits: I,
 3865        original_indent_columns: Vec<Option<u32>>,
 3866        cx: &mut Context<Self>,
 3867    ) where
 3868        I: IntoIterator<Item = (Range<S>, T)>,
 3869        S: ToOffset,
 3870        T: Into<Arc<str>>,
 3871    {
 3872        if self.read_only(cx) {
 3873            return;
 3874        }
 3875
 3876        self.buffer.update(cx, |buffer, cx| {
 3877            buffer.edit(
 3878                edits,
 3879                Some(AutoindentMode::Block {
 3880                    original_indent_columns,
 3881                }),
 3882                cx,
 3883            )
 3884        });
 3885    }
 3886
 3887    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3888        self.hide_context_menu(window, cx);
 3889
 3890        match phase {
 3891            SelectPhase::Begin {
 3892                position,
 3893                add,
 3894                click_count,
 3895            } => self.begin_selection(position, add, click_count, window, cx),
 3896            SelectPhase::BeginColumnar {
 3897                position,
 3898                goal_column,
 3899                reset,
 3900                mode,
 3901            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3902            SelectPhase::Extend {
 3903                position,
 3904                click_count,
 3905            } => self.extend_selection(position, click_count, window, cx),
 3906            SelectPhase::Update {
 3907                position,
 3908                goal_column,
 3909                scroll_delta,
 3910            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3911            SelectPhase::End => self.end_selection(window, cx),
 3912        }
 3913    }
 3914
 3915    fn extend_selection(
 3916        &mut self,
 3917        position: DisplayPoint,
 3918        click_count: usize,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) {
 3922        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3923        let tail = self
 3924            .selections
 3925            .newest::<MultiBufferOffset>(&display_map)
 3926            .tail();
 3927        let click_count = click_count.max(match self.selections.select_mode() {
 3928            SelectMode::Character => 1,
 3929            SelectMode::Word(_) => 2,
 3930            SelectMode::Line(_) => 3,
 3931            SelectMode::All => 4,
 3932        });
 3933        self.begin_selection(position, false, click_count, window, cx);
 3934
 3935        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3936
 3937        let current_selection = match self.selections.select_mode() {
 3938            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3939            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3940        };
 3941
 3942        let mut pending_selection = self
 3943            .selections
 3944            .pending_anchor()
 3945            .cloned()
 3946            .expect("extend_selection not called with pending selection");
 3947
 3948        if pending_selection
 3949            .start
 3950            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3951            == Ordering::Greater
 3952        {
 3953            pending_selection.start = current_selection.start;
 3954        }
 3955        if pending_selection
 3956            .end
 3957            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3958            == Ordering::Less
 3959        {
 3960            pending_selection.end = current_selection.end;
 3961            pending_selection.reversed = true;
 3962        }
 3963
 3964        let mut pending_mode = self.selections.pending_mode().unwrap();
 3965        match &mut pending_mode {
 3966            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3967            _ => {}
 3968        }
 3969
 3970        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3971            SelectionEffects::scroll(Autoscroll::fit())
 3972        } else {
 3973            SelectionEffects::no_scroll()
 3974        };
 3975
 3976        self.change_selections(effects, window, cx, |s| {
 3977            s.set_pending(pending_selection.clone(), pending_mode);
 3978            s.set_is_extending(true);
 3979        });
 3980    }
 3981
 3982    fn begin_selection(
 3983        &mut self,
 3984        position: DisplayPoint,
 3985        add: bool,
 3986        click_count: usize,
 3987        window: &mut Window,
 3988        cx: &mut Context<Self>,
 3989    ) {
 3990        if !self.focus_handle.is_focused(window) {
 3991            self.last_focused_descendant = None;
 3992            window.focus(&self.focus_handle, cx);
 3993        }
 3994
 3995        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3996        let buffer = display_map.buffer_snapshot();
 3997        let position = display_map.clip_point(position, Bias::Left);
 3998
 3999        let start;
 4000        let end;
 4001        let mode;
 4002        let mut auto_scroll;
 4003        match click_count {
 4004            1 => {
 4005                start = buffer.anchor_before(position.to_point(&display_map));
 4006                end = start;
 4007                mode = SelectMode::Character;
 4008                auto_scroll = true;
 4009            }
 4010            2 => {
 4011                let position = display_map
 4012                    .clip_point(position, Bias::Left)
 4013                    .to_offset(&display_map, Bias::Left);
 4014                let (range, _) = buffer.surrounding_word(position, None);
 4015                start = buffer.anchor_before(range.start);
 4016                end = buffer.anchor_before(range.end);
 4017                mode = SelectMode::Word(start..end);
 4018                auto_scroll = true;
 4019            }
 4020            3 => {
 4021                let position = display_map
 4022                    .clip_point(position, Bias::Left)
 4023                    .to_point(&display_map);
 4024                let line_start = display_map.prev_line_boundary(position).0;
 4025                let next_line_start = buffer.clip_point(
 4026                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4027                    Bias::Left,
 4028                );
 4029                start = buffer.anchor_before(line_start);
 4030                end = buffer.anchor_before(next_line_start);
 4031                mode = SelectMode::Line(start..end);
 4032                auto_scroll = true;
 4033            }
 4034            _ => {
 4035                start = buffer.anchor_before(MultiBufferOffset(0));
 4036                end = buffer.anchor_before(buffer.len());
 4037                mode = SelectMode::All;
 4038                auto_scroll = false;
 4039            }
 4040        }
 4041        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4042
 4043        let point_to_delete: Option<usize> = {
 4044            let selected_points: Vec<Selection<Point>> =
 4045                self.selections.disjoint_in_range(start..end, &display_map);
 4046
 4047            if !add || click_count > 1 {
 4048                None
 4049            } else if !selected_points.is_empty() {
 4050                Some(selected_points[0].id)
 4051            } else {
 4052                let clicked_point_already_selected =
 4053                    self.selections.disjoint_anchors().iter().find(|selection| {
 4054                        selection.start.to_point(buffer) == start.to_point(buffer)
 4055                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4056                    });
 4057
 4058                clicked_point_already_selected.map(|selection| selection.id)
 4059            }
 4060        };
 4061
 4062        let selections_count = self.selections.count();
 4063        let effects = if auto_scroll {
 4064            SelectionEffects::default()
 4065        } else {
 4066            SelectionEffects::no_scroll()
 4067        };
 4068
 4069        self.change_selections(effects, window, cx, |s| {
 4070            if let Some(point_to_delete) = point_to_delete {
 4071                s.delete(point_to_delete);
 4072
 4073                if selections_count == 1 {
 4074                    s.set_pending_anchor_range(start..end, mode);
 4075                }
 4076            } else {
 4077                if !add {
 4078                    s.clear_disjoint();
 4079                }
 4080
 4081                s.set_pending_anchor_range(start..end, mode);
 4082            }
 4083        });
 4084    }
 4085
 4086    fn begin_columnar_selection(
 4087        &mut self,
 4088        position: DisplayPoint,
 4089        goal_column: u32,
 4090        reset: bool,
 4091        mode: ColumnarMode,
 4092        window: &mut Window,
 4093        cx: &mut Context<Self>,
 4094    ) {
 4095        if !self.focus_handle.is_focused(window) {
 4096            self.last_focused_descendant = None;
 4097            window.focus(&self.focus_handle, cx);
 4098        }
 4099
 4100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4101
 4102        if reset {
 4103            let pointer_position = display_map
 4104                .buffer_snapshot()
 4105                .anchor_before(position.to_point(&display_map));
 4106
 4107            self.change_selections(
 4108                SelectionEffects::scroll(Autoscroll::newest()),
 4109                window,
 4110                cx,
 4111                |s| {
 4112                    s.clear_disjoint();
 4113                    s.set_pending_anchor_range(
 4114                        pointer_position..pointer_position,
 4115                        SelectMode::Character,
 4116                    );
 4117                },
 4118            );
 4119        };
 4120
 4121        let tail = self.selections.newest::<Point>(&display_map).tail();
 4122        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4123        self.columnar_selection_state = match mode {
 4124            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4125                selection_tail: selection_anchor,
 4126                display_point: if reset {
 4127                    if position.column() != goal_column {
 4128                        Some(DisplayPoint::new(position.row(), goal_column))
 4129                    } else {
 4130                        None
 4131                    }
 4132                } else {
 4133                    None
 4134                },
 4135            }),
 4136            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4137                selection_tail: selection_anchor,
 4138            }),
 4139        };
 4140
 4141        if !reset {
 4142            self.select_columns(position, goal_column, &display_map, window, cx);
 4143        }
 4144    }
 4145
 4146    fn update_selection(
 4147        &mut self,
 4148        position: DisplayPoint,
 4149        goal_column: u32,
 4150        scroll_delta: gpui::Point<f32>,
 4151        window: &mut Window,
 4152        cx: &mut Context<Self>,
 4153    ) {
 4154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4155
 4156        if self.columnar_selection_state.is_some() {
 4157            self.select_columns(position, goal_column, &display_map, window, cx);
 4158        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4159            let buffer = display_map.buffer_snapshot();
 4160            let head;
 4161            let tail;
 4162            let mode = self.selections.pending_mode().unwrap();
 4163            match &mode {
 4164                SelectMode::Character => {
 4165                    head = position.to_point(&display_map);
 4166                    tail = pending.tail().to_point(buffer);
 4167                }
 4168                SelectMode::Word(original_range) => {
 4169                    let offset = display_map
 4170                        .clip_point(position, Bias::Left)
 4171                        .to_offset(&display_map, Bias::Left);
 4172                    let original_range = original_range.to_offset(buffer);
 4173
 4174                    let head_offset = if buffer.is_inside_word(offset, None)
 4175                        || original_range.contains(&offset)
 4176                    {
 4177                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4178                        if word_range.start < original_range.start {
 4179                            word_range.start
 4180                        } else {
 4181                            word_range.end
 4182                        }
 4183                    } else {
 4184                        offset
 4185                    };
 4186
 4187                    head = head_offset.to_point(buffer);
 4188                    if head_offset <= original_range.start {
 4189                        tail = original_range.end.to_point(buffer);
 4190                    } else {
 4191                        tail = original_range.start.to_point(buffer);
 4192                    }
 4193                }
 4194                SelectMode::Line(original_range) => {
 4195                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4196
 4197                    let position = display_map
 4198                        .clip_point(position, Bias::Left)
 4199                        .to_point(&display_map);
 4200                    let line_start = display_map.prev_line_boundary(position).0;
 4201                    let next_line_start = buffer.clip_point(
 4202                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4203                        Bias::Left,
 4204                    );
 4205
 4206                    if line_start < original_range.start {
 4207                        head = line_start
 4208                    } else {
 4209                        head = next_line_start
 4210                    }
 4211
 4212                    if head <= original_range.start {
 4213                        tail = original_range.end;
 4214                    } else {
 4215                        tail = original_range.start;
 4216                    }
 4217                }
 4218                SelectMode::All => {
 4219                    return;
 4220                }
 4221            };
 4222
 4223            if head < tail {
 4224                pending.start = buffer.anchor_before(head);
 4225                pending.end = buffer.anchor_before(tail);
 4226                pending.reversed = true;
 4227            } else {
 4228                pending.start = buffer.anchor_before(tail);
 4229                pending.end = buffer.anchor_before(head);
 4230                pending.reversed = false;
 4231            }
 4232
 4233            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4234                s.set_pending(pending.clone(), mode);
 4235            });
 4236        } else {
 4237            log::error!("update_selection dispatched with no pending selection");
 4238            return;
 4239        }
 4240
 4241        self.apply_scroll_delta(scroll_delta, window, cx);
 4242        cx.notify();
 4243    }
 4244
 4245    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4246        self.columnar_selection_state.take();
 4247        if let Some(pending_mode) = self.selections.pending_mode() {
 4248            let selections = self
 4249                .selections
 4250                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4251            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4252                s.select(selections);
 4253                s.clear_pending();
 4254                if s.is_extending() {
 4255                    s.set_is_extending(false);
 4256                } else {
 4257                    s.set_select_mode(pending_mode);
 4258                }
 4259            });
 4260        }
 4261    }
 4262
 4263    fn select_columns(
 4264        &mut self,
 4265        head: DisplayPoint,
 4266        goal_column: u32,
 4267        display_map: &DisplaySnapshot,
 4268        window: &mut Window,
 4269        cx: &mut Context<Self>,
 4270    ) {
 4271        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4272            return;
 4273        };
 4274
 4275        let tail = match columnar_state {
 4276            ColumnarSelectionState::FromMouse {
 4277                selection_tail,
 4278                display_point,
 4279            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4280            ColumnarSelectionState::FromSelection { selection_tail } => {
 4281                selection_tail.to_display_point(display_map)
 4282            }
 4283        };
 4284
 4285        let start_row = cmp::min(tail.row(), head.row());
 4286        let end_row = cmp::max(tail.row(), head.row());
 4287        let start_column = cmp::min(tail.column(), goal_column);
 4288        let end_column = cmp::max(tail.column(), goal_column);
 4289        let reversed = start_column < tail.column();
 4290
 4291        let selection_ranges = (start_row.0..=end_row.0)
 4292            .map(DisplayRow)
 4293            .filter_map(|row| {
 4294                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4295                    || start_column <= display_map.line_len(row))
 4296                    && !display_map.is_block_line(row)
 4297                {
 4298                    let start = display_map
 4299                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4300                        .to_point(display_map);
 4301                    let end = display_map
 4302                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4303                        .to_point(display_map);
 4304                    if reversed {
 4305                        Some(end..start)
 4306                    } else {
 4307                        Some(start..end)
 4308                    }
 4309                } else {
 4310                    None
 4311                }
 4312            })
 4313            .collect::<Vec<_>>();
 4314        if selection_ranges.is_empty() {
 4315            return;
 4316        }
 4317
 4318        let ranges = match columnar_state {
 4319            ColumnarSelectionState::FromMouse { .. } => {
 4320                let mut non_empty_ranges = selection_ranges
 4321                    .iter()
 4322                    .filter(|selection_range| selection_range.start != selection_range.end)
 4323                    .peekable();
 4324                if non_empty_ranges.peek().is_some() {
 4325                    non_empty_ranges.cloned().collect()
 4326                } else {
 4327                    selection_ranges
 4328                }
 4329            }
 4330            _ => selection_ranges,
 4331        };
 4332
 4333        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4334            s.select_ranges(ranges);
 4335        });
 4336        cx.notify();
 4337    }
 4338
 4339    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4340        self.selections
 4341            .all_adjusted(snapshot)
 4342            .iter()
 4343            .any(|selection| !selection.is_empty())
 4344    }
 4345
 4346    pub fn has_pending_nonempty_selection(&self) -> bool {
 4347        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4348            Some(Selection { start, end, .. }) => start != end,
 4349            None => false,
 4350        };
 4351
 4352        pending_nonempty_selection
 4353            || (self.columnar_selection_state.is_some()
 4354                && self.selections.disjoint_anchors().len() > 1)
 4355    }
 4356
 4357    pub fn has_pending_selection(&self) -> bool {
 4358        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4359    }
 4360
 4361    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4362        self.selection_mark_mode = false;
 4363        self.selection_drag_state = SelectionDragState::None;
 4364
 4365        if self.dismiss_menus_and_popups(true, window, cx) {
 4366            cx.notify();
 4367            return;
 4368        }
 4369        if self.clear_expanded_diff_hunks(cx) {
 4370            cx.notify();
 4371            return;
 4372        }
 4373        if self.show_git_blame_gutter {
 4374            self.show_git_blame_gutter = false;
 4375            cx.notify();
 4376            return;
 4377        }
 4378
 4379        if self.mode.is_full()
 4380            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4381        {
 4382            cx.notify();
 4383            return;
 4384        }
 4385
 4386        cx.propagate();
 4387    }
 4388
 4389    pub fn dismiss_menus_and_popups(
 4390        &mut self,
 4391        is_user_requested: bool,
 4392        window: &mut Window,
 4393        cx: &mut Context<Self>,
 4394    ) -> bool {
 4395        let mut dismissed = false;
 4396
 4397        dismissed |= self.take_rename(false, window, cx).is_some();
 4398        dismissed |= self.hide_blame_popover(true, cx);
 4399        dismissed |= hide_hover(self, cx);
 4400        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4401        dismissed |= self.hide_context_menu(window, cx).is_some();
 4402        dismissed |= self.mouse_context_menu.take().is_some();
 4403        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4404        dismissed |= self.snippet_stack.pop().is_some();
 4405        if self.diff_review_drag_state.is_some() {
 4406            self.cancel_diff_review_drag(cx);
 4407            dismissed = true;
 4408        }
 4409        if !self.diff_review_overlays.is_empty() {
 4410            self.dismiss_all_diff_review_overlays(cx);
 4411            dismissed = true;
 4412        }
 4413
 4414        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4415            self.dismiss_diagnostics(cx);
 4416            dismissed = true;
 4417        }
 4418
 4419        dismissed
 4420    }
 4421
 4422    fn linked_editing_ranges_for(
 4423        &self,
 4424        selection: Range<text::Anchor>,
 4425        cx: &App,
 4426    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4427        if self.linked_edit_ranges.is_empty() {
 4428            return None;
 4429        }
 4430        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4431            selection.end.buffer_id.and_then(|end_buffer_id| {
 4432                if selection.start.buffer_id != Some(end_buffer_id) {
 4433                    return None;
 4434                }
 4435                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4436                let snapshot = buffer.read(cx).snapshot();
 4437                self.linked_edit_ranges
 4438                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4439                    .map(|ranges| (ranges, snapshot, buffer))
 4440            })?;
 4441        use text::ToOffset as TO;
 4442        // find offset from the start of current range to current cursor position
 4443        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4444
 4445        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4446        let start_difference = start_offset - start_byte_offset;
 4447        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4448        let end_difference = end_offset - start_byte_offset;
 4449        // Current range has associated linked ranges.
 4450        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4451        for range in linked_ranges.iter() {
 4452            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4453            let end_offset = start_offset + end_difference;
 4454            let start_offset = start_offset + start_difference;
 4455            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4456                continue;
 4457            }
 4458            if self.selections.disjoint_anchor_ranges().any(|s| {
 4459                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4460                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4461                {
 4462                    return false;
 4463                }
 4464                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4465                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4466            }) {
 4467                continue;
 4468            }
 4469            let start = buffer_snapshot.anchor_after(start_offset);
 4470            let end = buffer_snapshot.anchor_after(end_offset);
 4471            linked_edits
 4472                .entry(buffer.clone())
 4473                .or_default()
 4474                .push(start..end);
 4475        }
 4476        Some(linked_edits)
 4477    }
 4478
 4479    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4480        let text: Arc<str> = text.into();
 4481
 4482        if self.read_only(cx) {
 4483            return;
 4484        }
 4485
 4486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4487
 4488        self.unfold_buffers_with_selections(cx);
 4489
 4490        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4491        let mut bracket_inserted = false;
 4492        let mut edits = Vec::new();
 4493        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4494        let mut new_selections = Vec::with_capacity(selections.len());
 4495        let mut new_autoclose_regions = Vec::new();
 4496        let snapshot = self.buffer.read(cx).read(cx);
 4497        let mut clear_linked_edit_ranges = false;
 4498        let mut all_selections_read_only = true;
 4499        let mut has_adjacent_edits = false;
 4500        let mut in_adjacent_group = false;
 4501
 4502        let mut regions = self
 4503            .selections_with_autoclose_regions(selections, &snapshot)
 4504            .peekable();
 4505
 4506        while let Some((selection, autoclose_region)) = regions.next() {
 4507            if snapshot
 4508                .point_to_buffer_point(selection.head())
 4509                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4510            {
 4511                continue;
 4512            }
 4513            if snapshot
 4514                .point_to_buffer_point(selection.tail())
 4515                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4516            {
 4517                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4518                continue;
 4519            }
 4520            all_selections_read_only = false;
 4521
 4522            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4523                // Determine if the inserted text matches the opening or closing
 4524                // bracket of any of this language's bracket pairs.
 4525                let mut bracket_pair = None;
 4526                let mut is_bracket_pair_start = false;
 4527                let mut is_bracket_pair_end = false;
 4528                if !text.is_empty() {
 4529                    let mut bracket_pair_matching_end = None;
 4530                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4531                    //  and they are removing the character that triggered IME popup.
 4532                    for (pair, enabled) in scope.brackets() {
 4533                        if !pair.close && !pair.surround {
 4534                            continue;
 4535                        }
 4536
 4537                        if enabled && pair.start.ends_with(text.as_ref()) {
 4538                            let prefix_len = pair.start.len() - text.len();
 4539                            let preceding_text_matches_prefix = prefix_len == 0
 4540                                || (selection.start.column >= (prefix_len as u32)
 4541                                    && snapshot.contains_str_at(
 4542                                        Point::new(
 4543                                            selection.start.row,
 4544                                            selection.start.column - (prefix_len as u32),
 4545                                        ),
 4546                                        &pair.start[..prefix_len],
 4547                                    ));
 4548                            if preceding_text_matches_prefix {
 4549                                bracket_pair = Some(pair.clone());
 4550                                is_bracket_pair_start = true;
 4551                                break;
 4552                            }
 4553                        }
 4554                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4555                        {
 4556                            // take first bracket pair matching end, but don't break in case a later bracket
 4557                            // pair matches start
 4558                            bracket_pair_matching_end = Some(pair.clone());
 4559                        }
 4560                    }
 4561                    if let Some(end) = bracket_pair_matching_end
 4562                        && bracket_pair.is_none()
 4563                    {
 4564                        bracket_pair = Some(end);
 4565                        is_bracket_pair_end = true;
 4566                    }
 4567                }
 4568
 4569                if let Some(bracket_pair) = bracket_pair {
 4570                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4571                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4572                    let auto_surround =
 4573                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4574                    if selection.is_empty() {
 4575                        if is_bracket_pair_start {
 4576                            // If the inserted text is a suffix of an opening bracket and the
 4577                            // selection is preceded by the rest of the opening bracket, then
 4578                            // insert the closing bracket.
 4579                            let following_text_allows_autoclose = snapshot
 4580                                .chars_at(selection.start)
 4581                                .next()
 4582                                .is_none_or(|c| scope.should_autoclose_before(c));
 4583
 4584                            let preceding_text_allows_autoclose = selection.start.column == 0
 4585                                || snapshot
 4586                                    .reversed_chars_at(selection.start)
 4587                                    .next()
 4588                                    .is_none_or(|c| {
 4589                                        bracket_pair.start != bracket_pair.end
 4590                                            || !snapshot
 4591                                                .char_classifier_at(selection.start)
 4592                                                .is_word(c)
 4593                                    });
 4594
 4595                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4596                                && bracket_pair.start.len() == 1
 4597                            {
 4598                                let target = bracket_pair.start.chars().next().unwrap();
 4599                                let mut byte_offset = 0u32;
 4600                                let current_line_count = snapshot
 4601                                    .reversed_chars_at(selection.start)
 4602                                    .take_while(|&c| c != '\n')
 4603                                    .filter(|c| {
 4604                                        byte_offset += c.len_utf8() as u32;
 4605                                        if *c != target {
 4606                                            return false;
 4607                                        }
 4608
 4609                                        let point = Point::new(
 4610                                            selection.start.row,
 4611                                            selection.start.column.saturating_sub(byte_offset),
 4612                                        );
 4613
 4614                                        let is_enabled = snapshot
 4615                                            .language_scope_at(point)
 4616                                            .and_then(|scope| {
 4617                                                scope
 4618                                                    .brackets()
 4619                                                    .find(|(pair, _)| {
 4620                                                        pair.start == bracket_pair.start
 4621                                                    })
 4622                                                    .map(|(_, enabled)| enabled)
 4623                                            })
 4624                                            .unwrap_or(true);
 4625
 4626                                        let is_delimiter = snapshot
 4627                                            .language_scope_at(Point::new(
 4628                                                point.row,
 4629                                                point.column + 1,
 4630                                            ))
 4631                                            .and_then(|scope| {
 4632                                                scope
 4633                                                    .brackets()
 4634                                                    .find(|(pair, _)| {
 4635                                                        pair.start == bracket_pair.start
 4636                                                    })
 4637                                                    .map(|(_, enabled)| !enabled)
 4638                                            })
 4639                                            .unwrap_or(false);
 4640
 4641                                        is_enabled && !is_delimiter
 4642                                    })
 4643                                    .count();
 4644                                current_line_count % 2 == 1
 4645                            } else {
 4646                                false
 4647                            };
 4648
 4649                            if autoclose
 4650                                && bracket_pair.close
 4651                                && following_text_allows_autoclose
 4652                                && preceding_text_allows_autoclose
 4653                                && !is_closing_quote
 4654                            {
 4655                                let anchor = snapshot.anchor_before(selection.end);
 4656                                new_selections.push((selection.map(|_| anchor), text.len()));
 4657                                new_autoclose_regions.push((
 4658                                    anchor,
 4659                                    text.len(),
 4660                                    selection.id,
 4661                                    bracket_pair.clone(),
 4662                                ));
 4663                                edits.push((
 4664                                    selection.range(),
 4665                                    format!("{}{}", text, bracket_pair.end).into(),
 4666                                ));
 4667                                bracket_inserted = true;
 4668                                continue;
 4669                            }
 4670                        }
 4671
 4672                        if let Some(region) = autoclose_region {
 4673                            // If the selection is followed by an auto-inserted closing bracket,
 4674                            // then don't insert that closing bracket again; just move the selection
 4675                            // past the closing bracket.
 4676                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4677                                && text.as_ref() == region.pair.end.as_str()
 4678                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4679                            if should_skip {
 4680                                let anchor = snapshot.anchor_after(selection.end);
 4681                                new_selections
 4682                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4683                                continue;
 4684                            }
 4685                        }
 4686
 4687                        let always_treat_brackets_as_autoclosed = snapshot
 4688                            .language_settings_at(selection.start, cx)
 4689                            .always_treat_brackets_as_autoclosed;
 4690                        if always_treat_brackets_as_autoclosed
 4691                            && is_bracket_pair_end
 4692                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4693                        {
 4694                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4695                            // and the inserted text is a closing bracket and the selection is followed
 4696                            // by the closing bracket then move the selection past the closing bracket.
 4697                            let anchor = snapshot.anchor_after(selection.end);
 4698                            new_selections.push((selection.map(|_| anchor), text.len()));
 4699                            continue;
 4700                        }
 4701                    }
 4702                    // If an opening bracket is 1 character long and is typed while
 4703                    // text is selected, then surround that text with the bracket pair.
 4704                    else if auto_surround
 4705                        && bracket_pair.surround
 4706                        && is_bracket_pair_start
 4707                        && bracket_pair.start.chars().count() == 1
 4708                    {
 4709                        edits.push((selection.start..selection.start, text.clone()));
 4710                        edits.push((
 4711                            selection.end..selection.end,
 4712                            bracket_pair.end.as_str().into(),
 4713                        ));
 4714                        bracket_inserted = true;
 4715                        new_selections.push((
 4716                            Selection {
 4717                                id: selection.id,
 4718                                start: snapshot.anchor_after(selection.start),
 4719                                end: snapshot.anchor_before(selection.end),
 4720                                reversed: selection.reversed,
 4721                                goal: selection.goal,
 4722                            },
 4723                            0,
 4724                        ));
 4725                        continue;
 4726                    }
 4727                }
 4728            }
 4729
 4730            if self.auto_replace_emoji_shortcode
 4731                && selection.is_empty()
 4732                && text.as_ref().ends_with(':')
 4733                && let Some(possible_emoji_short_code) =
 4734                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4735                && !possible_emoji_short_code.is_empty()
 4736                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4737            {
 4738                let emoji_shortcode_start = Point::new(
 4739                    selection.start.row,
 4740                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4741                );
 4742
 4743                // Remove shortcode from buffer
 4744                edits.push((
 4745                    emoji_shortcode_start..selection.start,
 4746                    "".to_string().into(),
 4747                ));
 4748                new_selections.push((
 4749                    Selection {
 4750                        id: selection.id,
 4751                        start: snapshot.anchor_after(emoji_shortcode_start),
 4752                        end: snapshot.anchor_before(selection.start),
 4753                        reversed: selection.reversed,
 4754                        goal: selection.goal,
 4755                    },
 4756                    0,
 4757                ));
 4758
 4759                // Insert emoji
 4760                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4761                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4762                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4763
 4764                continue;
 4765            }
 4766
 4767            let next_is_adjacent = regions
 4768                .peek()
 4769                .is_some_and(|(next, _)| selection.end == next.start);
 4770
 4771            // If not handling any auto-close operation, then just replace the selected
 4772            // text with the given input and move the selection to the end of the
 4773            // newly inserted text.
 4774            let anchor = if in_adjacent_group || next_is_adjacent {
 4775                // After edits the right bias would shift those anchor to the next visible fragment
 4776                // but we want to resolve to the previous one
 4777                snapshot.anchor_before(selection.end)
 4778            } else {
 4779                snapshot.anchor_after(selection.end)
 4780            };
 4781
 4782            if !self.linked_edit_ranges.is_empty() {
 4783                let start_anchor = snapshot.anchor_before(selection.start);
 4784
 4785                let is_word_char = text.chars().next().is_none_or(|char| {
 4786                    let classifier = snapshot
 4787                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4788                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4789                    classifier.is_word(char)
 4790                });
 4791
 4792                if is_word_char {
 4793                    if let Some(ranges) = self
 4794                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4795                    {
 4796                        for (buffer, edits) in ranges {
 4797                            linked_edits
 4798                                .entry(buffer.clone())
 4799                                .or_default()
 4800                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4801                        }
 4802                    }
 4803                } else {
 4804                    clear_linked_edit_ranges = true;
 4805                }
 4806            }
 4807
 4808            new_selections.push((selection.map(|_| anchor), 0));
 4809            edits.push((selection.start..selection.end, text.clone()));
 4810
 4811            has_adjacent_edits |= next_is_adjacent;
 4812            in_adjacent_group = next_is_adjacent;
 4813        }
 4814
 4815        if all_selections_read_only {
 4816            return;
 4817        }
 4818
 4819        drop(regions);
 4820        drop(snapshot);
 4821
 4822        self.transact(window, cx, |this, window, cx| {
 4823            if clear_linked_edit_ranges {
 4824                this.linked_edit_ranges.clear();
 4825            }
 4826            let initial_buffer_versions =
 4827                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4828
 4829            this.buffer.update(cx, |buffer, cx| {
 4830                if has_adjacent_edits {
 4831                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4832                } else {
 4833                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4834                }
 4835            });
 4836            for (buffer, edits) in linked_edits {
 4837                buffer.update(cx, |buffer, cx| {
 4838                    let snapshot = buffer.snapshot();
 4839                    let edits = edits
 4840                        .into_iter()
 4841                        .map(|(range, text)| {
 4842                            use text::ToPoint as TP;
 4843                            let end_point = TP::to_point(&range.end, &snapshot);
 4844                            let start_point = TP::to_point(&range.start, &snapshot);
 4845                            (start_point..end_point, text)
 4846                        })
 4847                        .sorted_by_key(|(range, _)| range.start);
 4848                    buffer.edit(edits, None, cx);
 4849                })
 4850            }
 4851            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4852            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4853            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4854            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4855                new_anchor_selections,
 4856                &map,
 4857            )
 4858            .zip(new_selection_deltas)
 4859            .map(|(selection, delta)| Selection {
 4860                id: selection.id,
 4861                start: selection.start + delta,
 4862                end: selection.end + delta,
 4863                reversed: selection.reversed,
 4864                goal: SelectionGoal::None,
 4865            })
 4866            .collect::<Vec<_>>();
 4867
 4868            let mut i = 0;
 4869            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4870                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4871                let start = map.buffer_snapshot().anchor_before(position);
 4872                let end = map.buffer_snapshot().anchor_after(position);
 4873                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4874                    match existing_state
 4875                        .range
 4876                        .start
 4877                        .cmp(&start, map.buffer_snapshot())
 4878                    {
 4879                        Ordering::Less => i += 1,
 4880                        Ordering::Greater => break,
 4881                        Ordering::Equal => {
 4882                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4883                                Ordering::Less => i += 1,
 4884                                Ordering::Equal => break,
 4885                                Ordering::Greater => break,
 4886                            }
 4887                        }
 4888                    }
 4889                }
 4890                this.autoclose_regions.insert(
 4891                    i,
 4892                    AutocloseRegion {
 4893                        selection_id,
 4894                        range: start..end,
 4895                        pair,
 4896                    },
 4897                );
 4898            }
 4899
 4900            let had_active_edit_prediction = this.has_active_edit_prediction();
 4901            this.change_selections(
 4902                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4903                window,
 4904                cx,
 4905                |s| s.select(new_selections),
 4906            );
 4907
 4908            if !bracket_inserted
 4909                && let Some(on_type_format_task) =
 4910                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4911            {
 4912                on_type_format_task.detach_and_log_err(cx);
 4913            }
 4914
 4915            let editor_settings = EditorSettings::get_global(cx);
 4916            if bracket_inserted
 4917                && (editor_settings.auto_signature_help
 4918                    || editor_settings.show_signature_help_after_edits)
 4919            {
 4920                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4921            }
 4922
 4923            let trigger_in_words =
 4924                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4925            if this.hard_wrap.is_some() {
 4926                let latest: Range<Point> = this.selections.newest(&map).range();
 4927                if latest.is_empty()
 4928                    && this
 4929                        .buffer()
 4930                        .read(cx)
 4931                        .snapshot(cx)
 4932                        .line_len(MultiBufferRow(latest.start.row))
 4933                        == latest.start.column
 4934                {
 4935                    this.rewrap_impl(
 4936                        RewrapOptions {
 4937                            override_language_settings: true,
 4938                            preserve_existing_whitespace: true,
 4939                        },
 4940                        cx,
 4941                    )
 4942                }
 4943            }
 4944            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4945            refresh_linked_ranges(this, window, cx);
 4946            this.refresh_edit_prediction(true, false, window, cx);
 4947            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4948        });
 4949    }
 4950
 4951    fn find_possible_emoji_shortcode_at_position(
 4952        snapshot: &MultiBufferSnapshot,
 4953        position: Point,
 4954    ) -> Option<String> {
 4955        let mut chars = Vec::new();
 4956        let mut found_colon = false;
 4957        for char in snapshot.reversed_chars_at(position).take(100) {
 4958            // Found a possible emoji shortcode in the middle of the buffer
 4959            if found_colon {
 4960                if char.is_whitespace() {
 4961                    chars.reverse();
 4962                    return Some(chars.iter().collect());
 4963                }
 4964                // If the previous character is not a whitespace, we are in the middle of a word
 4965                // and we only want to complete the shortcode if the word is made up of other emojis
 4966                let mut containing_word = String::new();
 4967                for ch in snapshot
 4968                    .reversed_chars_at(position)
 4969                    .skip(chars.len() + 1)
 4970                    .take(100)
 4971                {
 4972                    if ch.is_whitespace() {
 4973                        break;
 4974                    }
 4975                    containing_word.push(ch);
 4976                }
 4977                let containing_word = containing_word.chars().rev().collect::<String>();
 4978                if util::word_consists_of_emojis(containing_word.as_str()) {
 4979                    chars.reverse();
 4980                    return Some(chars.iter().collect());
 4981                }
 4982            }
 4983
 4984            if char.is_whitespace() || !char.is_ascii() {
 4985                return None;
 4986            }
 4987            if char == ':' {
 4988                found_colon = true;
 4989            } else {
 4990                chars.push(char);
 4991            }
 4992        }
 4993        // Found a possible emoji shortcode at the beginning of the buffer
 4994        chars.reverse();
 4995        Some(chars.iter().collect())
 4996    }
 4997
 4998    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5000        self.transact(window, cx, |this, window, cx| {
 5001            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5002                let selections = this
 5003                    .selections
 5004                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5005                let multi_buffer = this.buffer.read(cx);
 5006                let buffer = multi_buffer.snapshot(cx);
 5007                selections
 5008                    .iter()
 5009                    .map(|selection| {
 5010                        let start_point = selection.start.to_point(&buffer);
 5011                        let mut existing_indent =
 5012                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5013                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5014                        let start = selection.start;
 5015                        let end = selection.end;
 5016                        let selection_is_empty = start == end;
 5017                        let language_scope = buffer.language_scope_at(start);
 5018                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5019                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5020                                &buffer,
 5021                                start..end,
 5022                                language,
 5023                            )
 5024                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5025                                    &buffer,
 5026                                    start..end,
 5027                                );
 5028
 5029                            let mut newline_config = NewlineConfig::Newline {
 5030                                additional_indent: IndentSize::spaces(0),
 5031                                extra_line_additional_indent: if needs_extra_newline {
 5032                                    Some(IndentSize::spaces(0))
 5033                                } else {
 5034                                    None
 5035                                },
 5036                                prevent_auto_indent: false,
 5037                            };
 5038
 5039                            let comment_delimiter = maybe!({
 5040                                if !selection_is_empty {
 5041                                    return None;
 5042                                }
 5043
 5044                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5045                                    return None;
 5046                                }
 5047
 5048                                return comment_delimiter_for_newline(
 5049                                    &start_point,
 5050                                    &buffer,
 5051                                    language,
 5052                                );
 5053                            });
 5054
 5055                            let doc_delimiter = maybe!({
 5056                                if !selection_is_empty {
 5057                                    return None;
 5058                                }
 5059
 5060                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5061                                    return None;
 5062                                }
 5063
 5064                                return documentation_delimiter_for_newline(
 5065                                    &start_point,
 5066                                    &buffer,
 5067                                    language,
 5068                                    &mut newline_config,
 5069                                );
 5070                            });
 5071
 5072                            let list_delimiter = maybe!({
 5073                                if !selection_is_empty {
 5074                                    return None;
 5075                                }
 5076
 5077                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5078                                    return None;
 5079                                }
 5080
 5081                                return list_delimiter_for_newline(
 5082                                    &start_point,
 5083                                    &buffer,
 5084                                    language,
 5085                                    &mut newline_config,
 5086                                );
 5087                            });
 5088
 5089                            (
 5090                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5091                                newline_config,
 5092                            )
 5093                        } else {
 5094                            (
 5095                                None,
 5096                                NewlineConfig::Newline {
 5097                                    additional_indent: IndentSize::spaces(0),
 5098                                    extra_line_additional_indent: None,
 5099                                    prevent_auto_indent: false,
 5100                                },
 5101                            )
 5102                        };
 5103
 5104                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5105                            NewlineConfig::ClearCurrentLine => {
 5106                                let row_start =
 5107                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5108                                (row_start, String::new(), false)
 5109                            }
 5110                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5111                                let row_start =
 5112                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5113                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5114                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5115                                let reduced_indent =
 5116                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5117                                let mut new_text = String::new();
 5118                                new_text.extend(reduced_indent.chars());
 5119                                new_text.push_str(continuation);
 5120                                (row_start, new_text, true)
 5121                            }
 5122                            NewlineConfig::Newline {
 5123                                additional_indent,
 5124                                extra_line_additional_indent,
 5125                                prevent_auto_indent,
 5126                            } => {
 5127                                let capacity_for_delimiter =
 5128                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5129                                let extra_line_len = extra_line_additional_indent
 5130                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 5131                                    .unwrap_or(0);
 5132                                let mut new_text = String::with_capacity(
 5133                                    1 + capacity_for_delimiter
 5134                                        + existing_indent.len as usize
 5135                                        + additional_indent.len as usize
 5136                                        + extra_line_len,
 5137                                );
 5138                                new_text.push('\n');
 5139                                new_text.extend(existing_indent.chars());
 5140                                new_text.extend(additional_indent.chars());
 5141                                if let Some(delimiter) = &delimiter {
 5142                                    new_text.push_str(delimiter);
 5143                                }
 5144                                if let Some(extra_indent) = extra_line_additional_indent {
 5145                                    new_text.push('\n');
 5146                                    new_text.extend(existing_indent.chars());
 5147                                    new_text.extend(extra_indent.chars());
 5148                                }
 5149                                (start, new_text, *prevent_auto_indent)
 5150                            }
 5151                        };
 5152
 5153                        let anchor = buffer.anchor_after(end);
 5154                        let new_selection = selection.map(|_| anchor);
 5155                        (
 5156                            ((edit_start..end, new_text), prevent_auto_indent),
 5157                            (newline_config.has_extra_line(), new_selection),
 5158                        )
 5159                    })
 5160                    .unzip()
 5161            };
 5162
 5163            let mut auto_indent_edits = Vec::new();
 5164            let mut edits = Vec::new();
 5165            for (edit, prevent_auto_indent) in edits_with_flags {
 5166                if prevent_auto_indent {
 5167                    edits.push(edit);
 5168                } else {
 5169                    auto_indent_edits.push(edit);
 5170                }
 5171            }
 5172            if !edits.is_empty() {
 5173                this.edit(edits, cx);
 5174            }
 5175            if !auto_indent_edits.is_empty() {
 5176                this.edit_with_autoindent(auto_indent_edits, cx);
 5177            }
 5178
 5179            let buffer = this.buffer.read(cx).snapshot(cx);
 5180            let new_selections = selection_info
 5181                .into_iter()
 5182                .map(|(extra_newline_inserted, new_selection)| {
 5183                    let mut cursor = new_selection.end.to_point(&buffer);
 5184                    if extra_newline_inserted {
 5185                        cursor.row -= 1;
 5186                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5187                    }
 5188                    new_selection.map(|_| cursor)
 5189                })
 5190                .collect();
 5191
 5192            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5193            this.refresh_edit_prediction(true, false, window, cx);
 5194            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5195                task.detach_and_log_err(cx);
 5196            }
 5197        });
 5198    }
 5199
 5200    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5202
 5203        let buffer = self.buffer.read(cx);
 5204        let snapshot = buffer.snapshot(cx);
 5205
 5206        let mut edits = Vec::new();
 5207        let mut rows = Vec::new();
 5208
 5209        for (rows_inserted, selection) in self
 5210            .selections
 5211            .all_adjusted(&self.display_snapshot(cx))
 5212            .into_iter()
 5213            .enumerate()
 5214        {
 5215            let cursor = selection.head();
 5216            let row = cursor.row;
 5217
 5218            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5219
 5220            let newline = "\n".to_string();
 5221            edits.push((start_of_line..start_of_line, newline));
 5222
 5223            rows.push(row + rows_inserted as u32);
 5224        }
 5225
 5226        self.transact(window, cx, |editor, window, cx| {
 5227            editor.edit(edits, cx);
 5228
 5229            editor.change_selections(Default::default(), window, cx, |s| {
 5230                let mut index = 0;
 5231                s.move_cursors_with(|map, _, _| {
 5232                    let row = rows[index];
 5233                    index += 1;
 5234
 5235                    let point = Point::new(row, 0);
 5236                    let boundary = map.next_line_boundary(point).1;
 5237                    let clipped = map.clip_point(boundary, Bias::Left);
 5238
 5239                    (clipped, SelectionGoal::None)
 5240                });
 5241            });
 5242
 5243            let mut indent_edits = Vec::new();
 5244            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5245            for row in rows {
 5246                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5247                for (row, indent) in indents {
 5248                    if indent.len == 0 {
 5249                        continue;
 5250                    }
 5251
 5252                    let text = match indent.kind {
 5253                        IndentKind::Space => " ".repeat(indent.len as usize),
 5254                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5255                    };
 5256                    let point = Point::new(row.0, 0);
 5257                    indent_edits.push((point..point, text));
 5258                }
 5259            }
 5260            editor.edit(indent_edits, cx);
 5261            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5262                format.detach_and_log_err(cx);
 5263            }
 5264        });
 5265    }
 5266
 5267    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5268        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5269
 5270        let buffer = self.buffer.read(cx);
 5271        let snapshot = buffer.snapshot(cx);
 5272
 5273        let mut edits = Vec::new();
 5274        let mut rows = Vec::new();
 5275        let mut rows_inserted = 0;
 5276
 5277        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5278            let cursor = selection.head();
 5279            let row = cursor.row;
 5280
 5281            let point = Point::new(row + 1, 0);
 5282            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5283
 5284            let newline = "\n".to_string();
 5285            edits.push((start_of_line..start_of_line, newline));
 5286
 5287            rows_inserted += 1;
 5288            rows.push(row + rows_inserted);
 5289        }
 5290
 5291        self.transact(window, cx, |editor, window, cx| {
 5292            editor.edit(edits, cx);
 5293
 5294            editor.change_selections(Default::default(), window, cx, |s| {
 5295                let mut index = 0;
 5296                s.move_cursors_with(|map, _, _| {
 5297                    let row = rows[index];
 5298                    index += 1;
 5299
 5300                    let point = Point::new(row, 0);
 5301                    let boundary = map.next_line_boundary(point).1;
 5302                    let clipped = map.clip_point(boundary, Bias::Left);
 5303
 5304                    (clipped, SelectionGoal::None)
 5305                });
 5306            });
 5307
 5308            let mut indent_edits = Vec::new();
 5309            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5310            for row in rows {
 5311                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5312                for (row, indent) in indents {
 5313                    if indent.len == 0 {
 5314                        continue;
 5315                    }
 5316
 5317                    let text = match indent.kind {
 5318                        IndentKind::Space => " ".repeat(indent.len as usize),
 5319                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5320                    };
 5321                    let point = Point::new(row.0, 0);
 5322                    indent_edits.push((point..point, text));
 5323                }
 5324            }
 5325            editor.edit(indent_edits, cx);
 5326            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5327                format.detach_and_log_err(cx);
 5328            }
 5329        });
 5330    }
 5331
 5332    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5333        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5334            original_indent_columns: Vec::new(),
 5335        });
 5336        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5337    }
 5338
 5339    fn insert_with_autoindent_mode(
 5340        &mut self,
 5341        text: &str,
 5342        autoindent_mode: Option<AutoindentMode>,
 5343        window: &mut Window,
 5344        cx: &mut Context<Self>,
 5345    ) {
 5346        if self.read_only(cx) {
 5347            return;
 5348        }
 5349
 5350        let text: Arc<str> = text.into();
 5351        self.transact(window, cx, |this, window, cx| {
 5352            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5353            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5354                let anchors = {
 5355                    let snapshot = buffer.read(cx);
 5356                    old_selections
 5357                        .iter()
 5358                        .map(|s| {
 5359                            let anchor = snapshot.anchor_after(s.head());
 5360                            s.map(|_| anchor)
 5361                        })
 5362                        .collect::<Vec<_>>()
 5363                };
 5364                buffer.edit(
 5365                    old_selections
 5366                        .iter()
 5367                        .map(|s| (s.start..s.end, text.clone())),
 5368                    autoindent_mode,
 5369                    cx,
 5370                );
 5371                anchors
 5372            });
 5373
 5374            this.change_selections(Default::default(), window, cx, |s| {
 5375                s.select_anchors(selection_anchors);
 5376            });
 5377
 5378            cx.notify();
 5379        });
 5380    }
 5381
 5382    fn trigger_completion_on_input(
 5383        &mut self,
 5384        text: &str,
 5385        trigger_in_words: bool,
 5386        window: &mut Window,
 5387        cx: &mut Context<Self>,
 5388    ) {
 5389        let completions_source = self
 5390            .context_menu
 5391            .borrow()
 5392            .as_ref()
 5393            .and_then(|menu| match menu {
 5394                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5395                CodeContextMenu::CodeActions(_) => None,
 5396            });
 5397
 5398        match completions_source {
 5399            Some(CompletionsMenuSource::Words { .. }) => {
 5400                self.open_or_update_completions_menu(
 5401                    Some(CompletionsMenuSource::Words {
 5402                        ignore_threshold: false,
 5403                    }),
 5404                    None,
 5405                    trigger_in_words,
 5406                    window,
 5407                    cx,
 5408                );
 5409            }
 5410            _ => self.open_or_update_completions_menu(
 5411                None,
 5412                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5413                true,
 5414                window,
 5415                cx,
 5416            ),
 5417        }
 5418    }
 5419
 5420    /// If any empty selections is touching the start of its innermost containing autoclose
 5421    /// region, expand it to select the brackets.
 5422    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5423        let selections = self
 5424            .selections
 5425            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5426        let buffer = self.buffer.read(cx).read(cx);
 5427        let new_selections = self
 5428            .selections_with_autoclose_regions(selections, &buffer)
 5429            .map(|(mut selection, region)| {
 5430                if !selection.is_empty() {
 5431                    return selection;
 5432                }
 5433
 5434                if let Some(region) = region {
 5435                    let mut range = region.range.to_offset(&buffer);
 5436                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5437                        range.start -= region.pair.start.len();
 5438                        if buffer.contains_str_at(range.start, &region.pair.start)
 5439                            && buffer.contains_str_at(range.end, &region.pair.end)
 5440                        {
 5441                            range.end += region.pair.end.len();
 5442                            selection.start = range.start;
 5443                            selection.end = range.end;
 5444
 5445                            return selection;
 5446                        }
 5447                    }
 5448                }
 5449
 5450                let always_treat_brackets_as_autoclosed = buffer
 5451                    .language_settings_at(selection.start, cx)
 5452                    .always_treat_brackets_as_autoclosed;
 5453
 5454                if !always_treat_brackets_as_autoclosed {
 5455                    return selection;
 5456                }
 5457
 5458                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5459                    for (pair, enabled) in scope.brackets() {
 5460                        if !enabled || !pair.close {
 5461                            continue;
 5462                        }
 5463
 5464                        if buffer.contains_str_at(selection.start, &pair.end) {
 5465                            let pair_start_len = pair.start.len();
 5466                            if buffer.contains_str_at(
 5467                                selection.start.saturating_sub_usize(pair_start_len),
 5468                                &pair.start,
 5469                            ) {
 5470                                selection.start -= pair_start_len;
 5471                                selection.end += pair.end.len();
 5472
 5473                                return selection;
 5474                            }
 5475                        }
 5476                    }
 5477                }
 5478
 5479                selection
 5480            })
 5481            .collect();
 5482
 5483        drop(buffer);
 5484        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5485            selections.select(new_selections)
 5486        });
 5487    }
 5488
 5489    /// Iterate the given selections, and for each one, find the smallest surrounding
 5490    /// autoclose region. This uses the ordering of the selections and the autoclose
 5491    /// regions to avoid repeated comparisons.
 5492    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5493        &'a self,
 5494        selections: impl IntoIterator<Item = Selection<D>>,
 5495        buffer: &'a MultiBufferSnapshot,
 5496    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5497        let mut i = 0;
 5498        let mut regions = self.autoclose_regions.as_slice();
 5499        selections.into_iter().map(move |selection| {
 5500            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5501
 5502            let mut enclosing = None;
 5503            while let Some(pair_state) = regions.get(i) {
 5504                if pair_state.range.end.to_offset(buffer) < range.start {
 5505                    regions = &regions[i + 1..];
 5506                    i = 0;
 5507                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5508                    break;
 5509                } else {
 5510                    if pair_state.selection_id == selection.id {
 5511                        enclosing = Some(pair_state);
 5512                    }
 5513                    i += 1;
 5514                }
 5515            }
 5516
 5517            (selection, enclosing)
 5518        })
 5519    }
 5520
 5521    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5522    fn invalidate_autoclose_regions(
 5523        &mut self,
 5524        mut selections: &[Selection<Anchor>],
 5525        buffer: &MultiBufferSnapshot,
 5526    ) {
 5527        self.autoclose_regions.retain(|state| {
 5528            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5529                return false;
 5530            }
 5531
 5532            let mut i = 0;
 5533            while let Some(selection) = selections.get(i) {
 5534                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5535                    selections = &selections[1..];
 5536                    continue;
 5537                }
 5538                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5539                    break;
 5540                }
 5541                if selection.id == state.selection_id {
 5542                    return true;
 5543                } else {
 5544                    i += 1;
 5545                }
 5546            }
 5547            false
 5548        });
 5549    }
 5550
 5551    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5552        let offset = position.to_offset(buffer);
 5553        let (word_range, kind) =
 5554            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5555        if offset > word_range.start && kind == Some(CharKind::Word) {
 5556            Some(
 5557                buffer
 5558                    .text_for_range(word_range.start..offset)
 5559                    .collect::<String>(),
 5560            )
 5561        } else {
 5562            None
 5563        }
 5564    }
 5565
 5566    pub fn visible_excerpts(
 5567        &self,
 5568        lsp_related_only: bool,
 5569        cx: &mut Context<Editor>,
 5570    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5571        let project = self.project().cloned();
 5572        let multi_buffer = self.buffer().read(cx);
 5573        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5574        let multi_buffer_visible_start = self
 5575            .scroll_manager
 5576            .anchor()
 5577            .anchor
 5578            .to_point(&multi_buffer_snapshot);
 5579        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5580            multi_buffer_visible_start
 5581                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5582            Bias::Left,
 5583        );
 5584        multi_buffer_snapshot
 5585            .range_to_buffer_ranges(multi_buffer_visible_start..=multi_buffer_visible_end)
 5586            .into_iter()
 5587            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5588            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5589                if !lsp_related_only {
 5590                    return Some((
 5591                        excerpt_id,
 5592                        (
 5593                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5594                            buffer.version().clone(),
 5595                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5596                        ),
 5597                    ));
 5598                }
 5599
 5600                let project = project.as_ref()?.read(cx);
 5601                let buffer_file = project::File::from_dyn(buffer.file())?;
 5602                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5603                let worktree_entry = buffer_worktree
 5604                    .read(cx)
 5605                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5606                if worktree_entry.is_ignored {
 5607                    None
 5608                } else {
 5609                    Some((
 5610                        excerpt_id,
 5611                        (
 5612                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5613                            buffer.version().clone(),
 5614                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5615                        ),
 5616                    ))
 5617                }
 5618            })
 5619            .collect()
 5620    }
 5621
 5622    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5623        TextLayoutDetails {
 5624            text_system: window.text_system().clone(),
 5625            editor_style: self.style.clone().unwrap(),
 5626            rem_size: window.rem_size(),
 5627            scroll_anchor: self.scroll_manager.anchor(),
 5628            visible_rows: self.visible_line_count(),
 5629            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5630        }
 5631    }
 5632
 5633    fn trigger_on_type_formatting(
 5634        &self,
 5635        input: String,
 5636        window: &mut Window,
 5637        cx: &mut Context<Self>,
 5638    ) -> Option<Task<Result<()>>> {
 5639        if input.chars().count() != 1 {
 5640            return None;
 5641        }
 5642
 5643        let project = self.project()?;
 5644        let position = self.selections.newest_anchor().head();
 5645        let (buffer, buffer_position) = self
 5646            .buffer
 5647            .read(cx)
 5648            .text_anchor_for_position(position, cx)?;
 5649
 5650        let settings = language_settings::language_settings(
 5651            buffer
 5652                .read(cx)
 5653                .language_at(buffer_position)
 5654                .map(|l| l.name()),
 5655            buffer.read(cx).file(),
 5656            cx,
 5657        );
 5658        if !settings.use_on_type_format {
 5659            return None;
 5660        }
 5661
 5662        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5663        // hence we do LSP request & edit on host side only — add formats to host's history.
 5664        let push_to_lsp_host_history = true;
 5665        // If this is not the host, append its history with new edits.
 5666        let push_to_client_history = project.read(cx).is_via_collab();
 5667
 5668        let on_type_formatting = project.update(cx, |project, cx| {
 5669            project.on_type_format(
 5670                buffer.clone(),
 5671                buffer_position,
 5672                input,
 5673                push_to_lsp_host_history,
 5674                cx,
 5675            )
 5676        });
 5677        Some(cx.spawn_in(window, async move |editor, cx| {
 5678            if let Some(transaction) = on_type_formatting.await? {
 5679                if push_to_client_history {
 5680                    buffer.update(cx, |buffer, _| {
 5681                        buffer.push_transaction(transaction, Instant::now());
 5682                        buffer.finalize_last_transaction();
 5683                    });
 5684                }
 5685                editor.update(cx, |editor, cx| {
 5686                    editor.refresh_document_highlights(cx);
 5687                })?;
 5688            }
 5689            Ok(())
 5690        }))
 5691    }
 5692
 5693    pub fn show_word_completions(
 5694        &mut self,
 5695        _: &ShowWordCompletions,
 5696        window: &mut Window,
 5697        cx: &mut Context<Self>,
 5698    ) {
 5699        self.open_or_update_completions_menu(
 5700            Some(CompletionsMenuSource::Words {
 5701                ignore_threshold: true,
 5702            }),
 5703            None,
 5704            false,
 5705            window,
 5706            cx,
 5707        );
 5708    }
 5709
 5710    pub fn show_completions(
 5711        &mut self,
 5712        _: &ShowCompletions,
 5713        window: &mut Window,
 5714        cx: &mut Context<Self>,
 5715    ) {
 5716        self.open_or_update_completions_menu(None, None, false, window, cx);
 5717    }
 5718
 5719    fn open_or_update_completions_menu(
 5720        &mut self,
 5721        requested_source: Option<CompletionsMenuSource>,
 5722        trigger: Option<String>,
 5723        trigger_in_words: bool,
 5724        window: &mut Window,
 5725        cx: &mut Context<Self>,
 5726    ) {
 5727        if self.pending_rename.is_some() {
 5728            return;
 5729        }
 5730
 5731        let completions_source = self
 5732            .context_menu
 5733            .borrow()
 5734            .as_ref()
 5735            .and_then(|menu| match menu {
 5736                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5737                CodeContextMenu::CodeActions(_) => None,
 5738            });
 5739
 5740        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5741
 5742        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5743        // inserted and selected. To handle that case, the start of the selection is used so that
 5744        // the menu starts with all choices.
 5745        let position = self
 5746            .selections
 5747            .newest_anchor()
 5748            .start
 5749            .bias_right(&multibuffer_snapshot);
 5750        if position.diff_base_anchor.is_some() {
 5751            return;
 5752        }
 5753        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5754        let Some(buffer) = buffer_position
 5755            .text_anchor
 5756            .buffer_id
 5757            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5758        else {
 5759            return;
 5760        };
 5761        let buffer_snapshot = buffer.read(cx).snapshot();
 5762
 5763        let menu_is_open = matches!(
 5764            self.context_menu.borrow().as_ref(),
 5765            Some(CodeContextMenu::Completions(_))
 5766        );
 5767
 5768        let language = buffer_snapshot
 5769            .language_at(buffer_position.text_anchor)
 5770            .map(|language| language.name());
 5771
 5772        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5773        let completion_settings = language_settings.completions.clone();
 5774
 5775        let show_completions_on_input = self
 5776            .show_completions_on_input_override
 5777            .unwrap_or(language_settings.show_completions_on_input);
 5778        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5779            return;
 5780        }
 5781
 5782        let query: Option<Arc<String>> =
 5783            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5784                .map(|query| query.into());
 5785
 5786        drop(multibuffer_snapshot);
 5787
 5788        // Hide the current completions menu when query is empty. Without this, cached
 5789        // completions from before the trigger char may be reused (#32774).
 5790        if query.is_none() && menu_is_open {
 5791            self.hide_context_menu(window, cx);
 5792        }
 5793
 5794        let mut ignore_word_threshold = false;
 5795        let provider = match requested_source {
 5796            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5797            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5798                ignore_word_threshold = ignore_threshold;
 5799                None
 5800            }
 5801            Some(CompletionsMenuSource::SnippetChoices)
 5802            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5803                log::error!("bug: SnippetChoices requested_source is not handled");
 5804                None
 5805            }
 5806        };
 5807
 5808        let sort_completions = provider
 5809            .as_ref()
 5810            .is_some_and(|provider| provider.sort_completions());
 5811
 5812        let filter_completions = provider
 5813            .as_ref()
 5814            .is_none_or(|provider| provider.filter_completions());
 5815
 5816        let was_snippets_only = matches!(
 5817            completions_source,
 5818            Some(CompletionsMenuSource::SnippetsOnly)
 5819        );
 5820
 5821        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5822            if filter_completions {
 5823                menu.filter(
 5824                    query.clone().unwrap_or_default(),
 5825                    buffer_position.text_anchor,
 5826                    &buffer,
 5827                    provider.clone(),
 5828                    window,
 5829                    cx,
 5830                );
 5831            }
 5832            // When `is_incomplete` is false, no need to re-query completions when the current query
 5833            // is a suffix of the initial query.
 5834            let was_complete = !menu.is_incomplete;
 5835            if was_complete && !was_snippets_only {
 5836                // If the new query is a suffix of the old query (typing more characters) and
 5837                // the previous result was complete, the existing completions can be filtered.
 5838                //
 5839                // Note that snippet completions are always complete.
 5840                let query_matches = match (&menu.initial_query, &query) {
 5841                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5842                    (None, _) => true,
 5843                    _ => false,
 5844                };
 5845                if query_matches {
 5846                    let position_matches = if menu.initial_position == position {
 5847                        true
 5848                    } else {
 5849                        let snapshot = self.buffer.read(cx).read(cx);
 5850                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5851                    };
 5852                    if position_matches {
 5853                        return;
 5854                    }
 5855                }
 5856            }
 5857        };
 5858
 5859        let Anchor {
 5860            excerpt_id: buffer_excerpt_id,
 5861            text_anchor: buffer_position,
 5862            ..
 5863        } = buffer_position;
 5864
 5865        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5866            buffer_snapshot.surrounding_word(buffer_position, None)
 5867        {
 5868            let word_to_exclude = buffer_snapshot
 5869                .text_for_range(word_range.clone())
 5870                .collect::<String>();
 5871            (
 5872                buffer_snapshot.anchor_before(word_range.start)
 5873                    ..buffer_snapshot.anchor_after(buffer_position),
 5874                Some(word_to_exclude),
 5875            )
 5876        } else {
 5877            (buffer_position..buffer_position, None)
 5878        };
 5879
 5880        let show_completion_documentation = buffer_snapshot
 5881            .settings_at(buffer_position, cx)
 5882            .show_completion_documentation;
 5883
 5884        // The document can be large, so stay in reasonable bounds when searching for words,
 5885        // otherwise completion pop-up might be slow to appear.
 5886        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5887        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5888        let min_word_search = buffer_snapshot.clip_point(
 5889            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5890            Bias::Left,
 5891        );
 5892        let max_word_search = buffer_snapshot.clip_point(
 5893            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5894            Bias::Right,
 5895        );
 5896        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5897            ..buffer_snapshot.point_to_offset(max_word_search);
 5898
 5899        let skip_digits = query
 5900            .as_ref()
 5901            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5902
 5903        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5904            trigger.as_ref().is_none_or(|trigger| {
 5905                provider.is_completion_trigger(
 5906                    &buffer,
 5907                    position.text_anchor,
 5908                    trigger,
 5909                    trigger_in_words,
 5910                    cx,
 5911                )
 5912            })
 5913        });
 5914
 5915        let provider_responses = if let Some(provider) = &provider
 5916            && load_provider_completions
 5917        {
 5918            let trigger_character =
 5919                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5920            let completion_context = CompletionContext {
 5921                trigger_kind: match &trigger_character {
 5922                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5923                    None => CompletionTriggerKind::INVOKED,
 5924                },
 5925                trigger_character,
 5926            };
 5927
 5928            provider.completions(
 5929                buffer_excerpt_id,
 5930                &buffer,
 5931                buffer_position,
 5932                completion_context,
 5933                window,
 5934                cx,
 5935            )
 5936        } else {
 5937            Task::ready(Ok(Vec::new()))
 5938        };
 5939
 5940        let load_word_completions = if !self.word_completions_enabled {
 5941            false
 5942        } else if requested_source
 5943            == Some(CompletionsMenuSource::Words {
 5944                ignore_threshold: true,
 5945            })
 5946        {
 5947            true
 5948        } else {
 5949            load_provider_completions
 5950                && completion_settings.words != WordsCompletionMode::Disabled
 5951                && (ignore_word_threshold || {
 5952                    let words_min_length = completion_settings.words_min_length;
 5953                    // check whether word has at least `words_min_length` characters
 5954                    let query_chars = query.iter().flat_map(|q| q.chars());
 5955                    query_chars.take(words_min_length).count() == words_min_length
 5956                })
 5957        };
 5958
 5959        let mut words = if load_word_completions {
 5960            cx.background_spawn({
 5961                let buffer_snapshot = buffer_snapshot.clone();
 5962                async move {
 5963                    buffer_snapshot.words_in_range(WordsQuery {
 5964                        fuzzy_contents: None,
 5965                        range: word_search_range,
 5966                        skip_digits,
 5967                    })
 5968                }
 5969            })
 5970        } else {
 5971            Task::ready(BTreeMap::default())
 5972        };
 5973
 5974        let snippets = if let Some(provider) = &provider
 5975            && provider.show_snippets()
 5976            && let Some(project) = self.project()
 5977        {
 5978            let char_classifier = buffer_snapshot
 5979                .char_classifier_at(buffer_position)
 5980                .scope_context(Some(CharScopeContext::Completion));
 5981            project.update(cx, |project, cx| {
 5982                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5983            })
 5984        } else {
 5985            Task::ready(Ok(CompletionResponse {
 5986                completions: Vec::new(),
 5987                display_options: Default::default(),
 5988                is_incomplete: false,
 5989            }))
 5990        };
 5991
 5992        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5993
 5994        let id = post_inc(&mut self.next_completion_id);
 5995        let task = cx.spawn_in(window, async move |editor, cx| {
 5996            let Ok(()) = editor.update(cx, |this, _| {
 5997                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5998            }) else {
 5999                return;
 6000            };
 6001
 6002            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6003            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6004            let mut completions = Vec::new();
 6005            let mut is_incomplete = false;
 6006            let mut display_options: Option<CompletionDisplayOptions> = None;
 6007            if let Some(provider_responses) = provider_responses.await.log_err()
 6008                && !provider_responses.is_empty()
 6009            {
 6010                for response in provider_responses {
 6011                    completions.extend(response.completions);
 6012                    is_incomplete = is_incomplete || response.is_incomplete;
 6013                    match display_options.as_mut() {
 6014                        None => {
 6015                            display_options = Some(response.display_options);
 6016                        }
 6017                        Some(options) => options.merge(&response.display_options),
 6018                    }
 6019                }
 6020                if completion_settings.words == WordsCompletionMode::Fallback {
 6021                    words = Task::ready(BTreeMap::default());
 6022                }
 6023            }
 6024            let display_options = display_options.unwrap_or_default();
 6025
 6026            let mut words = words.await;
 6027            if let Some(word_to_exclude) = &word_to_exclude {
 6028                words.remove(word_to_exclude);
 6029            }
 6030            for lsp_completion in &completions {
 6031                words.remove(&lsp_completion.new_text);
 6032            }
 6033            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6034                replace_range: word_replace_range.clone(),
 6035                new_text: word.clone(),
 6036                label: CodeLabel::plain(word, None),
 6037                match_start: None,
 6038                snippet_deduplication_key: None,
 6039                icon_path: None,
 6040                documentation: None,
 6041                source: CompletionSource::BufferWord {
 6042                    word_range,
 6043                    resolved: false,
 6044                },
 6045                insert_text_mode: Some(InsertTextMode::AS_IS),
 6046                confirm: None,
 6047            }));
 6048
 6049            completions.extend(
 6050                snippets
 6051                    .await
 6052                    .into_iter()
 6053                    .flat_map(|response| response.completions),
 6054            );
 6055
 6056            let menu = if completions.is_empty() {
 6057                None
 6058            } else {
 6059                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6060                    let languages = editor
 6061                        .workspace
 6062                        .as_ref()
 6063                        .and_then(|(workspace, _)| workspace.upgrade())
 6064                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6065                    let menu = CompletionsMenu::new(
 6066                        id,
 6067                        requested_source.unwrap_or(if load_provider_completions {
 6068                            CompletionsMenuSource::Normal
 6069                        } else {
 6070                            CompletionsMenuSource::SnippetsOnly
 6071                        }),
 6072                        sort_completions,
 6073                        show_completion_documentation,
 6074                        position,
 6075                        query.clone(),
 6076                        is_incomplete,
 6077                        buffer.clone(),
 6078                        completions.into(),
 6079                        editor
 6080                            .context_menu()
 6081                            .borrow_mut()
 6082                            .as_ref()
 6083                            .map(|menu| menu.primary_scroll_handle()),
 6084                        display_options,
 6085                        snippet_sort_order,
 6086                        languages,
 6087                        language,
 6088                        cx,
 6089                    );
 6090
 6091                    let query = if filter_completions { query } else { None };
 6092                    let matches_task = menu.do_async_filtering(
 6093                        query.unwrap_or_default(),
 6094                        buffer_position,
 6095                        &buffer,
 6096                        cx,
 6097                    );
 6098                    (menu, matches_task)
 6099                }) else {
 6100                    return;
 6101                };
 6102
 6103                let matches = matches_task.await;
 6104
 6105                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6106                    // Newer menu already set, so exit.
 6107                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6108                        editor.context_menu.borrow().as_ref()
 6109                        && prev_menu.id > id
 6110                    {
 6111                        return;
 6112                    };
 6113
 6114                    // Only valid to take prev_menu because either the new menu is immediately set
 6115                    // below, or the menu is hidden.
 6116                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6117                        editor.context_menu.borrow_mut().take()
 6118                    {
 6119                        let position_matches =
 6120                            if prev_menu.initial_position == menu.initial_position {
 6121                                true
 6122                            } else {
 6123                                let snapshot = editor.buffer.read(cx).read(cx);
 6124                                prev_menu.initial_position.to_offset(&snapshot)
 6125                                    == menu.initial_position.to_offset(&snapshot)
 6126                            };
 6127                        if position_matches {
 6128                            // Preserve markdown cache before `set_filter_results` because it will
 6129                            // try to populate the documentation cache.
 6130                            menu.preserve_markdown_cache(prev_menu);
 6131                        }
 6132                    };
 6133
 6134                    menu.set_filter_results(matches, provider, window, cx);
 6135                }) else {
 6136                    return;
 6137                };
 6138
 6139                menu.visible().then_some(menu)
 6140            };
 6141
 6142            editor
 6143                .update_in(cx, |editor, window, cx| {
 6144                    if editor.focus_handle.is_focused(window)
 6145                        && let Some(menu) = menu
 6146                    {
 6147                        *editor.context_menu.borrow_mut() =
 6148                            Some(CodeContextMenu::Completions(menu));
 6149
 6150                        crate::hover_popover::hide_hover(editor, cx);
 6151                        if editor.show_edit_predictions_in_menu() {
 6152                            editor.update_visible_edit_prediction(window, cx);
 6153                        } else {
 6154                            editor.discard_edit_prediction(false, cx);
 6155                        }
 6156
 6157                        cx.notify();
 6158                        return;
 6159                    }
 6160
 6161                    if editor.completion_tasks.len() <= 1 {
 6162                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6163                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6164                        // If it was already hidden and we don't show edit predictions in the menu,
 6165                        // we should also show the edit prediction when available.
 6166                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6167                            editor.update_visible_edit_prediction(window, cx);
 6168                        }
 6169                    }
 6170                })
 6171                .ok();
 6172        });
 6173
 6174        self.completion_tasks.push((id, task));
 6175    }
 6176
 6177    #[cfg(feature = "test-support")]
 6178    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6179        let menu = self.context_menu.borrow();
 6180        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6181            let completions = menu.completions.borrow();
 6182            Some(completions.to_vec())
 6183        } else {
 6184            None
 6185        }
 6186    }
 6187
 6188    pub fn with_completions_menu_matching_id<R>(
 6189        &self,
 6190        id: CompletionId,
 6191        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6192    ) -> R {
 6193        let mut context_menu = self.context_menu.borrow_mut();
 6194        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6195            return f(None);
 6196        };
 6197        if completions_menu.id != id {
 6198            return f(None);
 6199        }
 6200        f(Some(completions_menu))
 6201    }
 6202
 6203    pub fn confirm_completion(
 6204        &mut self,
 6205        action: &ConfirmCompletion,
 6206        window: &mut Window,
 6207        cx: &mut Context<Self>,
 6208    ) -> Option<Task<Result<()>>> {
 6209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6210        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6211    }
 6212
 6213    pub fn confirm_completion_insert(
 6214        &mut self,
 6215        _: &ConfirmCompletionInsert,
 6216        window: &mut Window,
 6217        cx: &mut Context<Self>,
 6218    ) -> Option<Task<Result<()>>> {
 6219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6220        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6221    }
 6222
 6223    pub fn confirm_completion_replace(
 6224        &mut self,
 6225        _: &ConfirmCompletionReplace,
 6226        window: &mut Window,
 6227        cx: &mut Context<Self>,
 6228    ) -> Option<Task<Result<()>>> {
 6229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6230        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6231    }
 6232
 6233    pub fn compose_completion(
 6234        &mut self,
 6235        action: &ComposeCompletion,
 6236        window: &mut Window,
 6237        cx: &mut Context<Self>,
 6238    ) -> Option<Task<Result<()>>> {
 6239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6240        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6241    }
 6242
 6243    fn do_completion(
 6244        &mut self,
 6245        item_ix: Option<usize>,
 6246        intent: CompletionIntent,
 6247        window: &mut Window,
 6248        cx: &mut Context<Editor>,
 6249    ) -> Option<Task<Result<()>>> {
 6250        use language::ToOffset as _;
 6251
 6252        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6253        else {
 6254            return None;
 6255        };
 6256
 6257        let candidate_id = {
 6258            let entries = completions_menu.entries.borrow();
 6259            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6260            if self.show_edit_predictions_in_menu() {
 6261                self.discard_edit_prediction(true, cx);
 6262            }
 6263            mat.candidate_id
 6264        };
 6265
 6266        let completion = completions_menu
 6267            .completions
 6268            .borrow()
 6269            .get(candidate_id)?
 6270            .clone();
 6271        cx.stop_propagation();
 6272
 6273        let buffer_handle = completions_menu.buffer.clone();
 6274
 6275        let CompletionEdit {
 6276            new_text,
 6277            snippet,
 6278            replace_range,
 6279        } = process_completion_for_edit(
 6280            &completion,
 6281            intent,
 6282            &buffer_handle,
 6283            &completions_menu.initial_position.text_anchor,
 6284            cx,
 6285        );
 6286
 6287        let buffer = buffer_handle.read(cx);
 6288        let snapshot = self.buffer.read(cx).snapshot(cx);
 6289        let newest_anchor = self.selections.newest_anchor();
 6290        let replace_range_multibuffer = {
 6291            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6292            excerpt.map_range_from_buffer(replace_range.clone())
 6293        };
 6294        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6295            return None;
 6296        }
 6297
 6298        let old_text = buffer
 6299            .text_for_range(replace_range.clone())
 6300            .collect::<String>();
 6301        let lookbehind = newest_anchor
 6302            .start
 6303            .text_anchor
 6304            .to_offset(buffer)
 6305            .saturating_sub(replace_range.start.0);
 6306        let lookahead = replace_range
 6307            .end
 6308            .0
 6309            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6310        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6311        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6312
 6313        let selections = self
 6314            .selections
 6315            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6316        let mut ranges = Vec::new();
 6317        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6318
 6319        for selection in &selections {
 6320            let range = if selection.id == newest_anchor.id {
 6321                replace_range_multibuffer.clone()
 6322            } else {
 6323                let mut range = selection.range();
 6324
 6325                // if prefix is present, don't duplicate it
 6326                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6327                    range.start = range.start.saturating_sub_usize(lookbehind);
 6328
 6329                    // if suffix is also present, mimic the newest cursor and replace it
 6330                    if selection.id != newest_anchor.id
 6331                        && snapshot.contains_str_at(range.end, suffix)
 6332                    {
 6333                        range.end += lookahead;
 6334                    }
 6335                }
 6336                range
 6337            };
 6338
 6339            ranges.push(range.clone());
 6340
 6341            if !self.linked_edit_ranges.is_empty() {
 6342                let start_anchor = snapshot.anchor_before(range.start);
 6343                let end_anchor = snapshot.anchor_after(range.end);
 6344                if let Some(ranges) = self
 6345                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6346                {
 6347                    for (buffer, edits) in ranges {
 6348                        linked_edits
 6349                            .entry(buffer.clone())
 6350                            .or_default()
 6351                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6352                    }
 6353                }
 6354            }
 6355        }
 6356
 6357        let common_prefix_len = old_text
 6358            .chars()
 6359            .zip(new_text.chars())
 6360            .take_while(|(a, b)| a == b)
 6361            .map(|(a, _)| a.len_utf8())
 6362            .sum::<usize>();
 6363
 6364        cx.emit(EditorEvent::InputHandled {
 6365            utf16_range_to_replace: None,
 6366            text: new_text[common_prefix_len..].into(),
 6367        });
 6368
 6369        self.transact(window, cx, |editor, window, cx| {
 6370            if let Some(mut snippet) = snippet {
 6371                snippet.text = new_text.to_string();
 6372                editor
 6373                    .insert_snippet(&ranges, snippet, window, cx)
 6374                    .log_err();
 6375            } else {
 6376                editor.buffer.update(cx, |multi_buffer, cx| {
 6377                    let auto_indent = match completion.insert_text_mode {
 6378                        Some(InsertTextMode::AS_IS) => None,
 6379                        _ => editor.autoindent_mode.clone(),
 6380                    };
 6381                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6382                    multi_buffer.edit(edits, auto_indent, cx);
 6383                });
 6384            }
 6385            for (buffer, edits) in linked_edits {
 6386                buffer.update(cx, |buffer, cx| {
 6387                    let snapshot = buffer.snapshot();
 6388                    let edits = edits
 6389                        .into_iter()
 6390                        .map(|(range, text)| {
 6391                            use text::ToPoint as TP;
 6392                            let end_point = TP::to_point(&range.end, &snapshot);
 6393                            let start_point = TP::to_point(&range.start, &snapshot);
 6394                            (start_point..end_point, text)
 6395                        })
 6396                        .sorted_by_key(|(range, _)| range.start);
 6397                    buffer.edit(edits, None, cx);
 6398                })
 6399            }
 6400
 6401            editor.refresh_edit_prediction(true, false, window, cx);
 6402        });
 6403        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6404
 6405        let show_new_completions_on_confirm = completion
 6406            .confirm
 6407            .as_ref()
 6408            .is_some_and(|confirm| confirm(intent, window, cx));
 6409        if show_new_completions_on_confirm {
 6410            self.open_or_update_completions_menu(None, None, false, window, cx);
 6411        }
 6412
 6413        let provider = self.completion_provider.as_ref()?;
 6414
 6415        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6416        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6417            let CompletionSource::Lsp {
 6418                lsp_completion,
 6419                server_id,
 6420                ..
 6421            } = &completion.source
 6422            else {
 6423                return None;
 6424            };
 6425            let lsp_command = lsp_completion.command.as_ref()?;
 6426            let available_commands = lsp_store
 6427                .read(cx)
 6428                .lsp_server_capabilities
 6429                .get(server_id)
 6430                .and_then(|server_capabilities| {
 6431                    server_capabilities
 6432                        .execute_command_provider
 6433                        .as_ref()
 6434                        .map(|options| options.commands.as_slice())
 6435                })?;
 6436            if available_commands.contains(&lsp_command.command) {
 6437                Some(CodeAction {
 6438                    server_id: *server_id,
 6439                    range: language::Anchor::MIN..language::Anchor::MIN,
 6440                    lsp_action: LspAction::Command(lsp_command.clone()),
 6441                    resolved: false,
 6442                })
 6443            } else {
 6444                None
 6445            }
 6446        });
 6447
 6448        drop(completion);
 6449        let apply_edits = provider.apply_additional_edits_for_completion(
 6450            buffer_handle.clone(),
 6451            completions_menu.completions.clone(),
 6452            candidate_id,
 6453            true,
 6454            cx,
 6455        );
 6456
 6457        let editor_settings = EditorSettings::get_global(cx);
 6458        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6459            // After the code completion is finished, users often want to know what signatures are needed.
 6460            // so we should automatically call signature_help
 6461            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6462        }
 6463
 6464        Some(cx.spawn_in(window, async move |editor, cx| {
 6465            apply_edits.await?;
 6466
 6467            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6468                let title = command.lsp_action.title().to_owned();
 6469                let project_transaction = lsp_store
 6470                    .update(cx, |lsp_store, cx| {
 6471                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6472                    })
 6473                    .await
 6474                    .context("applying post-completion command")?;
 6475                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6476                    Self::open_project_transaction(
 6477                        &editor,
 6478                        workspace.downgrade(),
 6479                        project_transaction,
 6480                        title,
 6481                        cx,
 6482                    )
 6483                    .await?;
 6484                }
 6485            }
 6486
 6487            Ok(())
 6488        }))
 6489    }
 6490
 6491    pub fn toggle_code_actions(
 6492        &mut self,
 6493        action: &ToggleCodeActions,
 6494        window: &mut Window,
 6495        cx: &mut Context<Self>,
 6496    ) {
 6497        let quick_launch = action.quick_launch;
 6498        let mut context_menu = self.context_menu.borrow_mut();
 6499        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6500            if code_actions.deployed_from == action.deployed_from {
 6501                // Toggle if we're selecting the same one
 6502                *context_menu = None;
 6503                cx.notify();
 6504                return;
 6505            } else {
 6506                // Otherwise, clear it and start a new one
 6507                *context_menu = None;
 6508                cx.notify();
 6509            }
 6510        }
 6511        drop(context_menu);
 6512        let snapshot = self.snapshot(window, cx);
 6513        let deployed_from = action.deployed_from.clone();
 6514        let action = action.clone();
 6515        self.completion_tasks.clear();
 6516        self.discard_edit_prediction(false, cx);
 6517
 6518        let multibuffer_point = match &action.deployed_from {
 6519            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6520                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6521            }
 6522            _ => self
 6523                .selections
 6524                .newest::<Point>(&snapshot.display_snapshot)
 6525                .head(),
 6526        };
 6527        let Some((buffer, buffer_row)) = snapshot
 6528            .buffer_snapshot()
 6529            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6530            .and_then(|(buffer_snapshot, range)| {
 6531                self.buffer()
 6532                    .read(cx)
 6533                    .buffer(buffer_snapshot.remote_id())
 6534                    .map(|buffer| (buffer, range.start.row))
 6535            })
 6536        else {
 6537            return;
 6538        };
 6539        let buffer_id = buffer.read(cx).remote_id();
 6540        let tasks = self
 6541            .tasks
 6542            .get(&(buffer_id, buffer_row))
 6543            .map(|t| Arc::new(t.to_owned()));
 6544
 6545        if !self.focus_handle.is_focused(window) {
 6546            return;
 6547        }
 6548        let project = self.project.clone();
 6549
 6550        let code_actions_task = match deployed_from {
 6551            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6552            _ => self.code_actions(buffer_row, window, cx),
 6553        };
 6554
 6555        let runnable_task = match deployed_from {
 6556            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6557            _ => {
 6558                let mut task_context_task = Task::ready(None);
 6559                if let Some(tasks) = &tasks
 6560                    && let Some(project) = project
 6561                {
 6562                    task_context_task =
 6563                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6564                }
 6565
 6566                cx.spawn_in(window, {
 6567                    let buffer = buffer.clone();
 6568                    async move |editor, cx| {
 6569                        let task_context = task_context_task.await;
 6570
 6571                        let resolved_tasks =
 6572                            tasks
 6573                                .zip(task_context.clone())
 6574                                .map(|(tasks, task_context)| ResolvedTasks {
 6575                                    templates: tasks.resolve(&task_context).collect(),
 6576                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6577                                        multibuffer_point.row,
 6578                                        tasks.column,
 6579                                    )),
 6580                                });
 6581                        let debug_scenarios = editor
 6582                            .update(cx, |editor, cx| {
 6583                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6584                            })?
 6585                            .await;
 6586                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6587                    }
 6588                })
 6589            }
 6590        };
 6591
 6592        cx.spawn_in(window, async move |editor, cx| {
 6593            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6594            let code_actions = code_actions_task.await;
 6595            let spawn_straight_away = quick_launch
 6596                && resolved_tasks
 6597                    .as_ref()
 6598                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6599                && code_actions
 6600                    .as_ref()
 6601                    .is_none_or(|actions| actions.is_empty())
 6602                && debug_scenarios.is_empty();
 6603
 6604            editor.update_in(cx, |editor, window, cx| {
 6605                crate::hover_popover::hide_hover(editor, cx);
 6606                let actions = CodeActionContents::new(
 6607                    resolved_tasks,
 6608                    code_actions,
 6609                    debug_scenarios,
 6610                    task_context.unwrap_or_default(),
 6611                );
 6612
 6613                // Don't show the menu if there are no actions available
 6614                if actions.is_empty() {
 6615                    cx.notify();
 6616                    return Task::ready(Ok(()));
 6617                }
 6618
 6619                *editor.context_menu.borrow_mut() =
 6620                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6621                        buffer,
 6622                        actions,
 6623                        selected_item: Default::default(),
 6624                        scroll_handle: UniformListScrollHandle::default(),
 6625                        deployed_from,
 6626                    }));
 6627                cx.notify();
 6628                if spawn_straight_away
 6629                    && let Some(task) = editor.confirm_code_action(
 6630                        &ConfirmCodeAction { item_ix: Some(0) },
 6631                        window,
 6632                        cx,
 6633                    )
 6634                {
 6635                    return task;
 6636                }
 6637
 6638                Task::ready(Ok(()))
 6639            })
 6640        })
 6641        .detach_and_log_err(cx);
 6642    }
 6643
 6644    fn debug_scenarios(
 6645        &mut self,
 6646        resolved_tasks: &Option<ResolvedTasks>,
 6647        buffer: &Entity<Buffer>,
 6648        cx: &mut App,
 6649    ) -> Task<Vec<task::DebugScenario>> {
 6650        maybe!({
 6651            let project = self.project()?;
 6652            let dap_store = project.read(cx).dap_store();
 6653            let mut scenarios = vec![];
 6654            let resolved_tasks = resolved_tasks.as_ref()?;
 6655            let buffer = buffer.read(cx);
 6656            let language = buffer.language()?;
 6657            let file = buffer.file();
 6658            let debug_adapter = language_settings(language.name().into(), file, cx)
 6659                .debuggers
 6660                .first()
 6661                .map(SharedString::from)
 6662                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6663
 6664            dap_store.update(cx, |dap_store, cx| {
 6665                for (_, task) in &resolved_tasks.templates {
 6666                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6667                        task.original_task().clone(),
 6668                        debug_adapter.clone().into(),
 6669                        task.display_label().to_owned().into(),
 6670                        cx,
 6671                    );
 6672                    scenarios.push(maybe_scenario);
 6673                }
 6674            });
 6675            Some(cx.background_spawn(async move {
 6676                futures::future::join_all(scenarios)
 6677                    .await
 6678                    .into_iter()
 6679                    .flatten()
 6680                    .collect::<Vec<_>>()
 6681            }))
 6682        })
 6683        .unwrap_or_else(|| Task::ready(vec![]))
 6684    }
 6685
 6686    fn code_actions(
 6687        &mut self,
 6688        buffer_row: u32,
 6689        window: &mut Window,
 6690        cx: &mut Context<Self>,
 6691    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6692        let mut task = self.code_actions_task.take();
 6693        cx.spawn_in(window, async move |editor, cx| {
 6694            while let Some(prev_task) = task {
 6695                prev_task.await.log_err();
 6696                task = editor
 6697                    .update(cx, |this, _| this.code_actions_task.take())
 6698                    .ok()?;
 6699            }
 6700
 6701            editor
 6702                .update(cx, |editor, cx| {
 6703                    editor
 6704                        .available_code_actions
 6705                        .clone()
 6706                        .and_then(|(location, code_actions)| {
 6707                            let snapshot = location.buffer.read(cx).snapshot();
 6708                            let point_range = location.range.to_point(&snapshot);
 6709                            let point_range = point_range.start.row..=point_range.end.row;
 6710                            if point_range.contains(&buffer_row) {
 6711                                Some(code_actions)
 6712                            } else {
 6713                                None
 6714                            }
 6715                        })
 6716                })
 6717                .ok()
 6718                .flatten()
 6719        })
 6720    }
 6721
 6722    pub fn confirm_code_action(
 6723        &mut self,
 6724        action: &ConfirmCodeAction,
 6725        window: &mut Window,
 6726        cx: &mut Context<Self>,
 6727    ) -> Option<Task<Result<()>>> {
 6728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6729
 6730        let actions_menu =
 6731            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6732                menu
 6733            } else {
 6734                return None;
 6735            };
 6736
 6737        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6738        let action = actions_menu.actions.get(action_ix)?;
 6739        let title = action.label();
 6740        let buffer = actions_menu.buffer;
 6741        let workspace = self.workspace()?;
 6742
 6743        match action {
 6744            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6745                workspace.update(cx, |workspace, cx| {
 6746                    workspace.schedule_resolved_task(
 6747                        task_source_kind,
 6748                        resolved_task,
 6749                        false,
 6750                        window,
 6751                        cx,
 6752                    );
 6753
 6754                    Some(Task::ready(Ok(())))
 6755                })
 6756            }
 6757            CodeActionsItem::CodeAction {
 6758                excerpt_id,
 6759                action,
 6760                provider,
 6761            } => {
 6762                let apply_code_action =
 6763                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6764                let workspace = workspace.downgrade();
 6765                Some(cx.spawn_in(window, async move |editor, cx| {
 6766                    let project_transaction = apply_code_action.await?;
 6767                    Self::open_project_transaction(
 6768                        &editor,
 6769                        workspace,
 6770                        project_transaction,
 6771                        title,
 6772                        cx,
 6773                    )
 6774                    .await
 6775                }))
 6776            }
 6777            CodeActionsItem::DebugScenario(scenario) => {
 6778                let context = actions_menu.actions.context;
 6779
 6780                workspace.update(cx, |workspace, cx| {
 6781                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6782                    workspace.start_debug_session(
 6783                        scenario,
 6784                        context,
 6785                        Some(buffer),
 6786                        None,
 6787                        window,
 6788                        cx,
 6789                    );
 6790                });
 6791                Some(Task::ready(Ok(())))
 6792            }
 6793        }
 6794    }
 6795
 6796    fn open_transaction_for_hidden_buffers(
 6797        workspace: Entity<Workspace>,
 6798        transaction: ProjectTransaction,
 6799        title: String,
 6800        window: &mut Window,
 6801        cx: &mut Context<Self>,
 6802    ) {
 6803        if transaction.0.is_empty() {
 6804            return;
 6805        }
 6806
 6807        let edited_buffers_already_open = {
 6808            let other_editors: Vec<Entity<Editor>> = workspace
 6809                .read(cx)
 6810                .panes()
 6811                .iter()
 6812                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6813                .filter(|editor| editor.entity_id() != cx.entity_id())
 6814                .collect();
 6815
 6816            transaction.0.keys().all(|buffer| {
 6817                other_editors.iter().any(|editor| {
 6818                    let multi_buffer = editor.read(cx).buffer();
 6819                    multi_buffer.read(cx).is_singleton()
 6820                        && multi_buffer
 6821                            .read(cx)
 6822                            .as_singleton()
 6823                            .map_or(false, |singleton| {
 6824                                singleton.entity_id() == buffer.entity_id()
 6825                            })
 6826                })
 6827            })
 6828        };
 6829        if !edited_buffers_already_open {
 6830            let workspace = workspace.downgrade();
 6831            cx.defer_in(window, move |_, window, cx| {
 6832                cx.spawn_in(window, async move |editor, cx| {
 6833                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6834                        .await
 6835                        .ok()
 6836                })
 6837                .detach();
 6838            });
 6839        }
 6840    }
 6841
 6842    pub async fn open_project_transaction(
 6843        editor: &WeakEntity<Editor>,
 6844        workspace: WeakEntity<Workspace>,
 6845        transaction: ProjectTransaction,
 6846        title: String,
 6847        cx: &mut AsyncWindowContext,
 6848    ) -> Result<()> {
 6849        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6850        cx.update(|_, cx| {
 6851            entries.sort_unstable_by_key(|(buffer, _)| {
 6852                buffer.read(cx).file().map(|f| f.path().clone())
 6853            });
 6854        })?;
 6855        if entries.is_empty() {
 6856            return Ok(());
 6857        }
 6858
 6859        // If the project transaction's edits are all contained within this editor, then
 6860        // avoid opening a new editor to display them.
 6861
 6862        if let [(buffer, transaction)] = &*entries {
 6863            let excerpt = editor.update(cx, |editor, cx| {
 6864                editor
 6865                    .buffer()
 6866                    .read(cx)
 6867                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6868            })?;
 6869            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6870                && excerpted_buffer == *buffer
 6871            {
 6872                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6873                    let excerpt_range = excerpt_range.to_offset(buffer);
 6874                    buffer
 6875                        .edited_ranges_for_transaction::<usize>(transaction)
 6876                        .all(|range| {
 6877                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6878                        })
 6879                });
 6880
 6881                if all_edits_within_excerpt {
 6882                    return Ok(());
 6883                }
 6884            }
 6885        }
 6886
 6887        let mut ranges_to_highlight = Vec::new();
 6888        let excerpt_buffer = cx.new(|cx| {
 6889            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6890            for (buffer_handle, transaction) in &entries {
 6891                let edited_ranges = buffer_handle
 6892                    .read(cx)
 6893                    .edited_ranges_for_transaction::<Point>(transaction)
 6894                    .collect::<Vec<_>>();
 6895                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6896                    PathKey::for_buffer(buffer_handle, cx),
 6897                    buffer_handle.clone(),
 6898                    edited_ranges,
 6899                    multibuffer_context_lines(cx),
 6900                    cx,
 6901                );
 6902
 6903                ranges_to_highlight.extend(ranges);
 6904            }
 6905            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6906            multibuffer
 6907        });
 6908
 6909        workspace.update_in(cx, |workspace, window, cx| {
 6910            let project = workspace.project().clone();
 6911            let editor =
 6912                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6913            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6914            editor.update(cx, |editor, cx| {
 6915                editor.highlight_background::<Self>(
 6916                    &ranges_to_highlight,
 6917                    |_, theme| theme.colors().editor_highlighted_line_background,
 6918                    cx,
 6919                );
 6920            });
 6921        })?;
 6922
 6923        Ok(())
 6924    }
 6925
 6926    pub fn clear_code_action_providers(&mut self) {
 6927        self.code_action_providers.clear();
 6928        self.available_code_actions.take();
 6929    }
 6930
 6931    pub fn add_code_action_provider(
 6932        &mut self,
 6933        provider: Rc<dyn CodeActionProvider>,
 6934        window: &mut Window,
 6935        cx: &mut Context<Self>,
 6936    ) {
 6937        if self
 6938            .code_action_providers
 6939            .iter()
 6940            .any(|existing_provider| existing_provider.id() == provider.id())
 6941        {
 6942            return;
 6943        }
 6944
 6945        self.code_action_providers.push(provider);
 6946        self.refresh_code_actions(window, cx);
 6947    }
 6948
 6949    pub fn remove_code_action_provider(
 6950        &mut self,
 6951        id: Arc<str>,
 6952        window: &mut Window,
 6953        cx: &mut Context<Self>,
 6954    ) {
 6955        self.code_action_providers
 6956            .retain(|provider| provider.id() != id);
 6957        self.refresh_code_actions(window, cx);
 6958    }
 6959
 6960    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6961        !self.code_action_providers.is_empty()
 6962            && EditorSettings::get_global(cx).toolbar.code_actions
 6963    }
 6964
 6965    pub fn has_available_code_actions(&self) -> bool {
 6966        self.available_code_actions
 6967            .as_ref()
 6968            .is_some_and(|(_, actions)| !actions.is_empty())
 6969    }
 6970
 6971    fn render_inline_code_actions(
 6972        &self,
 6973        icon_size: ui::IconSize,
 6974        display_row: DisplayRow,
 6975        is_active: bool,
 6976        cx: &mut Context<Self>,
 6977    ) -> AnyElement {
 6978        let show_tooltip = !self.context_menu_visible();
 6979        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6980            .icon_size(icon_size)
 6981            .shape(ui::IconButtonShape::Square)
 6982            .icon_color(ui::Color::Hidden)
 6983            .toggle_state(is_active)
 6984            .when(show_tooltip, |this| {
 6985                this.tooltip({
 6986                    let focus_handle = self.focus_handle.clone();
 6987                    move |_window, cx| {
 6988                        Tooltip::for_action_in(
 6989                            "Toggle Code Actions",
 6990                            &ToggleCodeActions {
 6991                                deployed_from: None,
 6992                                quick_launch: false,
 6993                            },
 6994                            &focus_handle,
 6995                            cx,
 6996                        )
 6997                    }
 6998                })
 6999            })
 7000            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7001                window.focus(&editor.focus_handle(cx), cx);
 7002                editor.toggle_code_actions(
 7003                    &crate::actions::ToggleCodeActions {
 7004                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7005                            display_row,
 7006                        )),
 7007                        quick_launch: false,
 7008                    },
 7009                    window,
 7010                    cx,
 7011                );
 7012            }))
 7013            .into_any_element()
 7014    }
 7015
 7016    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7017        &self.context_menu
 7018    }
 7019
 7020    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7021        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7022            cx.background_executor()
 7023                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7024                .await;
 7025
 7026            let (start_buffer, start, _, end, newest_selection) = this
 7027                .update(cx, |this, cx| {
 7028                    let newest_selection = this.selections.newest_anchor().clone();
 7029                    if newest_selection.head().diff_base_anchor.is_some() {
 7030                        return None;
 7031                    }
 7032                    let display_snapshot = this.display_snapshot(cx);
 7033                    let newest_selection_adjusted =
 7034                        this.selections.newest_adjusted(&display_snapshot);
 7035                    let buffer = this.buffer.read(cx);
 7036
 7037                    let (start_buffer, start) =
 7038                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7039                    let (end_buffer, end) =
 7040                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7041
 7042                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7043                })?
 7044                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7045                .context(
 7046                    "Expected selection to lie in a single buffer when refreshing code actions",
 7047                )?;
 7048            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7049                let providers = this.code_action_providers.clone();
 7050                let tasks = this
 7051                    .code_action_providers
 7052                    .iter()
 7053                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7054                    .collect::<Vec<_>>();
 7055                (providers, tasks)
 7056            })?;
 7057
 7058            let mut actions = Vec::new();
 7059            for (provider, provider_actions) in
 7060                providers.into_iter().zip(future::join_all(tasks).await)
 7061            {
 7062                if let Some(provider_actions) = provider_actions.log_err() {
 7063                    actions.extend(provider_actions.into_iter().map(|action| {
 7064                        AvailableCodeAction {
 7065                            excerpt_id: newest_selection.start.excerpt_id,
 7066                            action,
 7067                            provider: provider.clone(),
 7068                        }
 7069                    }));
 7070                }
 7071            }
 7072
 7073            this.update(cx, |this, cx| {
 7074                this.available_code_actions = if actions.is_empty() {
 7075                    None
 7076                } else {
 7077                    Some((
 7078                        Location {
 7079                            buffer: start_buffer,
 7080                            range: start..end,
 7081                        },
 7082                        actions.into(),
 7083                    ))
 7084                };
 7085                cx.notify();
 7086            })
 7087        }));
 7088    }
 7089
 7090    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7091        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7092            self.show_git_blame_inline = false;
 7093
 7094            self.show_git_blame_inline_delay_task =
 7095                Some(cx.spawn_in(window, async move |this, cx| {
 7096                    cx.background_executor().timer(delay).await;
 7097
 7098                    this.update(cx, |this, cx| {
 7099                        this.show_git_blame_inline = true;
 7100                        cx.notify();
 7101                    })
 7102                    .log_err();
 7103                }));
 7104        }
 7105    }
 7106
 7107    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7108        let snapshot = self.snapshot(window, cx);
 7109        let cursor = self
 7110            .selections
 7111            .newest::<Point>(&snapshot.display_snapshot)
 7112            .head();
 7113        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7114        else {
 7115            return;
 7116        };
 7117
 7118        if self.blame.is_none() {
 7119            self.start_git_blame(true, window, cx);
 7120        }
 7121        let Some(blame) = self.blame.as_ref() else {
 7122            return;
 7123        };
 7124
 7125        let row_info = RowInfo {
 7126            buffer_id: Some(buffer.remote_id()),
 7127            buffer_row: Some(point.row),
 7128            ..Default::default()
 7129        };
 7130        let Some((buffer, blame_entry)) = blame
 7131            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7132            .flatten()
 7133        else {
 7134            return;
 7135        };
 7136
 7137        let anchor = self.selections.newest_anchor().head();
 7138        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7139        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7140            self.show_blame_popover(
 7141                buffer,
 7142                &blame_entry,
 7143                position + last_bounds.origin,
 7144                true,
 7145                cx,
 7146            );
 7147        };
 7148    }
 7149
 7150    fn show_blame_popover(
 7151        &mut self,
 7152        buffer: BufferId,
 7153        blame_entry: &BlameEntry,
 7154        position: gpui::Point<Pixels>,
 7155        ignore_timeout: bool,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        if let Some(state) = &mut self.inline_blame_popover {
 7159            state.hide_task.take();
 7160        } else {
 7161            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7162            let blame_entry = blame_entry.clone();
 7163            let show_task = cx.spawn(async move |editor, cx| {
 7164                if !ignore_timeout {
 7165                    cx.background_executor()
 7166                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7167                        .await;
 7168                }
 7169                editor
 7170                    .update(cx, |editor, cx| {
 7171                        editor.inline_blame_popover_show_task.take();
 7172                        let Some(blame) = editor.blame.as_ref() else {
 7173                            return;
 7174                        };
 7175                        let blame = blame.read(cx);
 7176                        let details = blame.details_for_entry(buffer, &blame_entry);
 7177                        let markdown = cx.new(|cx| {
 7178                            Markdown::new(
 7179                                details
 7180                                    .as_ref()
 7181                                    .map(|message| message.message.clone())
 7182                                    .unwrap_or_default(),
 7183                                None,
 7184                                None,
 7185                                cx,
 7186                            )
 7187                        });
 7188                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7189                            position,
 7190                            hide_task: None,
 7191                            popover_bounds: None,
 7192                            popover_state: InlineBlamePopoverState {
 7193                                scroll_handle: ScrollHandle::new(),
 7194                                commit_message: details,
 7195                                markdown,
 7196                            },
 7197                            keyboard_grace: ignore_timeout,
 7198                        });
 7199                        cx.notify();
 7200                    })
 7201                    .ok();
 7202            });
 7203            self.inline_blame_popover_show_task = Some(show_task);
 7204        }
 7205    }
 7206
 7207    pub fn has_mouse_context_menu(&self) -> bool {
 7208        self.mouse_context_menu.is_some()
 7209    }
 7210
 7211    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7212        self.inline_blame_popover_show_task.take();
 7213        if let Some(state) = &mut self.inline_blame_popover {
 7214            let hide_task = cx.spawn(async move |editor, cx| {
 7215                if !ignore_timeout {
 7216                    cx.background_executor()
 7217                        .timer(std::time::Duration::from_millis(100))
 7218                        .await;
 7219                }
 7220                editor
 7221                    .update(cx, |editor, cx| {
 7222                        editor.inline_blame_popover.take();
 7223                        cx.notify();
 7224                    })
 7225                    .ok();
 7226            });
 7227            state.hide_task = Some(hide_task);
 7228            true
 7229        } else {
 7230            false
 7231        }
 7232    }
 7233
 7234    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7235        if self.pending_rename.is_some() {
 7236            return None;
 7237        }
 7238
 7239        let provider = self.semantics_provider.clone()?;
 7240        let buffer = self.buffer.read(cx);
 7241        let newest_selection = self.selections.newest_anchor().clone();
 7242        let cursor_position = newest_selection.head();
 7243        let (cursor_buffer, cursor_buffer_position) =
 7244            buffer.text_anchor_for_position(cursor_position, cx)?;
 7245        let (tail_buffer, tail_buffer_position) =
 7246            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7247        if cursor_buffer != tail_buffer {
 7248            return None;
 7249        }
 7250
 7251        let snapshot = cursor_buffer.read(cx).snapshot();
 7252        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7253        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7254        if start_word_range != end_word_range {
 7255            self.document_highlights_task.take();
 7256            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7257            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7258            return None;
 7259        }
 7260
 7261        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7262        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7263            cx.background_executor()
 7264                .timer(Duration::from_millis(debounce))
 7265                .await;
 7266
 7267            let highlights = if let Some(highlights) = cx.update(|cx| {
 7268                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7269            }) {
 7270                highlights.await.log_err()
 7271            } else {
 7272                None
 7273            };
 7274
 7275            if let Some(highlights) = highlights {
 7276                this.update(cx, |this, cx| {
 7277                    if this.pending_rename.is_some() {
 7278                        return;
 7279                    }
 7280
 7281                    let buffer = this.buffer.read(cx);
 7282                    if buffer
 7283                        .text_anchor_for_position(cursor_position, cx)
 7284                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7285                    {
 7286                        return;
 7287                    }
 7288
 7289                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7290                    let mut write_ranges = Vec::new();
 7291                    let mut read_ranges = Vec::new();
 7292                    for highlight in highlights {
 7293                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7294                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7295                        {
 7296                            let start = highlight
 7297                                .range
 7298                                .start
 7299                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7300                            let end = highlight
 7301                                .range
 7302                                .end
 7303                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7304                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7305                                continue;
 7306                            }
 7307
 7308                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7309                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7310                                write_ranges.push(range);
 7311                            } else {
 7312                                read_ranges.push(range);
 7313                            }
 7314                        }
 7315                    }
 7316
 7317                    this.highlight_background::<DocumentHighlightRead>(
 7318                        &read_ranges,
 7319                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7320                        cx,
 7321                    );
 7322                    this.highlight_background::<DocumentHighlightWrite>(
 7323                        &write_ranges,
 7324                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7325                        cx,
 7326                    );
 7327                    cx.notify();
 7328                })
 7329                .log_err();
 7330            }
 7331        }));
 7332        None
 7333    }
 7334
 7335    fn prepare_highlight_query_from_selection(
 7336        &mut self,
 7337        window: &Window,
 7338        cx: &mut Context<Editor>,
 7339    ) -> Option<(String, Range<Anchor>)> {
 7340        if matches!(self.mode, EditorMode::SingleLine) {
 7341            return None;
 7342        }
 7343        if !EditorSettings::get_global(cx).selection_highlight {
 7344            return None;
 7345        }
 7346        if self.selections.count() != 1 || self.selections.line_mode() {
 7347            return None;
 7348        }
 7349        let snapshot = self.snapshot(window, cx);
 7350        let selection = self.selections.newest::<Point>(&snapshot);
 7351        // If the selection spans multiple rows OR it is empty
 7352        if selection.start.row != selection.end.row
 7353            || selection.start.column == selection.end.column
 7354        {
 7355            return None;
 7356        }
 7357        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7358        let query = snapshot
 7359            .buffer_snapshot()
 7360            .text_for_range(selection_anchor_range.clone())
 7361            .collect::<String>();
 7362        if query.trim().is_empty() {
 7363            return None;
 7364        }
 7365        Some((query, selection_anchor_range))
 7366    }
 7367
 7368    #[ztracing::instrument(skip_all)]
 7369    fn update_selection_occurrence_highlights(
 7370        &mut self,
 7371        query_text: String,
 7372        query_range: Range<Anchor>,
 7373        multi_buffer_range_to_query: Range<Point>,
 7374        use_debounce: bool,
 7375        window: &mut Window,
 7376        cx: &mut Context<Editor>,
 7377    ) -> Task<()> {
 7378        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7379        cx.spawn_in(window, async move |editor, cx| {
 7380            if use_debounce {
 7381                cx.background_executor()
 7382                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7383                    .await;
 7384            }
 7385            let match_task = cx.background_spawn(async move {
 7386                let buffer_ranges = multi_buffer_snapshot
 7387                    .range_to_buffer_ranges(
 7388                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7389                    )
 7390                    .into_iter()
 7391                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7392                let mut match_ranges = Vec::new();
 7393                let Ok(regex) = project::search::SearchQuery::text(
 7394                    query_text.clone(),
 7395                    false,
 7396                    false,
 7397                    false,
 7398                    Default::default(),
 7399                    Default::default(),
 7400                    false,
 7401                    None,
 7402                ) else {
 7403                    return Vec::default();
 7404                };
 7405                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7406                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7407                    match_ranges.extend(
 7408                        regex
 7409                            .search(
 7410                                buffer_snapshot,
 7411                                Some(search_range.start.0..search_range.end.0),
 7412                            )
 7413                            .await
 7414                            .into_iter()
 7415                            .filter_map(|match_range| {
 7416                                let match_start = buffer_snapshot
 7417                                    .anchor_after(search_range.start + match_range.start);
 7418                                let match_end = buffer_snapshot
 7419                                    .anchor_before(search_range.start + match_range.end);
 7420                                let match_anchor_range =
 7421                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7422                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7423                            }),
 7424                    );
 7425                }
 7426                match_ranges
 7427            });
 7428            let match_ranges = match_task.await;
 7429            editor
 7430                .update_in(cx, |editor, _, cx| {
 7431                    if use_debounce {
 7432                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7433                        editor.debounced_selection_highlight_complete = true;
 7434                    } else if editor.debounced_selection_highlight_complete {
 7435                        return;
 7436                    }
 7437                    if !match_ranges.is_empty() {
 7438                        editor.highlight_background::<SelectedTextHighlight>(
 7439                            &match_ranges,
 7440                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7441                            cx,
 7442                        )
 7443                    }
 7444                })
 7445                .log_err();
 7446        })
 7447    }
 7448
 7449    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7450        struct NewlineFold;
 7451        let type_id = std::any::TypeId::of::<NewlineFold>();
 7452        if !self.mode.is_single_line() {
 7453            return;
 7454        }
 7455        let snapshot = self.snapshot(window, cx);
 7456        if snapshot.buffer_snapshot().max_point().row == 0 {
 7457            return;
 7458        }
 7459        let task = cx.background_spawn(async move {
 7460            let new_newlines = snapshot
 7461                .buffer_chars_at(MultiBufferOffset(0))
 7462                .filter_map(|(c, i)| {
 7463                    if c == '\n' {
 7464                        Some(
 7465                            snapshot.buffer_snapshot().anchor_after(i)
 7466                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7467                        )
 7468                    } else {
 7469                        None
 7470                    }
 7471                })
 7472                .collect::<Vec<_>>();
 7473            let existing_newlines = snapshot
 7474                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7475                .filter_map(|fold| {
 7476                    if fold.placeholder.type_tag == Some(type_id) {
 7477                        Some(fold.range.start..fold.range.end)
 7478                    } else {
 7479                        None
 7480                    }
 7481                })
 7482                .collect::<Vec<_>>();
 7483
 7484            (new_newlines, existing_newlines)
 7485        });
 7486        self.folding_newlines = cx.spawn(async move |this, cx| {
 7487            let (new_newlines, existing_newlines) = task.await;
 7488            if new_newlines == existing_newlines {
 7489                return;
 7490            }
 7491            let placeholder = FoldPlaceholder {
 7492                render: Arc::new(move |_, _, cx| {
 7493                    div()
 7494                        .bg(cx.theme().status().hint_background)
 7495                        .border_b_1()
 7496                        .size_full()
 7497                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7498                        .border_color(cx.theme().status().hint)
 7499                        .child("\\n")
 7500                        .into_any()
 7501                }),
 7502                constrain_width: false,
 7503                merge_adjacent: false,
 7504                type_tag: Some(type_id),
 7505            };
 7506            let creases = new_newlines
 7507                .into_iter()
 7508                .map(|range| Crease::simple(range, placeholder.clone()))
 7509                .collect();
 7510            this.update(cx, |this, cx| {
 7511                this.display_map.update(cx, |display_map, cx| {
 7512                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7513                    display_map.fold(creases, cx);
 7514                });
 7515            })
 7516            .ok();
 7517        });
 7518    }
 7519
 7520    #[ztracing::instrument(skip_all)]
 7521    fn refresh_selected_text_highlights(
 7522        &mut self,
 7523        on_buffer_edit: bool,
 7524        window: &mut Window,
 7525        cx: &mut Context<Editor>,
 7526    ) {
 7527        let Some((query_text, query_range)) =
 7528            self.prepare_highlight_query_from_selection(window, cx)
 7529        else {
 7530            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7531            self.quick_selection_highlight_task.take();
 7532            self.debounced_selection_highlight_task.take();
 7533            self.debounced_selection_highlight_complete = false;
 7534            return;
 7535        };
 7536        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7537        let query_changed = self
 7538            .quick_selection_highlight_task
 7539            .as_ref()
 7540            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7541        if query_changed {
 7542            self.debounced_selection_highlight_complete = false;
 7543        }
 7544        if on_buffer_edit || query_changed {
 7545            let multi_buffer_visible_start = self
 7546                .scroll_manager
 7547                .anchor()
 7548                .anchor
 7549                .to_point(&multi_buffer_snapshot);
 7550            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7551                multi_buffer_visible_start
 7552                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7553                Bias::Left,
 7554            );
 7555            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7556            self.quick_selection_highlight_task = Some((
 7557                query_range.clone(),
 7558                self.update_selection_occurrence_highlights(
 7559                    query_text.clone(),
 7560                    query_range.clone(),
 7561                    multi_buffer_visible_range,
 7562                    false,
 7563                    window,
 7564                    cx,
 7565                ),
 7566            ));
 7567        }
 7568        if on_buffer_edit
 7569            || self
 7570                .debounced_selection_highlight_task
 7571                .as_ref()
 7572                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7573        {
 7574            let multi_buffer_start = multi_buffer_snapshot
 7575                .anchor_before(MultiBufferOffset(0))
 7576                .to_point(&multi_buffer_snapshot);
 7577            let multi_buffer_end = multi_buffer_snapshot
 7578                .anchor_after(multi_buffer_snapshot.len())
 7579                .to_point(&multi_buffer_snapshot);
 7580            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7581            self.debounced_selection_highlight_task = Some((
 7582                query_range.clone(),
 7583                self.update_selection_occurrence_highlights(
 7584                    query_text,
 7585                    query_range,
 7586                    multi_buffer_full_range,
 7587                    true,
 7588                    window,
 7589                    cx,
 7590                ),
 7591            ));
 7592        }
 7593    }
 7594
 7595    pub fn refresh_edit_prediction(
 7596        &mut self,
 7597        debounce: bool,
 7598        user_requested: bool,
 7599        window: &mut Window,
 7600        cx: &mut Context<Self>,
 7601    ) -> Option<()> {
 7602        if DisableAiSettings::get_global(cx).disable_ai {
 7603            return None;
 7604        }
 7605
 7606        let provider = self.edit_prediction_provider()?;
 7607        let cursor = self.selections.newest_anchor().head();
 7608        let (buffer, cursor_buffer_position) =
 7609            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7610
 7611        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7612            self.discard_edit_prediction(false, cx);
 7613            return None;
 7614        }
 7615
 7616        self.update_visible_edit_prediction(window, cx);
 7617
 7618        if !user_requested
 7619            && (!self.should_show_edit_predictions()
 7620                || !self.is_focused(window)
 7621                || buffer.read(cx).is_empty())
 7622        {
 7623            self.discard_edit_prediction(false, cx);
 7624            return None;
 7625        }
 7626
 7627        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7628        Some(())
 7629    }
 7630
 7631    fn show_edit_predictions_in_menu(&self) -> bool {
 7632        match self.edit_prediction_settings {
 7633            EditPredictionSettings::Disabled => false,
 7634            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7635        }
 7636    }
 7637
 7638    pub fn edit_predictions_enabled(&self) -> bool {
 7639        match self.edit_prediction_settings {
 7640            EditPredictionSettings::Disabled => false,
 7641            EditPredictionSettings::Enabled { .. } => true,
 7642        }
 7643    }
 7644
 7645    fn edit_prediction_requires_modifier(&self) -> bool {
 7646        match self.edit_prediction_settings {
 7647            EditPredictionSettings::Disabled => false,
 7648            EditPredictionSettings::Enabled {
 7649                preview_requires_modifier,
 7650                ..
 7651            } => preview_requires_modifier,
 7652        }
 7653    }
 7654
 7655    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7656        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7657            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7658            self.discard_edit_prediction(false, cx);
 7659        } else {
 7660            let selection = self.selections.newest_anchor();
 7661            let cursor = selection.head();
 7662
 7663            if let Some((buffer, cursor_buffer_position)) =
 7664                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7665            {
 7666                self.edit_prediction_settings =
 7667                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7668            }
 7669        }
 7670    }
 7671
 7672    fn edit_prediction_settings_at_position(
 7673        &self,
 7674        buffer: &Entity<Buffer>,
 7675        buffer_position: language::Anchor,
 7676        cx: &App,
 7677    ) -> EditPredictionSettings {
 7678        if !self.mode.is_full()
 7679            || !self.show_edit_predictions_override.unwrap_or(true)
 7680            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7681        {
 7682            return EditPredictionSettings::Disabled;
 7683        }
 7684
 7685        let buffer = buffer.read(cx);
 7686
 7687        let file = buffer.file();
 7688
 7689        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7690            return EditPredictionSettings::Disabled;
 7691        };
 7692
 7693        let by_provider = matches!(
 7694            self.menu_edit_predictions_policy,
 7695            MenuEditPredictionsPolicy::ByProvider
 7696        );
 7697
 7698        let show_in_menu = by_provider
 7699            && self
 7700                .edit_prediction_provider
 7701                .as_ref()
 7702                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7703
 7704        let preview_requires_modifier =
 7705            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7706
 7707        EditPredictionSettings::Enabled {
 7708            show_in_menu,
 7709            preview_requires_modifier,
 7710        }
 7711    }
 7712
 7713    fn should_show_edit_predictions(&self) -> bool {
 7714        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7715    }
 7716
 7717    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7718        matches!(
 7719            self.edit_prediction_preview,
 7720            EditPredictionPreview::Active { .. }
 7721        )
 7722    }
 7723
 7724    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7725        let cursor = self.selections.newest_anchor().head();
 7726        if let Some((buffer, cursor_position)) =
 7727            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7728        {
 7729            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7730        } else {
 7731            false
 7732        }
 7733    }
 7734
 7735    pub fn supports_minimap(&self, cx: &App) -> bool {
 7736        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7737    }
 7738
 7739    fn edit_predictions_enabled_in_buffer(
 7740        &self,
 7741        buffer: &Entity<Buffer>,
 7742        buffer_position: language::Anchor,
 7743        cx: &App,
 7744    ) -> bool {
 7745        maybe!({
 7746            if self.read_only(cx) {
 7747                return Some(false);
 7748            }
 7749            let provider = self.edit_prediction_provider()?;
 7750            if !provider.is_enabled(buffer, buffer_position, cx) {
 7751                return Some(false);
 7752            }
 7753            let buffer = buffer.read(cx);
 7754            let Some(file) = buffer.file() else {
 7755                return Some(true);
 7756            };
 7757            let settings = all_language_settings(Some(file), cx);
 7758            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7759        })
 7760        .unwrap_or(false)
 7761    }
 7762
 7763    pub fn show_edit_prediction(
 7764        &mut self,
 7765        _: &ShowEditPrediction,
 7766        window: &mut Window,
 7767        cx: &mut Context<Self>,
 7768    ) {
 7769        if !self.has_active_edit_prediction() {
 7770            self.refresh_edit_prediction(false, true, window, cx);
 7771            return;
 7772        }
 7773
 7774        self.update_visible_edit_prediction(window, cx);
 7775    }
 7776
 7777    pub fn display_cursor_names(
 7778        &mut self,
 7779        _: &DisplayCursorNames,
 7780        window: &mut Window,
 7781        cx: &mut Context<Self>,
 7782    ) {
 7783        self.show_cursor_names(window, cx);
 7784    }
 7785
 7786    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7787        self.show_cursor_names = true;
 7788        cx.notify();
 7789        cx.spawn_in(window, async move |this, cx| {
 7790            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7791            this.update(cx, |this, cx| {
 7792                this.show_cursor_names = false;
 7793                cx.notify()
 7794            })
 7795            .ok()
 7796        })
 7797        .detach();
 7798    }
 7799
 7800    pub fn accept_partial_edit_prediction(
 7801        &mut self,
 7802        granularity: EditPredictionGranularity,
 7803        window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) {
 7806        if self.show_edit_predictions_in_menu() {
 7807            self.hide_context_menu(window, cx);
 7808        }
 7809
 7810        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7811            return;
 7812        };
 7813
 7814        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7815            return;
 7816        }
 7817
 7818        match &active_edit_prediction.completion {
 7819            EditPrediction::MoveWithin { target, .. } => {
 7820                let target = *target;
 7821
 7822                if matches!(granularity, EditPredictionGranularity::Full) {
 7823                    if let Some(position_map) = &self.last_position_map {
 7824                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7825                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7826
 7827                        if is_visible || !self.edit_prediction_requires_modifier() {
 7828                            self.unfold_ranges(&[target..target], true, false, cx);
 7829                            self.change_selections(
 7830                                SelectionEffects::scroll(Autoscroll::newest()),
 7831                                window,
 7832                                cx,
 7833                                |selections| {
 7834                                    selections.select_anchor_ranges([target..target]);
 7835                                },
 7836                            );
 7837                            self.clear_row_highlights::<EditPredictionPreview>();
 7838                            self.edit_prediction_preview
 7839                                .set_previous_scroll_position(None);
 7840                        } else {
 7841                            // Highlight and request scroll
 7842                            self.edit_prediction_preview
 7843                                .set_previous_scroll_position(Some(
 7844                                    position_map.snapshot.scroll_anchor,
 7845                                ));
 7846                            self.highlight_rows::<EditPredictionPreview>(
 7847                                target..target,
 7848                                cx.theme().colors().editor_highlighted_line_background,
 7849                                RowHighlightOptions {
 7850                                    autoscroll: true,
 7851                                    ..Default::default()
 7852                                },
 7853                                cx,
 7854                            );
 7855                            self.request_autoscroll(Autoscroll::fit(), cx);
 7856                        }
 7857                    }
 7858                } else {
 7859                    self.change_selections(
 7860                        SelectionEffects::scroll(Autoscroll::newest()),
 7861                        window,
 7862                        cx,
 7863                        |selections| {
 7864                            selections.select_anchor_ranges([target..target]);
 7865                        },
 7866                    );
 7867                }
 7868            }
 7869            EditPrediction::MoveOutside { snapshot, target } => {
 7870                if let Some(workspace) = self.workspace() {
 7871                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7872                        .detach_and_log_err(cx);
 7873                }
 7874            }
 7875            EditPrediction::Edit { edits, .. } => {
 7876                self.report_edit_prediction_event(
 7877                    active_edit_prediction.completion_id.clone(),
 7878                    true,
 7879                    cx,
 7880                );
 7881
 7882                match granularity {
 7883                    EditPredictionGranularity::Full => {
 7884                        if let Some(provider) = self.edit_prediction_provider() {
 7885                            provider.accept(cx);
 7886                        }
 7887
 7888                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7889                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7890                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7891
 7892                        self.buffer.update(cx, |buffer, cx| {
 7893                            buffer.edit(edits.iter().cloned(), None, cx)
 7894                        });
 7895
 7896                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7897                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7898                        });
 7899
 7900                        let selections = self.selections.disjoint_anchors_arc();
 7901                        if let Some(transaction_id_now) =
 7902                            self.buffer.read(cx).last_transaction_id(cx)
 7903                        {
 7904                            if transaction_id_prev != Some(transaction_id_now) {
 7905                                self.selection_history
 7906                                    .insert_transaction(transaction_id_now, selections);
 7907                            }
 7908                        }
 7909
 7910                        self.update_visible_edit_prediction(window, cx);
 7911                        if self.active_edit_prediction.is_none() {
 7912                            self.refresh_edit_prediction(true, true, window, cx);
 7913                        }
 7914                        cx.notify();
 7915                    }
 7916                    _ => {
 7917                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7918                        let cursor_offset = self
 7919                            .selections
 7920                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7921                            .head();
 7922
 7923                        let insertion = edits.iter().find_map(|(range, text)| {
 7924                            let range = range.to_offset(&snapshot);
 7925                            if range.is_empty() && range.start == cursor_offset {
 7926                                Some(text)
 7927                            } else {
 7928                                None
 7929                            }
 7930                        });
 7931
 7932                        if let Some(text) = insertion {
 7933                            let text_to_insert = match granularity {
 7934                                EditPredictionGranularity::Word => {
 7935                                    let mut partial = text
 7936                                        .chars()
 7937                                        .by_ref()
 7938                                        .take_while(|c| c.is_alphabetic())
 7939                                        .collect::<String>();
 7940                                    if partial.is_empty() {
 7941                                        partial = text
 7942                                            .chars()
 7943                                            .by_ref()
 7944                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7945                                            .collect::<String>();
 7946                                    }
 7947                                    partial
 7948                                }
 7949                                EditPredictionGranularity::Line => {
 7950                                    if let Some(line) = text.split_inclusive('\n').next() {
 7951                                        line.to_string()
 7952                                    } else {
 7953                                        text.to_string()
 7954                                    }
 7955                                }
 7956                                EditPredictionGranularity::Full => unreachable!(),
 7957                            };
 7958
 7959                            cx.emit(EditorEvent::InputHandled {
 7960                                utf16_range_to_replace: None,
 7961                                text: text_to_insert.clone().into(),
 7962                            });
 7963
 7964                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7965                            self.refresh_edit_prediction(true, true, window, cx);
 7966                            cx.notify();
 7967                        } else {
 7968                            self.accept_partial_edit_prediction(
 7969                                EditPredictionGranularity::Full,
 7970                                window,
 7971                                cx,
 7972                            );
 7973                        }
 7974                    }
 7975                }
 7976            }
 7977        }
 7978
 7979        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7980    }
 7981
 7982    pub fn accept_next_word_edit_prediction(
 7983        &mut self,
 7984        _: &AcceptNextWordEditPrediction,
 7985        window: &mut Window,
 7986        cx: &mut Context<Self>,
 7987    ) {
 7988        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7989    }
 7990
 7991    pub fn accept_next_line_edit_prediction(
 7992        &mut self,
 7993        _: &AcceptNextLineEditPrediction,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) {
 7997        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7998    }
 7999
 8000    pub fn accept_edit_prediction(
 8001        &mut self,
 8002        _: &AcceptEditPrediction,
 8003        window: &mut Window,
 8004        cx: &mut Context<Self>,
 8005    ) {
 8006        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8007    }
 8008
 8009    fn discard_edit_prediction(
 8010        &mut self,
 8011        should_report_edit_prediction_event: bool,
 8012        cx: &mut Context<Self>,
 8013    ) -> bool {
 8014        if should_report_edit_prediction_event {
 8015            let completion_id = self
 8016                .active_edit_prediction
 8017                .as_ref()
 8018                .and_then(|active_completion| active_completion.completion_id.clone());
 8019
 8020            self.report_edit_prediction_event(completion_id, false, cx);
 8021        }
 8022
 8023        if let Some(provider) = self.edit_prediction_provider() {
 8024            provider.discard(cx);
 8025        }
 8026
 8027        self.take_active_edit_prediction(cx)
 8028    }
 8029
 8030    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8031        let Some(provider) = self.edit_prediction_provider() else {
 8032            return;
 8033        };
 8034
 8035        let Some((_, buffer, _)) = self
 8036            .buffer
 8037            .read(cx)
 8038            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8039        else {
 8040            return;
 8041        };
 8042
 8043        let extension = buffer
 8044            .read(cx)
 8045            .file()
 8046            .and_then(|file| Some(file.path().extension()?.to_string()));
 8047
 8048        let event_type = match accepted {
 8049            true => "Edit Prediction Accepted",
 8050            false => "Edit Prediction Discarded",
 8051        };
 8052        telemetry::event!(
 8053            event_type,
 8054            provider = provider.name(),
 8055            prediction_id = id,
 8056            suggestion_accepted = accepted,
 8057            file_extension = extension,
 8058        );
 8059    }
 8060
 8061    fn open_editor_at_anchor(
 8062        snapshot: &language::BufferSnapshot,
 8063        target: language::Anchor,
 8064        workspace: &Entity<Workspace>,
 8065        window: &mut Window,
 8066        cx: &mut App,
 8067    ) -> Task<Result<()>> {
 8068        workspace.update(cx, |workspace, cx| {
 8069            let path = snapshot.file().map(|file| file.full_path(cx));
 8070            let Some(path) =
 8071                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8072            else {
 8073                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8074            };
 8075            let target = text::ToPoint::to_point(&target, snapshot);
 8076            let item = workspace.open_path(path, None, true, window, cx);
 8077            window.spawn(cx, async move |cx| {
 8078                let Some(editor) = item.await?.downcast::<Editor>() else {
 8079                    return Ok(());
 8080                };
 8081                editor
 8082                    .update_in(cx, |editor, window, cx| {
 8083                        editor.go_to_singleton_buffer_point(target, window, cx);
 8084                    })
 8085                    .ok();
 8086                anyhow::Ok(())
 8087            })
 8088        })
 8089    }
 8090
 8091    pub fn has_active_edit_prediction(&self) -> bool {
 8092        self.active_edit_prediction.is_some()
 8093    }
 8094
 8095    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8096        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8097            return false;
 8098        };
 8099
 8100        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8101        self.clear_highlights::<EditPredictionHighlight>(cx);
 8102        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8103        true
 8104    }
 8105
 8106    /// Returns true when we're displaying the edit prediction popover below the cursor
 8107    /// like we are not previewing and the LSP autocomplete menu is visible
 8108    /// or we are in `when_holding_modifier` mode.
 8109    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8110        if self.edit_prediction_preview_is_active()
 8111            || !self.show_edit_predictions_in_menu()
 8112            || !self.edit_predictions_enabled()
 8113        {
 8114            return false;
 8115        }
 8116
 8117        if self.has_visible_completions_menu() {
 8118            return true;
 8119        }
 8120
 8121        has_completion && self.edit_prediction_requires_modifier()
 8122    }
 8123
 8124    fn handle_modifiers_changed(
 8125        &mut self,
 8126        modifiers: Modifiers,
 8127        position_map: &PositionMap,
 8128        window: &mut Window,
 8129        cx: &mut Context<Self>,
 8130    ) {
 8131        // Ensure that the edit prediction preview is updated, even when not
 8132        // enabled, if there's an active edit prediction preview.
 8133        if self.show_edit_predictions_in_menu()
 8134            || matches!(
 8135                self.edit_prediction_preview,
 8136                EditPredictionPreview::Active { .. }
 8137            )
 8138        {
 8139            self.update_edit_prediction_preview(&modifiers, window, cx);
 8140        }
 8141
 8142        self.update_selection_mode(&modifiers, position_map, window, cx);
 8143
 8144        let mouse_position = window.mouse_position();
 8145        if !position_map.text_hitbox.is_hovered(window) {
 8146            return;
 8147        }
 8148
 8149        self.update_hovered_link(
 8150            position_map.point_for_position(mouse_position),
 8151            &position_map.snapshot,
 8152            modifiers,
 8153            window,
 8154            cx,
 8155        )
 8156    }
 8157
 8158    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8159        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8160            MultiCursorModifier::Alt => modifiers.secondary(),
 8161            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8162        }
 8163    }
 8164
 8165    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8166        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8167            MultiCursorModifier::Alt => modifiers.alt,
 8168            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8169        }
 8170    }
 8171
 8172    fn columnar_selection_mode(
 8173        modifiers: &Modifiers,
 8174        cx: &mut Context<Self>,
 8175    ) -> Option<ColumnarMode> {
 8176        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8177            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8178                Some(ColumnarMode::FromMouse)
 8179            } else if Self::is_alt_pressed(modifiers, cx) {
 8180                Some(ColumnarMode::FromSelection)
 8181            } else {
 8182                None
 8183            }
 8184        } else {
 8185            None
 8186        }
 8187    }
 8188
 8189    fn update_selection_mode(
 8190        &mut self,
 8191        modifiers: &Modifiers,
 8192        position_map: &PositionMap,
 8193        window: &mut Window,
 8194        cx: &mut Context<Self>,
 8195    ) {
 8196        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8197            return;
 8198        };
 8199        if self.selections.pending_anchor().is_none() {
 8200            return;
 8201        }
 8202
 8203        let mouse_position = window.mouse_position();
 8204        let point_for_position = position_map.point_for_position(mouse_position);
 8205        let position = point_for_position.previous_valid;
 8206
 8207        self.select(
 8208            SelectPhase::BeginColumnar {
 8209                position,
 8210                reset: false,
 8211                mode,
 8212                goal_column: point_for_position.exact_unclipped.column(),
 8213            },
 8214            window,
 8215            cx,
 8216        );
 8217    }
 8218
 8219    fn update_edit_prediction_preview(
 8220        &mut self,
 8221        modifiers: &Modifiers,
 8222        window: &mut Window,
 8223        cx: &mut Context<Self>,
 8224    ) {
 8225        let mut modifiers_held = false;
 8226
 8227        // Check bindings for all granularities.
 8228        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8229        let granularities = [
 8230            EditPredictionGranularity::Full,
 8231            EditPredictionGranularity::Line,
 8232            EditPredictionGranularity::Word,
 8233        ];
 8234
 8235        for granularity in granularities {
 8236            if let Some(keystroke) = self
 8237                .accept_edit_prediction_keybind(granularity, window, cx)
 8238                .keystroke()
 8239            {
 8240                modifiers_held = modifiers_held
 8241                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8242            }
 8243        }
 8244
 8245        if modifiers_held {
 8246            if matches!(
 8247                self.edit_prediction_preview,
 8248                EditPredictionPreview::Inactive { .. }
 8249            ) {
 8250                self.edit_prediction_preview = EditPredictionPreview::Active {
 8251                    previous_scroll_position: None,
 8252                    since: Instant::now(),
 8253                };
 8254
 8255                self.update_visible_edit_prediction(window, cx);
 8256                cx.notify();
 8257            }
 8258        } else if let EditPredictionPreview::Active {
 8259            previous_scroll_position,
 8260            since,
 8261        } = self.edit_prediction_preview
 8262        {
 8263            if let (Some(previous_scroll_position), Some(position_map)) =
 8264                (previous_scroll_position, self.last_position_map.as_ref())
 8265            {
 8266                self.set_scroll_position(
 8267                    previous_scroll_position
 8268                        .scroll_position(&position_map.snapshot.display_snapshot),
 8269                    window,
 8270                    cx,
 8271                );
 8272            }
 8273
 8274            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8275                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8276            };
 8277            self.clear_row_highlights::<EditPredictionPreview>();
 8278            self.update_visible_edit_prediction(window, cx);
 8279            cx.notify();
 8280        }
 8281    }
 8282
 8283    fn update_visible_edit_prediction(
 8284        &mut self,
 8285        _window: &mut Window,
 8286        cx: &mut Context<Self>,
 8287    ) -> Option<()> {
 8288        if DisableAiSettings::get_global(cx).disable_ai {
 8289            return None;
 8290        }
 8291
 8292        if self.ime_transaction.is_some() {
 8293            self.discard_edit_prediction(false, cx);
 8294            return None;
 8295        }
 8296
 8297        let selection = self.selections.newest_anchor();
 8298        let cursor = selection.head();
 8299        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8300        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8301        let excerpt_id = cursor.excerpt_id;
 8302
 8303        let show_in_menu = self.show_edit_predictions_in_menu();
 8304        let completions_menu_has_precedence = !show_in_menu
 8305            && (self.context_menu.borrow().is_some()
 8306                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8307
 8308        if completions_menu_has_precedence
 8309            || !offset_selection.is_empty()
 8310            || self
 8311                .active_edit_prediction
 8312                .as_ref()
 8313                .is_some_and(|completion| {
 8314                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8315                        return false;
 8316                    };
 8317                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8318                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8319                    !invalidation_range.contains(&offset_selection.head())
 8320                })
 8321        {
 8322            self.discard_edit_prediction(false, cx);
 8323            return None;
 8324        }
 8325
 8326        self.take_active_edit_prediction(cx);
 8327        let Some(provider) = self.edit_prediction_provider() else {
 8328            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8329            return None;
 8330        };
 8331
 8332        let (buffer, cursor_buffer_position) =
 8333            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8334
 8335        self.edit_prediction_settings =
 8336            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8337
 8338        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8339
 8340        if self.edit_prediction_indent_conflict {
 8341            let cursor_point = cursor.to_point(&multibuffer);
 8342            let mut suggested_indent = None;
 8343            multibuffer.suggested_indents_callback(
 8344                cursor_point.row..cursor_point.row + 1,
 8345                |_, indent| {
 8346                    suggested_indent = Some(indent);
 8347                    ControlFlow::Break(())
 8348                },
 8349                cx,
 8350            );
 8351
 8352            if let Some(indent) = suggested_indent
 8353                && indent.len == cursor_point.column
 8354            {
 8355                self.edit_prediction_indent_conflict = false;
 8356            }
 8357        }
 8358
 8359        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8360
 8361        let (completion_id, edits, edit_preview) = match edit_prediction {
 8362            edit_prediction_types::EditPrediction::Local {
 8363                id,
 8364                edits,
 8365                edit_preview,
 8366            } => (id, edits, edit_preview),
 8367            edit_prediction_types::EditPrediction::Jump {
 8368                id,
 8369                snapshot,
 8370                target,
 8371            } => {
 8372                if let Some(provider) = &self.edit_prediction_provider {
 8373                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8374                }
 8375                self.stale_edit_prediction_in_menu = None;
 8376                self.active_edit_prediction = Some(EditPredictionState {
 8377                    inlay_ids: vec![],
 8378                    completion: EditPrediction::MoveOutside { snapshot, target },
 8379                    completion_id: id,
 8380                    invalidation_range: None,
 8381                });
 8382                cx.notify();
 8383                return Some(());
 8384            }
 8385        };
 8386
 8387        let edits = edits
 8388            .into_iter()
 8389            .flat_map(|(range, new_text)| {
 8390                Some((
 8391                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8392                    new_text,
 8393                ))
 8394            })
 8395            .collect::<Vec<_>>();
 8396        if edits.is_empty() {
 8397            return None;
 8398        }
 8399
 8400        let first_edit_start = edits.first().unwrap().0.start;
 8401        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8402        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8403
 8404        let last_edit_end = edits.last().unwrap().0.end;
 8405        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8406        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8407
 8408        let cursor_row = cursor.to_point(&multibuffer).row;
 8409
 8410        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8411
 8412        let mut inlay_ids = Vec::new();
 8413        let invalidation_row_range;
 8414        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8415            Some(cursor_row..edit_end_row)
 8416        } else if cursor_row > edit_end_row {
 8417            Some(edit_start_row..cursor_row)
 8418        } else {
 8419            None
 8420        };
 8421        let supports_jump = self
 8422            .edit_prediction_provider
 8423            .as_ref()
 8424            .map(|provider| provider.provider.supports_jump_to_edit())
 8425            .unwrap_or(true);
 8426
 8427        let is_move = supports_jump
 8428            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8429        let completion = if is_move {
 8430            if let Some(provider) = &self.edit_prediction_provider {
 8431                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8432            }
 8433            invalidation_row_range =
 8434                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8435            let target = first_edit_start;
 8436            EditPrediction::MoveWithin { target, snapshot }
 8437        } else {
 8438            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8439                && !self.edit_predictions_hidden_for_vim_mode;
 8440
 8441            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8442                if provider.show_tab_accept_marker() {
 8443                    EditDisplayMode::TabAccept
 8444                } else {
 8445                    EditDisplayMode::Inline
 8446                }
 8447            } else {
 8448                EditDisplayMode::DiffPopover
 8449            };
 8450
 8451            if show_completions_in_buffer {
 8452                if let Some(provider) = &self.edit_prediction_provider {
 8453                    let suggestion_display_type = match display_mode {
 8454                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8455                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8456                            SuggestionDisplayType::GhostText
 8457                        }
 8458                    };
 8459                    provider.provider.did_show(suggestion_display_type, cx);
 8460                }
 8461                if edits
 8462                    .iter()
 8463                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8464                {
 8465                    let mut inlays = Vec::new();
 8466                    for (range, new_text) in &edits {
 8467                        let inlay = Inlay::edit_prediction(
 8468                            post_inc(&mut self.next_inlay_id),
 8469                            range.start,
 8470                            new_text.as_ref(),
 8471                        );
 8472                        inlay_ids.push(inlay.id);
 8473                        inlays.push(inlay);
 8474                    }
 8475
 8476                    self.splice_inlays(&[], inlays, cx);
 8477                } else {
 8478                    let background_color = cx.theme().status().deleted_background;
 8479                    self.highlight_text::<EditPredictionHighlight>(
 8480                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8481                        HighlightStyle {
 8482                            background_color: Some(background_color),
 8483                            ..Default::default()
 8484                        },
 8485                        cx,
 8486                    );
 8487                }
 8488            }
 8489
 8490            invalidation_row_range = edit_start_row..edit_end_row;
 8491
 8492            EditPrediction::Edit {
 8493                edits,
 8494                edit_preview,
 8495                display_mode,
 8496                snapshot,
 8497            }
 8498        };
 8499
 8500        let invalidation_range = multibuffer
 8501            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8502            ..multibuffer.anchor_after(Point::new(
 8503                invalidation_row_range.end,
 8504                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8505            ));
 8506
 8507        self.stale_edit_prediction_in_menu = None;
 8508        self.active_edit_prediction = Some(EditPredictionState {
 8509            inlay_ids,
 8510            completion,
 8511            completion_id,
 8512            invalidation_range: Some(invalidation_range),
 8513        });
 8514
 8515        cx.notify();
 8516
 8517        Some(())
 8518    }
 8519
 8520    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8521        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8522    }
 8523
 8524    fn clear_tasks(&mut self) {
 8525        self.tasks.clear()
 8526    }
 8527
 8528    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8529        if self.tasks.insert(key, value).is_some() {
 8530            // This case should hopefully be rare, but just in case...
 8531            log::error!(
 8532                "multiple different run targets found on a single line, only the last target will be rendered"
 8533            )
 8534        }
 8535    }
 8536
 8537    /// Get all display points of breakpoints that will be rendered within editor
 8538    ///
 8539    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8540    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8541    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8542    fn active_breakpoints(
 8543        &self,
 8544        range: Range<DisplayRow>,
 8545        window: &mut Window,
 8546        cx: &mut Context<Self>,
 8547    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8548        let mut breakpoint_display_points = HashMap::default();
 8549
 8550        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8551            return breakpoint_display_points;
 8552        };
 8553
 8554        let snapshot = self.snapshot(window, cx);
 8555
 8556        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8557        let Some(project) = self.project() else {
 8558            return breakpoint_display_points;
 8559        };
 8560
 8561        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8562            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8563
 8564        for (buffer_snapshot, range, excerpt_id) in
 8565            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8566        {
 8567            let Some(buffer) = project
 8568                .read(cx)
 8569                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8570            else {
 8571                continue;
 8572            };
 8573            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8574                &buffer,
 8575                Some(
 8576                    buffer_snapshot.anchor_before(range.start)
 8577                        ..buffer_snapshot.anchor_after(range.end),
 8578                ),
 8579                buffer_snapshot,
 8580                cx,
 8581            );
 8582            for (breakpoint, state) in breakpoints {
 8583                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8584                let position = multi_buffer_anchor
 8585                    .to_point(&multi_buffer_snapshot)
 8586                    .to_display_point(&snapshot);
 8587
 8588                breakpoint_display_points.insert(
 8589                    position.row(),
 8590                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8591                );
 8592            }
 8593        }
 8594
 8595        breakpoint_display_points
 8596    }
 8597
 8598    fn breakpoint_context_menu(
 8599        &self,
 8600        anchor: Anchor,
 8601        window: &mut Window,
 8602        cx: &mut Context<Self>,
 8603    ) -> Entity<ui::ContextMenu> {
 8604        let weak_editor = cx.weak_entity();
 8605        let focus_handle = self.focus_handle(cx);
 8606
 8607        let row = self
 8608            .buffer
 8609            .read(cx)
 8610            .snapshot(cx)
 8611            .summary_for_anchor::<Point>(&anchor)
 8612            .row;
 8613
 8614        let breakpoint = self
 8615            .breakpoint_at_row(row, window, cx)
 8616            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8617
 8618        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8619            "Edit Log Breakpoint"
 8620        } else {
 8621            "Set Log Breakpoint"
 8622        };
 8623
 8624        let condition_breakpoint_msg = if breakpoint
 8625            .as_ref()
 8626            .is_some_and(|bp| bp.1.condition.is_some())
 8627        {
 8628            "Edit Condition Breakpoint"
 8629        } else {
 8630            "Set Condition Breakpoint"
 8631        };
 8632
 8633        let hit_condition_breakpoint_msg = if breakpoint
 8634            .as_ref()
 8635            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8636        {
 8637            "Edit Hit Condition Breakpoint"
 8638        } else {
 8639            "Set Hit Condition Breakpoint"
 8640        };
 8641
 8642        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8643            "Unset Breakpoint"
 8644        } else {
 8645            "Set Breakpoint"
 8646        };
 8647
 8648        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8649
 8650        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8651            BreakpointState::Enabled => Some("Disable"),
 8652            BreakpointState::Disabled => Some("Enable"),
 8653        });
 8654
 8655        let (anchor, breakpoint) =
 8656            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8657
 8658        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8659            menu.on_blur_subscription(Subscription::new(|| {}))
 8660                .context(focus_handle)
 8661                .when(run_to_cursor, |this| {
 8662                    let weak_editor = weak_editor.clone();
 8663                    this.entry("Run to cursor", None, move |window, cx| {
 8664                        weak_editor
 8665                            .update(cx, |editor, cx| {
 8666                                editor.change_selections(
 8667                                    SelectionEffects::no_scroll(),
 8668                                    window,
 8669                                    cx,
 8670                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8671                                );
 8672                            })
 8673                            .ok();
 8674
 8675                        window.dispatch_action(Box::new(RunToCursor), cx);
 8676                    })
 8677                    .separator()
 8678                })
 8679                .when_some(toggle_state_msg, |this, msg| {
 8680                    this.entry(msg, None, {
 8681                        let weak_editor = weak_editor.clone();
 8682                        let breakpoint = breakpoint.clone();
 8683                        move |_window, cx| {
 8684                            weak_editor
 8685                                .update(cx, |this, cx| {
 8686                                    this.edit_breakpoint_at_anchor(
 8687                                        anchor,
 8688                                        breakpoint.as_ref().clone(),
 8689                                        BreakpointEditAction::InvertState,
 8690                                        cx,
 8691                                    );
 8692                                })
 8693                                .log_err();
 8694                        }
 8695                    })
 8696                })
 8697                .entry(set_breakpoint_msg, None, {
 8698                    let weak_editor = weak_editor.clone();
 8699                    let breakpoint = breakpoint.clone();
 8700                    move |_window, cx| {
 8701                        weak_editor
 8702                            .update(cx, |this, cx| {
 8703                                this.edit_breakpoint_at_anchor(
 8704                                    anchor,
 8705                                    breakpoint.as_ref().clone(),
 8706                                    BreakpointEditAction::Toggle,
 8707                                    cx,
 8708                                );
 8709                            })
 8710                            .log_err();
 8711                    }
 8712                })
 8713                .entry(log_breakpoint_msg, None, {
 8714                    let breakpoint = breakpoint.clone();
 8715                    let weak_editor = weak_editor.clone();
 8716                    move |window, cx| {
 8717                        weak_editor
 8718                            .update(cx, |this, cx| {
 8719                                this.add_edit_breakpoint_block(
 8720                                    anchor,
 8721                                    breakpoint.as_ref(),
 8722                                    BreakpointPromptEditAction::Log,
 8723                                    window,
 8724                                    cx,
 8725                                );
 8726                            })
 8727                            .log_err();
 8728                    }
 8729                })
 8730                .entry(condition_breakpoint_msg, None, {
 8731                    let breakpoint = breakpoint.clone();
 8732                    let weak_editor = weak_editor.clone();
 8733                    move |window, cx| {
 8734                        weak_editor
 8735                            .update(cx, |this, cx| {
 8736                                this.add_edit_breakpoint_block(
 8737                                    anchor,
 8738                                    breakpoint.as_ref(),
 8739                                    BreakpointPromptEditAction::Condition,
 8740                                    window,
 8741                                    cx,
 8742                                );
 8743                            })
 8744                            .log_err();
 8745                    }
 8746                })
 8747                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8748                    weak_editor
 8749                        .update(cx, |this, cx| {
 8750                            this.add_edit_breakpoint_block(
 8751                                anchor,
 8752                                breakpoint.as_ref(),
 8753                                BreakpointPromptEditAction::HitCondition,
 8754                                window,
 8755                                cx,
 8756                            );
 8757                        })
 8758                        .log_err();
 8759                })
 8760        })
 8761    }
 8762
 8763    fn render_breakpoint(
 8764        &self,
 8765        position: Anchor,
 8766        row: DisplayRow,
 8767        breakpoint: &Breakpoint,
 8768        state: Option<BreakpointSessionState>,
 8769        cx: &mut Context<Self>,
 8770    ) -> IconButton {
 8771        let is_rejected = state.is_some_and(|s| !s.verified);
 8772        // Is it a breakpoint that shows up when hovering over gutter?
 8773        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8774            (false, false),
 8775            |PhantomBreakpointIndicator {
 8776                 is_active,
 8777                 display_row,
 8778                 collides_with_existing_breakpoint,
 8779             }| {
 8780                (
 8781                    is_active && display_row == row,
 8782                    collides_with_existing_breakpoint,
 8783                )
 8784            },
 8785        );
 8786
 8787        let (color, icon) = {
 8788            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8789                (false, false) => ui::IconName::DebugBreakpoint,
 8790                (true, false) => ui::IconName::DebugLogBreakpoint,
 8791                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8792                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8793            };
 8794
 8795            let theme_colors = cx.theme().colors();
 8796
 8797            let color = if is_phantom {
 8798                if collides_with_existing {
 8799                    Color::Custom(
 8800                        theme_colors
 8801                            .debugger_accent
 8802                            .blend(theme_colors.text.opacity(0.6)),
 8803                    )
 8804                } else {
 8805                    Color::Hint
 8806                }
 8807            } else if is_rejected {
 8808                Color::Disabled
 8809            } else {
 8810                Color::Debugger
 8811            };
 8812
 8813            (color, icon)
 8814        };
 8815
 8816        let breakpoint = Arc::from(breakpoint.clone());
 8817
 8818        let alt_as_text = gpui::Keystroke {
 8819            modifiers: Modifiers::secondary_key(),
 8820            ..Default::default()
 8821        };
 8822        let primary_action_text = if breakpoint.is_disabled() {
 8823            "Enable breakpoint"
 8824        } else if is_phantom && !collides_with_existing {
 8825            "Set breakpoint"
 8826        } else {
 8827            "Unset breakpoint"
 8828        };
 8829        let focus_handle = self.focus_handle.clone();
 8830
 8831        let meta = if is_rejected {
 8832            SharedString::from("No executable code is associated with this line.")
 8833        } else if collides_with_existing && !breakpoint.is_disabled() {
 8834            SharedString::from(format!(
 8835                "{alt_as_text}-click to disable,\nright-click for more options."
 8836            ))
 8837        } else {
 8838            SharedString::from("Right-click for more options.")
 8839        };
 8840        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8841            .icon_size(IconSize::XSmall)
 8842            .size(ui::ButtonSize::None)
 8843            .when(is_rejected, |this| {
 8844                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8845            })
 8846            .icon_color(color)
 8847            .style(ButtonStyle::Transparent)
 8848            .on_click(cx.listener({
 8849                move |editor, event: &ClickEvent, window, cx| {
 8850                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8851                        BreakpointEditAction::InvertState
 8852                    } else {
 8853                        BreakpointEditAction::Toggle
 8854                    };
 8855
 8856                    window.focus(&editor.focus_handle(cx), cx);
 8857                    editor.edit_breakpoint_at_anchor(
 8858                        position,
 8859                        breakpoint.as_ref().clone(),
 8860                        edit_action,
 8861                        cx,
 8862                    );
 8863                }
 8864            }))
 8865            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8866                editor.set_breakpoint_context_menu(
 8867                    row,
 8868                    Some(position),
 8869                    event.position(),
 8870                    window,
 8871                    cx,
 8872                );
 8873            }))
 8874            .tooltip(move |_window, cx| {
 8875                Tooltip::with_meta_in(
 8876                    primary_action_text,
 8877                    Some(&ToggleBreakpoint),
 8878                    meta.clone(),
 8879                    &focus_handle,
 8880                    cx,
 8881                )
 8882            })
 8883    }
 8884
 8885    fn build_tasks_context(
 8886        project: &Entity<Project>,
 8887        buffer: &Entity<Buffer>,
 8888        buffer_row: u32,
 8889        tasks: &Arc<RunnableTasks>,
 8890        cx: &mut Context<Self>,
 8891    ) -> Task<Option<task::TaskContext>> {
 8892        let position = Point::new(buffer_row, tasks.column);
 8893        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8894        let location = Location {
 8895            buffer: buffer.clone(),
 8896            range: range_start..range_start,
 8897        };
 8898        // Fill in the environmental variables from the tree-sitter captures
 8899        let mut captured_task_variables = TaskVariables::default();
 8900        for (capture_name, value) in tasks.extra_variables.clone() {
 8901            captured_task_variables.insert(
 8902                task::VariableName::Custom(capture_name.into()),
 8903                value.clone(),
 8904            );
 8905        }
 8906        project.update(cx, |project, cx| {
 8907            project.task_store().update(cx, |task_store, cx| {
 8908                task_store.task_context_for_location(captured_task_variables, location, cx)
 8909            })
 8910        })
 8911    }
 8912
 8913    pub fn spawn_nearest_task(
 8914        &mut self,
 8915        action: &SpawnNearestTask,
 8916        window: &mut Window,
 8917        cx: &mut Context<Self>,
 8918    ) {
 8919        let Some((workspace, _)) = self.workspace.clone() else {
 8920            return;
 8921        };
 8922        let Some(project) = self.project.clone() else {
 8923            return;
 8924        };
 8925
 8926        // Try to find a closest, enclosing node using tree-sitter that has a task
 8927        let Some((buffer, buffer_row, tasks)) = self
 8928            .find_enclosing_node_task(cx)
 8929            // Or find the task that's closest in row-distance.
 8930            .or_else(|| self.find_closest_task(cx))
 8931        else {
 8932            return;
 8933        };
 8934
 8935        let reveal_strategy = action.reveal;
 8936        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8937        cx.spawn_in(window, async move |_, cx| {
 8938            let context = task_context.await?;
 8939            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8940
 8941            let resolved = &mut resolved_task.resolved;
 8942            resolved.reveal = reveal_strategy;
 8943
 8944            workspace
 8945                .update_in(cx, |workspace, window, cx| {
 8946                    workspace.schedule_resolved_task(
 8947                        task_source_kind,
 8948                        resolved_task,
 8949                        false,
 8950                        window,
 8951                        cx,
 8952                    );
 8953                })
 8954                .ok()
 8955        })
 8956        .detach();
 8957    }
 8958
 8959    fn find_closest_task(
 8960        &mut self,
 8961        cx: &mut Context<Self>,
 8962    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8963        let cursor_row = self
 8964            .selections
 8965            .newest_adjusted(&self.display_snapshot(cx))
 8966            .head()
 8967            .row;
 8968
 8969        let ((buffer_id, row), tasks) = self
 8970            .tasks
 8971            .iter()
 8972            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8973
 8974        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8975        let tasks = Arc::new(tasks.to_owned());
 8976        Some((buffer, *row, tasks))
 8977    }
 8978
 8979    fn find_enclosing_node_task(
 8980        &mut self,
 8981        cx: &mut Context<Self>,
 8982    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8983        let snapshot = self.buffer.read(cx).snapshot(cx);
 8984        let offset = self
 8985            .selections
 8986            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8987            .head();
 8988        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8989        let offset = excerpt.map_offset_to_buffer(offset);
 8990        let buffer_id = excerpt.buffer().remote_id();
 8991
 8992        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8993        let mut cursor = layer.node().walk();
 8994
 8995        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8996            if cursor.node().end_byte() == offset.0 {
 8997                cursor.goto_next_sibling();
 8998            }
 8999        }
 9000
 9001        // Ascend to the smallest ancestor that contains the range and has a task.
 9002        loop {
 9003            let node = cursor.node();
 9004            let node_range = node.byte_range();
 9005            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 9006
 9007            // Check if this node contains our offset
 9008            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 9009                // If it contains offset, check for task
 9010                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 9011                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 9012                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 9013                }
 9014            }
 9015
 9016            if !cursor.goto_parent() {
 9017                break;
 9018            }
 9019        }
 9020        None
 9021    }
 9022
 9023    fn render_run_indicator(
 9024        &self,
 9025        _style: &EditorStyle,
 9026        is_active: bool,
 9027        row: DisplayRow,
 9028        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 9029        cx: &mut Context<Self>,
 9030    ) -> IconButton {
 9031        let color = Color::Muted;
 9032        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 9033
 9034        IconButton::new(
 9035            ("run_indicator", row.0 as usize),
 9036            ui::IconName::PlayOutlined,
 9037        )
 9038        .shape(ui::IconButtonShape::Square)
 9039        .icon_size(IconSize::XSmall)
 9040        .icon_color(color)
 9041        .toggle_state(is_active)
 9042        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 9043            let quick_launch = match e {
 9044                ClickEvent::Keyboard(_) => true,
 9045                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 9046            };
 9047
 9048            window.focus(&editor.focus_handle(cx), cx);
 9049            editor.toggle_code_actions(
 9050                &ToggleCodeActions {
 9051                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 9052                    quick_launch,
 9053                },
 9054                window,
 9055                cx,
 9056            );
 9057        }))
 9058        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9059            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 9060        }))
 9061    }
 9062
 9063    pub fn context_menu_visible(&self) -> bool {
 9064        !self.edit_prediction_preview_is_active()
 9065            && self
 9066                .context_menu
 9067                .borrow()
 9068                .as_ref()
 9069                .is_some_and(|menu| menu.visible())
 9070    }
 9071
 9072    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9073        self.context_menu
 9074            .borrow()
 9075            .as_ref()
 9076            .map(|menu| menu.origin())
 9077    }
 9078
 9079    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9080        self.context_menu_options = Some(options);
 9081    }
 9082
 9083    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9084    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9085
 9086    fn render_edit_prediction_popover(
 9087        &mut self,
 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        scroll_top: ScrollOffset,
 9094        scroll_bottom: ScrollOffset,
 9095        line_layouts: &[LineWithInvisibles],
 9096        line_height: Pixels,
 9097        scroll_position: gpui::Point<ScrollOffset>,
 9098        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9099        newest_selection_head: Option<DisplayPoint>,
 9100        editor_width: Pixels,
 9101        style: &EditorStyle,
 9102        window: &mut Window,
 9103        cx: &mut App,
 9104    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9105        if self.mode().is_minimap() {
 9106            return None;
 9107        }
 9108        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9109
 9110        if self.edit_prediction_visible_in_cursor_popover(true) {
 9111            return None;
 9112        }
 9113
 9114        match &active_edit_prediction.completion {
 9115            EditPrediction::MoveWithin { target, .. } => {
 9116                let target_display_point = target.to_display_point(editor_snapshot);
 9117
 9118                if self.edit_prediction_requires_modifier() {
 9119                    if !self.edit_prediction_preview_is_active() {
 9120                        return None;
 9121                    }
 9122
 9123                    self.render_edit_prediction_modifier_jump_popover(
 9124                        text_bounds,
 9125                        content_origin,
 9126                        visible_row_range,
 9127                        line_layouts,
 9128                        line_height,
 9129                        scroll_pixel_position,
 9130                        newest_selection_head,
 9131                        target_display_point,
 9132                        window,
 9133                        cx,
 9134                    )
 9135                } else {
 9136                    self.render_edit_prediction_eager_jump_popover(
 9137                        text_bounds,
 9138                        content_origin,
 9139                        editor_snapshot,
 9140                        visible_row_range,
 9141                        scroll_top,
 9142                        scroll_bottom,
 9143                        line_height,
 9144                        scroll_pixel_position,
 9145                        target_display_point,
 9146                        editor_width,
 9147                        window,
 9148                        cx,
 9149                    )
 9150                }
 9151            }
 9152            EditPrediction::Edit {
 9153                display_mode: EditDisplayMode::Inline,
 9154                ..
 9155            } => None,
 9156            EditPrediction::Edit {
 9157                display_mode: EditDisplayMode::TabAccept,
 9158                edits,
 9159                ..
 9160            } => {
 9161                let range = &edits.first()?.0;
 9162                let target_display_point = range.end.to_display_point(editor_snapshot);
 9163
 9164                self.render_edit_prediction_end_of_line_popover(
 9165                    "Accept",
 9166                    editor_snapshot,
 9167                    visible_row_range,
 9168                    target_display_point,
 9169                    line_height,
 9170                    scroll_pixel_position,
 9171                    content_origin,
 9172                    editor_width,
 9173                    window,
 9174                    cx,
 9175                )
 9176            }
 9177            EditPrediction::Edit {
 9178                edits,
 9179                edit_preview,
 9180                display_mode: EditDisplayMode::DiffPopover,
 9181                snapshot,
 9182            } => self.render_edit_prediction_diff_popover(
 9183                text_bounds,
 9184                content_origin,
 9185                right_margin,
 9186                editor_snapshot,
 9187                visible_row_range,
 9188                line_layouts,
 9189                line_height,
 9190                scroll_position,
 9191                scroll_pixel_position,
 9192                newest_selection_head,
 9193                editor_width,
 9194                style,
 9195                edits,
 9196                edit_preview,
 9197                snapshot,
 9198                window,
 9199                cx,
 9200            ),
 9201            EditPrediction::MoveOutside { snapshot, .. } => {
 9202                let mut element = self
 9203                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9204                    .into_any();
 9205
 9206                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9207                let origin_x = text_bounds.size.width - size.width - px(30.);
 9208                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9209                element.prepaint_at(origin, window, cx);
 9210
 9211                Some((element, origin))
 9212            }
 9213        }
 9214    }
 9215
 9216    fn render_edit_prediction_modifier_jump_popover(
 9217        &mut self,
 9218        text_bounds: &Bounds<Pixels>,
 9219        content_origin: gpui::Point<Pixels>,
 9220        visible_row_range: Range<DisplayRow>,
 9221        line_layouts: &[LineWithInvisibles],
 9222        line_height: Pixels,
 9223        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9224        newest_selection_head: Option<DisplayPoint>,
 9225        target_display_point: DisplayPoint,
 9226        window: &mut Window,
 9227        cx: &mut App,
 9228    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9229        let scrolled_content_origin =
 9230            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9231
 9232        const SCROLL_PADDING_Y: Pixels = px(12.);
 9233
 9234        if target_display_point.row() < visible_row_range.start {
 9235            return self.render_edit_prediction_scroll_popover(
 9236                |_| SCROLL_PADDING_Y,
 9237                IconName::ArrowUp,
 9238                visible_row_range,
 9239                line_layouts,
 9240                newest_selection_head,
 9241                scrolled_content_origin,
 9242                window,
 9243                cx,
 9244            );
 9245        } else if target_display_point.row() >= visible_row_range.end {
 9246            return self.render_edit_prediction_scroll_popover(
 9247                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9248                IconName::ArrowDown,
 9249                visible_row_range,
 9250                line_layouts,
 9251                newest_selection_head,
 9252                scrolled_content_origin,
 9253                window,
 9254                cx,
 9255            );
 9256        }
 9257
 9258        const POLE_WIDTH: Pixels = px(2.);
 9259
 9260        let line_layout =
 9261            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9262        let target_column = target_display_point.column() as usize;
 9263
 9264        let target_x = line_layout.x_for_index(target_column);
 9265        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9266            - scroll_pixel_position.y;
 9267
 9268        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9269
 9270        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9271        border_color.l += 0.001;
 9272
 9273        let mut element = v_flex()
 9274            .items_end()
 9275            .when(flag_on_right, |el| el.items_start())
 9276            .child(if flag_on_right {
 9277                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9278                    .rounded_bl(px(0.))
 9279                    .rounded_tl(px(0.))
 9280                    .border_l_2()
 9281                    .border_color(border_color)
 9282            } else {
 9283                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9284                    .rounded_br(px(0.))
 9285                    .rounded_tr(px(0.))
 9286                    .border_r_2()
 9287                    .border_color(border_color)
 9288            })
 9289            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9290            .into_any();
 9291
 9292        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9293
 9294        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9295            - point(
 9296                if flag_on_right {
 9297                    POLE_WIDTH
 9298                } else {
 9299                    size.width - POLE_WIDTH
 9300                },
 9301                size.height - line_height,
 9302            );
 9303
 9304        origin.x = origin.x.max(content_origin.x);
 9305
 9306        element.prepaint_at(origin, window, cx);
 9307
 9308        Some((element, origin))
 9309    }
 9310
 9311    fn render_edit_prediction_scroll_popover(
 9312        &mut self,
 9313        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9314        scroll_icon: IconName,
 9315        visible_row_range: Range<DisplayRow>,
 9316        line_layouts: &[LineWithInvisibles],
 9317        newest_selection_head: Option<DisplayPoint>,
 9318        scrolled_content_origin: gpui::Point<Pixels>,
 9319        window: &mut Window,
 9320        cx: &mut App,
 9321    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9322        let mut element = self
 9323            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9324            .into_any();
 9325
 9326        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9327
 9328        let cursor = newest_selection_head?;
 9329        let cursor_row_layout =
 9330            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9331        let cursor_column = cursor.column() as usize;
 9332
 9333        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9334
 9335        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9336
 9337        element.prepaint_at(origin, window, cx);
 9338        Some((element, origin))
 9339    }
 9340
 9341    fn render_edit_prediction_eager_jump_popover(
 9342        &mut self,
 9343        text_bounds: &Bounds<Pixels>,
 9344        content_origin: gpui::Point<Pixels>,
 9345        editor_snapshot: &EditorSnapshot,
 9346        visible_row_range: Range<DisplayRow>,
 9347        scroll_top: ScrollOffset,
 9348        scroll_bottom: ScrollOffset,
 9349        line_height: Pixels,
 9350        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9351        target_display_point: DisplayPoint,
 9352        editor_width: Pixels,
 9353        window: &mut Window,
 9354        cx: &mut App,
 9355    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9356        if target_display_point.row().as_f64() < scroll_top {
 9357            let mut element = self
 9358                .render_edit_prediction_line_popover(
 9359                    "Jump to Edit",
 9360                    Some(IconName::ArrowUp),
 9361                    window,
 9362                    cx,
 9363                )
 9364                .into_any();
 9365
 9366            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9367            let offset = point(
 9368                (text_bounds.size.width - size.width) / 2.,
 9369                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9370            );
 9371
 9372            let origin = text_bounds.origin + offset;
 9373            element.prepaint_at(origin, window, cx);
 9374            Some((element, origin))
 9375        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9376            let mut element = self
 9377                .render_edit_prediction_line_popover(
 9378                    "Jump to Edit",
 9379                    Some(IconName::ArrowDown),
 9380                    window,
 9381                    cx,
 9382                )
 9383                .into_any();
 9384
 9385            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9386            let offset = point(
 9387                (text_bounds.size.width - size.width) / 2.,
 9388                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9389            );
 9390
 9391            let origin = text_bounds.origin + offset;
 9392            element.prepaint_at(origin, window, cx);
 9393            Some((element, origin))
 9394        } else {
 9395            self.render_edit_prediction_end_of_line_popover(
 9396                "Jump to Edit",
 9397                editor_snapshot,
 9398                visible_row_range,
 9399                target_display_point,
 9400                line_height,
 9401                scroll_pixel_position,
 9402                content_origin,
 9403                editor_width,
 9404                window,
 9405                cx,
 9406            )
 9407        }
 9408    }
 9409
 9410    fn render_edit_prediction_end_of_line_popover(
 9411        self: &mut Editor,
 9412        label: &'static str,
 9413        editor_snapshot: &EditorSnapshot,
 9414        visible_row_range: Range<DisplayRow>,
 9415        target_display_point: DisplayPoint,
 9416        line_height: Pixels,
 9417        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9418        content_origin: gpui::Point<Pixels>,
 9419        editor_width: Pixels,
 9420        window: &mut Window,
 9421        cx: &mut App,
 9422    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9423        let target_line_end = DisplayPoint::new(
 9424            target_display_point.row(),
 9425            editor_snapshot.line_len(target_display_point.row()),
 9426        );
 9427
 9428        let mut element = self
 9429            .render_edit_prediction_line_popover(label, None, window, cx)
 9430            .into_any();
 9431
 9432        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9433
 9434        let line_origin =
 9435            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9436
 9437        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9438        let mut origin = start_point
 9439            + line_origin
 9440            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9441        origin.x = origin.x.max(content_origin.x);
 9442
 9443        let max_x = content_origin.x + editor_width - size.width;
 9444
 9445        if origin.x > max_x {
 9446            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9447
 9448            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9449                origin.y += offset;
 9450                IconName::ArrowUp
 9451            } else {
 9452                origin.y -= offset;
 9453                IconName::ArrowDown
 9454            };
 9455
 9456            element = self
 9457                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9458                .into_any();
 9459
 9460            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9461
 9462            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9463        }
 9464
 9465        element.prepaint_at(origin, window, cx);
 9466        Some((element, origin))
 9467    }
 9468
 9469    fn render_edit_prediction_diff_popover(
 9470        self: &Editor,
 9471        text_bounds: &Bounds<Pixels>,
 9472        content_origin: gpui::Point<Pixels>,
 9473        right_margin: Pixels,
 9474        editor_snapshot: &EditorSnapshot,
 9475        visible_row_range: Range<DisplayRow>,
 9476        line_layouts: &[LineWithInvisibles],
 9477        line_height: Pixels,
 9478        scroll_position: gpui::Point<ScrollOffset>,
 9479        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9480        newest_selection_head: Option<DisplayPoint>,
 9481        editor_width: Pixels,
 9482        style: &EditorStyle,
 9483        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9484        edit_preview: &Option<language::EditPreview>,
 9485        snapshot: &language::BufferSnapshot,
 9486        window: &mut Window,
 9487        cx: &mut App,
 9488    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9489        let edit_start = edits
 9490            .first()
 9491            .unwrap()
 9492            .0
 9493            .start
 9494            .to_display_point(editor_snapshot);
 9495        let edit_end = edits
 9496            .last()
 9497            .unwrap()
 9498            .0
 9499            .end
 9500            .to_display_point(editor_snapshot);
 9501
 9502        let is_visible = visible_row_range.contains(&edit_start.row())
 9503            || visible_row_range.contains(&edit_end.row());
 9504        if !is_visible {
 9505            return None;
 9506        }
 9507
 9508        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9509            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9510        } else {
 9511            // Fallback for providers without edit_preview
 9512            crate::edit_prediction_fallback_text(edits, cx)
 9513        };
 9514
 9515        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9516        let line_count = highlighted_edits.text.lines().count();
 9517
 9518        const BORDER_WIDTH: Pixels = px(1.);
 9519
 9520        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9521        let has_keybind = keybind.is_some();
 9522
 9523        let mut element = h_flex()
 9524            .items_start()
 9525            .child(
 9526                h_flex()
 9527                    .bg(cx.theme().colors().editor_background)
 9528                    .border(BORDER_WIDTH)
 9529                    .shadow_xs()
 9530                    .border_color(cx.theme().colors().border)
 9531                    .rounded_l_lg()
 9532                    .when(line_count > 1, |el| el.rounded_br_lg())
 9533                    .pr_1()
 9534                    .child(styled_text),
 9535            )
 9536            .child(
 9537                h_flex()
 9538                    .h(line_height + BORDER_WIDTH * 2.)
 9539                    .px_1p5()
 9540                    .gap_1()
 9541                    // Workaround: For some reason, there's a gap if we don't do this
 9542                    .ml(-BORDER_WIDTH)
 9543                    .shadow(vec![gpui::BoxShadow {
 9544                        color: gpui::black().opacity(0.05),
 9545                        offset: point(px(1.), px(1.)),
 9546                        blur_radius: px(2.),
 9547                        spread_radius: px(0.),
 9548                    }])
 9549                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9550                    .border(BORDER_WIDTH)
 9551                    .border_color(cx.theme().colors().border)
 9552                    .rounded_r_lg()
 9553                    .id("edit_prediction_diff_popover_keybind")
 9554                    .when(!has_keybind, |el| {
 9555                        let status_colors = cx.theme().status();
 9556
 9557                        el.bg(status_colors.error_background)
 9558                            .border_color(status_colors.error.opacity(0.6))
 9559                            .child(Icon::new(IconName::Info).color(Color::Error))
 9560                            .cursor_default()
 9561                            .hoverable_tooltip(move |_window, cx| {
 9562                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9563                            })
 9564                    })
 9565                    .children(keybind),
 9566            )
 9567            .into_any();
 9568
 9569        let longest_row =
 9570            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9571        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9572            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9573        } else {
 9574            layout_line(
 9575                longest_row,
 9576                editor_snapshot,
 9577                style,
 9578                editor_width,
 9579                |_| false,
 9580                window,
 9581                cx,
 9582            )
 9583            .width
 9584        };
 9585
 9586        let viewport_bounds =
 9587            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9588                right: -right_margin,
 9589                ..Default::default()
 9590            });
 9591
 9592        let x_after_longest = Pixels::from(
 9593            ScrollPixelOffset::from(
 9594                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9595            ) - scroll_pixel_position.x,
 9596        );
 9597
 9598        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9599
 9600        // Fully visible if it can be displayed within the window (allow overlapping other
 9601        // panes). However, this is only allowed if the popover starts within text_bounds.
 9602        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9603            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9604
 9605        let mut origin = if can_position_to_the_right {
 9606            point(
 9607                x_after_longest,
 9608                text_bounds.origin.y
 9609                    + Pixels::from(
 9610                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9611                            - scroll_pixel_position.y,
 9612                    ),
 9613            )
 9614        } else {
 9615            let cursor_row = newest_selection_head.map(|head| head.row());
 9616            let above_edit = edit_start
 9617                .row()
 9618                .0
 9619                .checked_sub(line_count as u32)
 9620                .map(DisplayRow);
 9621            let below_edit = Some(edit_end.row() + 1);
 9622            let above_cursor =
 9623                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9624            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9625
 9626            // Place the edit popover adjacent to the edit if there is a location
 9627            // available that is onscreen and does not obscure the cursor. Otherwise,
 9628            // place it adjacent to the cursor.
 9629            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9630                .into_iter()
 9631                .flatten()
 9632                .find(|&start_row| {
 9633                    let end_row = start_row + line_count as u32;
 9634                    visible_row_range.contains(&start_row)
 9635                        && visible_row_range.contains(&end_row)
 9636                        && cursor_row
 9637                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9638                })?;
 9639
 9640            content_origin
 9641                + point(
 9642                    Pixels::from(-scroll_pixel_position.x),
 9643                    Pixels::from(
 9644                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9645                    ),
 9646                )
 9647        };
 9648
 9649        origin.x -= BORDER_WIDTH;
 9650
 9651        window.defer_draw(element, origin, 1);
 9652
 9653        // Do not return an element, since it will already be drawn due to defer_draw.
 9654        None
 9655    }
 9656
 9657    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9658        px(30.)
 9659    }
 9660
 9661    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9662        if self.read_only(cx) {
 9663            cx.theme().players().read_only()
 9664        } else {
 9665            self.style.as_ref().unwrap().local_player
 9666        }
 9667    }
 9668
 9669    fn render_edit_prediction_accept_keybind(
 9670        &self,
 9671        window: &mut Window,
 9672        cx: &mut App,
 9673    ) -> Option<AnyElement> {
 9674        let accept_binding =
 9675            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9676        let accept_keystroke = accept_binding.keystroke()?;
 9677
 9678        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9679
 9680        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9681            Color::Accent
 9682        } else {
 9683            Color::Muted
 9684        };
 9685
 9686        h_flex()
 9687            .px_0p5()
 9688            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9689            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9690            .text_size(TextSize::XSmall.rems(cx))
 9691            .child(h_flex().children(ui::render_modifiers(
 9692                accept_keystroke.modifiers(),
 9693                PlatformStyle::platform(),
 9694                Some(modifiers_color),
 9695                Some(IconSize::XSmall.rems().into()),
 9696                true,
 9697            )))
 9698            .when(is_platform_style_mac, |parent| {
 9699                parent.child(accept_keystroke.key().to_string())
 9700            })
 9701            .when(!is_platform_style_mac, |parent| {
 9702                parent.child(
 9703                    Key::new(
 9704                        util::capitalize(accept_keystroke.key()),
 9705                        Some(Color::Default),
 9706                    )
 9707                    .size(Some(IconSize::XSmall.rems().into())),
 9708                )
 9709            })
 9710            .into_any()
 9711            .into()
 9712    }
 9713
 9714    fn render_edit_prediction_line_popover(
 9715        &self,
 9716        label: impl Into<SharedString>,
 9717        icon: Option<IconName>,
 9718        window: &mut Window,
 9719        cx: &mut App,
 9720    ) -> Stateful<Div> {
 9721        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9722
 9723        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9724        let has_keybind = keybind.is_some();
 9725
 9726        h_flex()
 9727            .id("ep-line-popover")
 9728            .py_0p5()
 9729            .pl_1()
 9730            .pr(padding_right)
 9731            .gap_1()
 9732            .rounded_md()
 9733            .border_1()
 9734            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9735            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9736            .shadow_xs()
 9737            .when(!has_keybind, |el| {
 9738                let status_colors = cx.theme().status();
 9739
 9740                el.bg(status_colors.error_background)
 9741                    .border_color(status_colors.error.opacity(0.6))
 9742                    .pl_2()
 9743                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9744                    .cursor_default()
 9745                    .hoverable_tooltip(move |_window, cx| {
 9746                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9747                    })
 9748            })
 9749            .children(keybind)
 9750            .child(
 9751                Label::new(label)
 9752                    .size(LabelSize::Small)
 9753                    .when(!has_keybind, |el| {
 9754                        el.color(cx.theme().status().error.into()).strikethrough()
 9755                    }),
 9756            )
 9757            .when(!has_keybind, |el| {
 9758                el.child(
 9759                    h_flex().ml_1().child(
 9760                        Icon::new(IconName::Info)
 9761                            .size(IconSize::Small)
 9762                            .color(cx.theme().status().error.into()),
 9763                    ),
 9764                )
 9765            })
 9766            .when_some(icon, |element, icon| {
 9767                element.child(
 9768                    div()
 9769                        .mt(px(1.5))
 9770                        .child(Icon::new(icon).size(IconSize::Small)),
 9771                )
 9772            })
 9773    }
 9774
 9775    fn render_edit_prediction_jump_outside_popover(
 9776        &self,
 9777        snapshot: &BufferSnapshot,
 9778        window: &mut Window,
 9779        cx: &mut App,
 9780    ) -> Stateful<Div> {
 9781        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9782        let has_keybind = keybind.is_some();
 9783
 9784        let file_name = snapshot
 9785            .file()
 9786            .map(|file| SharedString::new(file.file_name(cx)))
 9787            .unwrap_or(SharedString::new_static("untitled"));
 9788
 9789        h_flex()
 9790            .id("ep-jump-outside-popover")
 9791            .py_1()
 9792            .px_2()
 9793            .gap_1()
 9794            .rounded_md()
 9795            .border_1()
 9796            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9797            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9798            .shadow_xs()
 9799            .when(!has_keybind, |el| {
 9800                let status_colors = cx.theme().status();
 9801
 9802                el.bg(status_colors.error_background)
 9803                    .border_color(status_colors.error.opacity(0.6))
 9804                    .pl_2()
 9805                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9806                    .cursor_default()
 9807                    .hoverable_tooltip(move |_window, cx| {
 9808                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9809                    })
 9810            })
 9811            .children(keybind)
 9812            .child(
 9813                Label::new(file_name)
 9814                    .size(LabelSize::Small)
 9815                    .buffer_font(cx)
 9816                    .when(!has_keybind, |el| {
 9817                        el.color(cx.theme().status().error.into()).strikethrough()
 9818                    }),
 9819            )
 9820            .when(!has_keybind, |el| {
 9821                el.child(
 9822                    h_flex().ml_1().child(
 9823                        Icon::new(IconName::Info)
 9824                            .size(IconSize::Small)
 9825                            .color(cx.theme().status().error.into()),
 9826                    ),
 9827                )
 9828            })
 9829            .child(
 9830                div()
 9831                    .mt(px(1.5))
 9832                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9833            )
 9834    }
 9835
 9836    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9837        let accent_color = cx.theme().colors().text_accent;
 9838        let editor_bg_color = cx.theme().colors().editor_background;
 9839        editor_bg_color.blend(accent_color.opacity(0.1))
 9840    }
 9841
 9842    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9843        let accent_color = cx.theme().colors().text_accent;
 9844        let editor_bg_color = cx.theme().colors().editor_background;
 9845        editor_bg_color.blend(accent_color.opacity(0.6))
 9846    }
 9847    fn get_prediction_provider_icon_name(
 9848        provider: &Option<RegisteredEditPredictionDelegate>,
 9849    ) -> IconName {
 9850        match provider {
 9851            Some(provider) => match provider.provider.name() {
 9852                "copilot" => IconName::Copilot,
 9853                "supermaven" => IconName::Supermaven,
 9854                _ => IconName::ZedPredict,
 9855            },
 9856            None => IconName::ZedPredict,
 9857        }
 9858    }
 9859
 9860    fn render_edit_prediction_cursor_popover(
 9861        &self,
 9862        min_width: Pixels,
 9863        max_width: Pixels,
 9864        cursor_point: Point,
 9865        style: &EditorStyle,
 9866        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9867        _window: &Window,
 9868        cx: &mut Context<Editor>,
 9869    ) -> Option<AnyElement> {
 9870        let provider = self.edit_prediction_provider.as_ref()?;
 9871        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9872
 9873        let is_refreshing = provider.provider.is_refreshing(cx);
 9874
 9875        fn pending_completion_container(icon: IconName) -> Div {
 9876            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9877        }
 9878
 9879        let completion = match &self.active_edit_prediction {
 9880            Some(prediction) => {
 9881                if !self.has_visible_completions_menu() {
 9882                    const RADIUS: Pixels = px(6.);
 9883                    const BORDER_WIDTH: Pixels = px(1.);
 9884
 9885                    return Some(
 9886                        h_flex()
 9887                            .elevation_2(cx)
 9888                            .border(BORDER_WIDTH)
 9889                            .border_color(cx.theme().colors().border)
 9890                            .when(accept_keystroke.is_none(), |el| {
 9891                                el.border_color(cx.theme().status().error)
 9892                            })
 9893                            .rounded(RADIUS)
 9894                            .rounded_tl(px(0.))
 9895                            .overflow_hidden()
 9896                            .child(div().px_1p5().child(match &prediction.completion {
 9897                                EditPrediction::MoveWithin { target, snapshot } => {
 9898                                    use text::ToPoint as _;
 9899                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9900                                    {
 9901                                        Icon::new(IconName::ZedPredictDown)
 9902                                    } else {
 9903                                        Icon::new(IconName::ZedPredictUp)
 9904                                    }
 9905                                }
 9906                                EditPrediction::MoveOutside { .. } => {
 9907                                    // TODO [zeta2] custom icon for external jump?
 9908                                    Icon::new(provider_icon)
 9909                                }
 9910                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9911                            }))
 9912                            .child(
 9913                                h_flex()
 9914                                    .gap_1()
 9915                                    .py_1()
 9916                                    .px_2()
 9917                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9918                                    .border_l_1()
 9919                                    .border_color(cx.theme().colors().border)
 9920                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9921                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9922                                        el.child(
 9923                                            Label::new("Hold")
 9924                                                .size(LabelSize::Small)
 9925                                                .when(accept_keystroke.is_none(), |el| {
 9926                                                    el.strikethrough()
 9927                                                })
 9928                                                .line_height_style(LineHeightStyle::UiLabel),
 9929                                        )
 9930                                    })
 9931                                    .id("edit_prediction_cursor_popover_keybind")
 9932                                    .when(accept_keystroke.is_none(), |el| {
 9933                                        let status_colors = cx.theme().status();
 9934
 9935                                        el.bg(status_colors.error_background)
 9936                                            .border_color(status_colors.error.opacity(0.6))
 9937                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9938                                            .cursor_default()
 9939                                            .hoverable_tooltip(move |_window, cx| {
 9940                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9941                                                    .into()
 9942                                            })
 9943                                    })
 9944                                    .when_some(
 9945                                        accept_keystroke.as_ref(),
 9946                                        |el, accept_keystroke| {
 9947                                            el.child(h_flex().children(ui::render_modifiers(
 9948                                                accept_keystroke.modifiers(),
 9949                                                PlatformStyle::platform(),
 9950                                                Some(Color::Default),
 9951                                                Some(IconSize::XSmall.rems().into()),
 9952                                                false,
 9953                                            )))
 9954                                        },
 9955                                    ),
 9956                            )
 9957                            .into_any(),
 9958                    );
 9959                }
 9960
 9961                self.render_edit_prediction_cursor_popover_preview(
 9962                    prediction,
 9963                    cursor_point,
 9964                    style,
 9965                    cx,
 9966                )?
 9967            }
 9968
 9969            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9970                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9971                    stale_completion,
 9972                    cursor_point,
 9973                    style,
 9974                    cx,
 9975                )?,
 9976
 9977                None => pending_completion_container(provider_icon)
 9978                    .child(Label::new("...").size(LabelSize::Small)),
 9979            },
 9980
 9981            None => pending_completion_container(provider_icon)
 9982                .child(Label::new("...").size(LabelSize::Small)),
 9983        };
 9984
 9985        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9986            completion
 9987                .with_animation(
 9988                    "loading-completion",
 9989                    Animation::new(Duration::from_secs(2))
 9990                        .repeat()
 9991                        .with_easing(pulsating_between(0.4, 0.8)),
 9992                    |label, delta| label.opacity(delta),
 9993                )
 9994                .into_any_element()
 9995        } else {
 9996            completion.into_any_element()
 9997        };
 9998
 9999        let has_completion = self.active_edit_prediction.is_some();
10000
10001        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10002        Some(
10003            h_flex()
10004                .min_w(min_width)
10005                .max_w(max_width)
10006                .flex_1()
10007                .elevation_2(cx)
10008                .border_color(cx.theme().colors().border)
10009                .child(
10010                    div()
10011                        .flex_1()
10012                        .py_1()
10013                        .px_2()
10014                        .overflow_hidden()
10015                        .child(completion),
10016                )
10017                .when_some(accept_keystroke, |el, accept_keystroke| {
10018                    if !accept_keystroke.modifiers().modified() {
10019                        return el;
10020                    }
10021
10022                    el.child(
10023                        h_flex()
10024                            .h_full()
10025                            .border_l_1()
10026                            .rounded_r_lg()
10027                            .border_color(cx.theme().colors().border)
10028                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10029                            .gap_1()
10030                            .py_1()
10031                            .px_2()
10032                            .child(
10033                                h_flex()
10034                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10035                                    .when(is_platform_style_mac, |parent| parent.gap_1())
10036                                    .child(h_flex().children(ui::render_modifiers(
10037                                        accept_keystroke.modifiers(),
10038                                        PlatformStyle::platform(),
10039                                        Some(if !has_completion {
10040                                            Color::Muted
10041                                        } else {
10042                                            Color::Default
10043                                        }),
10044                                        None,
10045                                        false,
10046                                    ))),
10047                            )
10048                            .child(Label::new("Preview").into_any_element())
10049                            .opacity(if has_completion { 1.0 } else { 0.4 }),
10050                    )
10051                })
10052                .into_any(),
10053        )
10054    }
10055
10056    fn render_edit_prediction_cursor_popover_preview(
10057        &self,
10058        completion: &EditPredictionState,
10059        cursor_point: Point,
10060        style: &EditorStyle,
10061        cx: &mut Context<Editor>,
10062    ) -> Option<Div> {
10063        use text::ToPoint as _;
10064
10065        fn render_relative_row_jump(
10066            prefix: impl Into<String>,
10067            current_row: u32,
10068            target_row: u32,
10069        ) -> Div {
10070            let (row_diff, arrow) = if target_row < current_row {
10071                (current_row - target_row, IconName::ArrowUp)
10072            } else {
10073                (target_row - current_row, IconName::ArrowDown)
10074            };
10075
10076            h_flex()
10077                .child(
10078                    Label::new(format!("{}{}", prefix.into(), row_diff))
10079                        .color(Color::Muted)
10080                        .size(LabelSize::Small),
10081                )
10082                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10083        }
10084
10085        let supports_jump = self
10086            .edit_prediction_provider
10087            .as_ref()
10088            .map(|provider| provider.provider.supports_jump_to_edit())
10089            .unwrap_or(true);
10090
10091        match &completion.completion {
10092            EditPrediction::MoveWithin {
10093                target, snapshot, ..
10094            } => {
10095                if !supports_jump {
10096                    return None;
10097                }
10098
10099                Some(
10100                    h_flex()
10101                        .px_2()
10102                        .gap_2()
10103                        .flex_1()
10104                        .child(
10105                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10106                                Icon::new(IconName::ZedPredictDown)
10107                            } else {
10108                                Icon::new(IconName::ZedPredictUp)
10109                            },
10110                        )
10111                        .child(Label::new("Jump to Edit")),
10112                )
10113            }
10114            EditPrediction::MoveOutside { snapshot, .. } => {
10115                let file_name = snapshot
10116                    .file()
10117                    .map(|file| file.file_name(cx))
10118                    .unwrap_or("untitled");
10119                Some(
10120                    h_flex()
10121                        .px_2()
10122                        .gap_2()
10123                        .flex_1()
10124                        .child(Icon::new(IconName::ZedPredict))
10125                        .child(Label::new(format!("Jump to {file_name}"))),
10126                )
10127            }
10128            EditPrediction::Edit {
10129                edits,
10130                edit_preview,
10131                snapshot,
10132                display_mode: _,
10133            } => {
10134                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10135
10136                let (highlighted_edits, has_more_lines) =
10137                    if let Some(edit_preview) = edit_preview.as_ref() {
10138                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10139                            .first_line_preview()
10140                    } else {
10141                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10142                    };
10143
10144                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10145                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10146
10147                let preview = h_flex()
10148                    .gap_1()
10149                    .min_w_16()
10150                    .child(styled_text)
10151                    .when(has_more_lines, |parent| parent.child(""));
10152
10153                let left = if supports_jump && first_edit_row != cursor_point.row {
10154                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10155                        .into_any_element()
10156                } else {
10157                    let icon_name =
10158                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10159                    Icon::new(icon_name).into_any_element()
10160                };
10161
10162                Some(
10163                    h_flex()
10164                        .h_full()
10165                        .flex_1()
10166                        .gap_2()
10167                        .pr_1()
10168                        .overflow_x_hidden()
10169                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10170                        .child(left)
10171                        .child(preview),
10172                )
10173            }
10174        }
10175    }
10176
10177    pub fn render_context_menu(
10178        &mut self,
10179        max_height_in_lines: u32,
10180        window: &mut Window,
10181        cx: &mut Context<Editor>,
10182    ) -> Option<AnyElement> {
10183        let menu = self.context_menu.borrow();
10184        let menu = menu.as_ref()?;
10185        if !menu.visible() {
10186            return None;
10187        };
10188        self.style
10189            .as_ref()
10190            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10191    }
10192
10193    fn render_context_menu_aside(
10194        &mut self,
10195        max_size: Size<Pixels>,
10196        window: &mut Window,
10197        cx: &mut Context<Editor>,
10198    ) -> Option<AnyElement> {
10199        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10200            if menu.visible() {
10201                menu.render_aside(max_size, window, cx)
10202            } else {
10203                None
10204            }
10205        })
10206    }
10207
10208    fn hide_context_menu(
10209        &mut self,
10210        window: &mut Window,
10211        cx: &mut Context<Self>,
10212    ) -> Option<CodeContextMenu> {
10213        cx.notify();
10214        self.completion_tasks.clear();
10215        let context_menu = self.context_menu.borrow_mut().take();
10216        self.stale_edit_prediction_in_menu.take();
10217        self.update_visible_edit_prediction(window, cx);
10218        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10219            && let Some(completion_provider) = &self.completion_provider
10220        {
10221            completion_provider.selection_changed(None, window, cx);
10222        }
10223        context_menu
10224    }
10225
10226    fn show_snippet_choices(
10227        &mut self,
10228        choices: &Vec<String>,
10229        selection: Range<Anchor>,
10230        cx: &mut Context<Self>,
10231    ) {
10232        let Some((_, buffer, _)) = self
10233            .buffer()
10234            .read(cx)
10235            .excerpt_containing(selection.start, cx)
10236        else {
10237            return;
10238        };
10239        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10240        else {
10241            return;
10242        };
10243        if buffer != end_buffer {
10244            log::error!("expected anchor range to have matching buffer IDs");
10245            return;
10246        }
10247
10248        let id = post_inc(&mut self.next_completion_id);
10249        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10250        let mut context_menu = self.context_menu.borrow_mut();
10251        let old_menu = context_menu.take();
10252        *context_menu = Some(CodeContextMenu::Completions(
10253            CompletionsMenu::new_snippet_choices(
10254                id,
10255                true,
10256                choices,
10257                selection,
10258                buffer,
10259                old_menu.map(|menu| menu.primary_scroll_handle()),
10260                snippet_sort_order,
10261            ),
10262        ));
10263    }
10264
10265    pub fn insert_snippet(
10266        &mut self,
10267        insertion_ranges: &[Range<MultiBufferOffset>],
10268        snippet: Snippet,
10269        window: &mut Window,
10270        cx: &mut Context<Self>,
10271    ) -> Result<()> {
10272        struct Tabstop<T> {
10273            is_end_tabstop: bool,
10274            ranges: Vec<Range<T>>,
10275            choices: Option<Vec<String>>,
10276        }
10277
10278        let tabstops = self.buffer.update(cx, |buffer, cx| {
10279            let snippet_text: Arc<str> = snippet.text.clone().into();
10280            let edits = insertion_ranges
10281                .iter()
10282                .cloned()
10283                .map(|range| (range, snippet_text.clone()));
10284            let autoindent_mode = AutoindentMode::Block {
10285                original_indent_columns: Vec::new(),
10286            };
10287            buffer.edit(edits, Some(autoindent_mode), cx);
10288
10289            let snapshot = &*buffer.read(cx);
10290            let snippet = &snippet;
10291            snippet
10292                .tabstops
10293                .iter()
10294                .map(|tabstop| {
10295                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10296                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10297                    });
10298                    let mut tabstop_ranges = tabstop
10299                        .ranges
10300                        .iter()
10301                        .flat_map(|tabstop_range| {
10302                            let mut delta = 0_isize;
10303                            insertion_ranges.iter().map(move |insertion_range| {
10304                                let insertion_start = insertion_range.start + delta;
10305                                delta += snippet.text.len() as isize
10306                                    - (insertion_range.end - insertion_range.start) as isize;
10307
10308                                let start =
10309                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10310                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10311                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10312                            })
10313                        })
10314                        .collect::<Vec<_>>();
10315                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10316
10317                    Tabstop {
10318                        is_end_tabstop,
10319                        ranges: tabstop_ranges,
10320                        choices: tabstop.choices.clone(),
10321                    }
10322                })
10323                .collect::<Vec<_>>()
10324        });
10325        if let Some(tabstop) = tabstops.first() {
10326            self.change_selections(Default::default(), window, cx, |s| {
10327                // Reverse order so that the first range is the newest created selection.
10328                // Completions will use it and autoscroll will prioritize it.
10329                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10330            });
10331
10332            if let Some(choices) = &tabstop.choices
10333                && let Some(selection) = tabstop.ranges.first()
10334            {
10335                self.show_snippet_choices(choices, selection.clone(), cx)
10336            }
10337
10338            // If we're already at the last tabstop and it's at the end of the snippet,
10339            // we're done, we don't need to keep the state around.
10340            if !tabstop.is_end_tabstop {
10341                let choices = tabstops
10342                    .iter()
10343                    .map(|tabstop| tabstop.choices.clone())
10344                    .collect();
10345
10346                let ranges = tabstops
10347                    .into_iter()
10348                    .map(|tabstop| tabstop.ranges)
10349                    .collect::<Vec<_>>();
10350
10351                self.snippet_stack.push(SnippetState {
10352                    active_index: 0,
10353                    ranges,
10354                    choices,
10355                });
10356            }
10357
10358            // Check whether the just-entered snippet ends with an auto-closable bracket.
10359            if self.autoclose_regions.is_empty() {
10360                let snapshot = self.buffer.read(cx).snapshot(cx);
10361                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10362                    let selection_head = selection.head();
10363                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10364                        continue;
10365                    };
10366
10367                    let mut bracket_pair = None;
10368                    let max_lookup_length = scope
10369                        .brackets()
10370                        .map(|(pair, _)| {
10371                            pair.start
10372                                .as_str()
10373                                .chars()
10374                                .count()
10375                                .max(pair.end.as_str().chars().count())
10376                        })
10377                        .max();
10378                    if let Some(max_lookup_length) = max_lookup_length {
10379                        let next_text = snapshot
10380                            .chars_at(selection_head)
10381                            .take(max_lookup_length)
10382                            .collect::<String>();
10383                        let prev_text = snapshot
10384                            .reversed_chars_at(selection_head)
10385                            .take(max_lookup_length)
10386                            .collect::<String>();
10387
10388                        for (pair, enabled) in scope.brackets() {
10389                            if enabled
10390                                && pair.close
10391                                && prev_text.starts_with(pair.start.as_str())
10392                                && next_text.starts_with(pair.end.as_str())
10393                            {
10394                                bracket_pair = Some(pair.clone());
10395                                break;
10396                            }
10397                        }
10398                    }
10399
10400                    if let Some(pair) = bracket_pair {
10401                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10402                        let autoclose_enabled =
10403                            self.use_autoclose && snapshot_settings.use_autoclose;
10404                        if autoclose_enabled {
10405                            let start = snapshot.anchor_after(selection_head);
10406                            let end = snapshot.anchor_after(selection_head);
10407                            self.autoclose_regions.push(AutocloseRegion {
10408                                selection_id: selection.id,
10409                                range: start..end,
10410                                pair,
10411                            });
10412                        }
10413                    }
10414                }
10415            }
10416        }
10417        Ok(())
10418    }
10419
10420    pub fn move_to_next_snippet_tabstop(
10421        &mut self,
10422        window: &mut Window,
10423        cx: &mut Context<Self>,
10424    ) -> bool {
10425        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10426    }
10427
10428    pub fn move_to_prev_snippet_tabstop(
10429        &mut self,
10430        window: &mut Window,
10431        cx: &mut Context<Self>,
10432    ) -> bool {
10433        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10434    }
10435
10436    pub fn move_to_snippet_tabstop(
10437        &mut self,
10438        bias: Bias,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) -> bool {
10442        if let Some(mut snippet) = self.snippet_stack.pop() {
10443            match bias {
10444                Bias::Left => {
10445                    if snippet.active_index > 0 {
10446                        snippet.active_index -= 1;
10447                    } else {
10448                        self.snippet_stack.push(snippet);
10449                        return false;
10450                    }
10451                }
10452                Bias::Right => {
10453                    if snippet.active_index + 1 < snippet.ranges.len() {
10454                        snippet.active_index += 1;
10455                    } else {
10456                        self.snippet_stack.push(snippet);
10457                        return false;
10458                    }
10459                }
10460            }
10461            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10462                self.change_selections(Default::default(), window, cx, |s| {
10463                    // Reverse order so that the first range is the newest created selection.
10464                    // Completions will use it and autoscroll will prioritize it.
10465                    s.select_ranges(current_ranges.iter().rev().cloned())
10466                });
10467
10468                if let Some(choices) = &snippet.choices[snippet.active_index]
10469                    && let Some(selection) = current_ranges.first()
10470                {
10471                    self.show_snippet_choices(choices, selection.clone(), cx);
10472                }
10473
10474                // If snippet state is not at the last tabstop, push it back on the stack
10475                if snippet.active_index + 1 < snippet.ranges.len() {
10476                    self.snippet_stack.push(snippet);
10477                }
10478                return true;
10479            }
10480        }
10481
10482        false
10483    }
10484
10485    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10486        self.transact(window, cx, |this, window, cx| {
10487            this.select_all(&SelectAll, window, cx);
10488            this.insert("", window, cx);
10489        });
10490    }
10491
10492    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10493        if self.read_only(cx) {
10494            return;
10495        }
10496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10497        self.transact(window, cx, |this, window, cx| {
10498            this.select_autoclose_pair(window, cx);
10499
10500            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10501
10502            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10503            if !this.linked_edit_ranges.is_empty() {
10504                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10505                let snapshot = this.buffer.read(cx).snapshot(cx);
10506
10507                for selection in selections.iter() {
10508                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10509                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10510                    if selection_start.buffer_id != selection_end.buffer_id {
10511                        continue;
10512                    }
10513                    if let Some(ranges) =
10514                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10515                    {
10516                        for (buffer, entries) in ranges {
10517                            linked_ranges.entry(buffer).or_default().extend(entries);
10518                        }
10519                    }
10520                }
10521            }
10522
10523            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10524            for selection in &mut selections {
10525                if selection.is_empty() {
10526                    let old_head = selection.head();
10527                    let mut new_head =
10528                        movement::left(&display_map, old_head.to_display_point(&display_map))
10529                            .to_point(&display_map);
10530                    if let Some((buffer, line_buffer_range)) = display_map
10531                        .buffer_snapshot()
10532                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10533                    {
10534                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10535                        let indent_len = match indent_size.kind {
10536                            IndentKind::Space => {
10537                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10538                            }
10539                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10540                        };
10541                        if old_head.column <= indent_size.len && old_head.column > 0 {
10542                            let indent_len = indent_len.get();
10543                            new_head = cmp::min(
10544                                new_head,
10545                                MultiBufferPoint::new(
10546                                    old_head.row,
10547                                    ((old_head.column - 1) / indent_len) * indent_len,
10548                                ),
10549                            );
10550                        }
10551                    }
10552
10553                    selection.set_head(new_head, SelectionGoal::None);
10554                }
10555            }
10556
10557            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10558            this.insert("", window, cx);
10559            let empty_str: Arc<str> = Arc::from("");
10560            for (buffer, edits) in linked_ranges {
10561                let snapshot = buffer.read(cx).snapshot();
10562                use text::ToPoint as TP;
10563
10564                let edits = edits
10565                    .into_iter()
10566                    .map(|range| {
10567                        let end_point = TP::to_point(&range.end, &snapshot);
10568                        let mut start_point = TP::to_point(&range.start, &snapshot);
10569
10570                        if end_point == start_point {
10571                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10572                                .saturating_sub(1);
10573                            start_point =
10574                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10575                        };
10576
10577                        (start_point..end_point, empty_str.clone())
10578                    })
10579                    .sorted_by_key(|(range, _)| range.start)
10580                    .collect::<Vec<_>>();
10581                buffer.update(cx, |this, cx| {
10582                    this.edit(edits, None, cx);
10583                })
10584            }
10585            this.refresh_edit_prediction(true, false, window, cx);
10586            refresh_linked_ranges(this, window, cx);
10587        });
10588    }
10589
10590    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10591        if self.read_only(cx) {
10592            return;
10593        }
10594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10595        self.transact(window, cx, |this, window, cx| {
10596            this.change_selections(Default::default(), window, cx, |s| {
10597                s.move_with(|map, selection| {
10598                    if selection.is_empty() {
10599                        let cursor = movement::right(map, selection.head());
10600                        selection.end = cursor;
10601                        selection.reversed = true;
10602                        selection.goal = SelectionGoal::None;
10603                    }
10604                })
10605            });
10606            this.insert("", window, cx);
10607            this.refresh_edit_prediction(true, false, window, cx);
10608        });
10609    }
10610
10611    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10612        if self.mode.is_single_line() {
10613            cx.propagate();
10614            return;
10615        }
10616
10617        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10618        if self.move_to_prev_snippet_tabstop(window, cx) {
10619            return;
10620        }
10621        self.outdent(&Outdent, window, cx);
10622    }
10623
10624    pub fn next_snippet_tabstop(
10625        &mut self,
10626        _: &NextSnippetTabstop,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10631            cx.propagate();
10632            return;
10633        }
10634
10635        if self.move_to_next_snippet_tabstop(window, cx) {
10636            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10637            return;
10638        }
10639        cx.propagate();
10640    }
10641
10642    pub fn previous_snippet_tabstop(
10643        &mut self,
10644        _: &PreviousSnippetTabstop,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10649            cx.propagate();
10650            return;
10651        }
10652
10653        if self.move_to_prev_snippet_tabstop(window, cx) {
10654            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10655            return;
10656        }
10657        cx.propagate();
10658    }
10659
10660    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10661        if self.mode.is_single_line() {
10662            cx.propagate();
10663            return;
10664        }
10665
10666        if self.move_to_next_snippet_tabstop(window, cx) {
10667            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10668            return;
10669        }
10670        if self.read_only(cx) {
10671            return;
10672        }
10673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10674        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10675        let buffer = self.buffer.read(cx);
10676        let snapshot = buffer.snapshot(cx);
10677        let rows_iter = selections.iter().map(|s| s.head().row);
10678        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10679
10680        let has_some_cursor_in_whitespace = selections
10681            .iter()
10682            .filter(|selection| selection.is_empty())
10683            .any(|selection| {
10684                let cursor = selection.head();
10685                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10686                cursor.column < current_indent.len
10687            });
10688
10689        let mut edits = Vec::new();
10690        let mut prev_edited_row = 0;
10691        let mut row_delta = 0;
10692        for selection in &mut selections {
10693            if selection.start.row != prev_edited_row {
10694                row_delta = 0;
10695            }
10696            prev_edited_row = selection.end.row;
10697
10698            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10699            if selection.is_empty() {
10700                let cursor = selection.head();
10701                let settings = buffer.language_settings_at(cursor, cx);
10702                if settings.indent_list_on_tab {
10703                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10704                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10705                            row_delta = Self::indent_selection(
10706                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10707                            );
10708                            continue;
10709                        }
10710                    }
10711                }
10712            }
10713
10714            // If the selection is non-empty, then increase the indentation of the selected lines.
10715            if !selection.is_empty() {
10716                row_delta =
10717                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10718                continue;
10719            }
10720
10721            let cursor = selection.head();
10722            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10723            if let Some(suggested_indent) =
10724                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10725            {
10726                // Don't do anything if already at suggested indent
10727                // and there is any other cursor which is not
10728                if has_some_cursor_in_whitespace
10729                    && cursor.column == current_indent.len
10730                    && current_indent.len == suggested_indent.len
10731                {
10732                    continue;
10733                }
10734
10735                // Adjust line and move cursor to suggested indent
10736                // if cursor is not at suggested indent
10737                if cursor.column < suggested_indent.len
10738                    && cursor.column <= current_indent.len
10739                    && current_indent.len <= suggested_indent.len
10740                {
10741                    selection.start = Point::new(cursor.row, suggested_indent.len);
10742                    selection.end = selection.start;
10743                    if row_delta == 0 {
10744                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10745                            cursor.row,
10746                            current_indent,
10747                            suggested_indent,
10748                        ));
10749                        row_delta = suggested_indent.len - current_indent.len;
10750                    }
10751                    continue;
10752                }
10753
10754                // If current indent is more than suggested indent
10755                // only move cursor to current indent and skip indent
10756                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10757                    selection.start = Point::new(cursor.row, current_indent.len);
10758                    selection.end = selection.start;
10759                    continue;
10760                }
10761            }
10762
10763            // Otherwise, insert a hard or soft tab.
10764            let settings = buffer.language_settings_at(cursor, cx);
10765            let tab_size = if settings.hard_tabs {
10766                IndentSize::tab()
10767            } else {
10768                let tab_size = settings.tab_size.get();
10769                let indent_remainder = snapshot
10770                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10771                    .flat_map(str::chars)
10772                    .fold(row_delta % tab_size, |counter: u32, c| {
10773                        if c == '\t' {
10774                            0
10775                        } else {
10776                            (counter + 1) % tab_size
10777                        }
10778                    });
10779
10780                let chars_to_next_tab_stop = tab_size - indent_remainder;
10781                IndentSize::spaces(chars_to_next_tab_stop)
10782            };
10783            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10784            selection.end = selection.start;
10785            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10786            row_delta += tab_size.len;
10787        }
10788
10789        self.transact(window, cx, |this, window, cx| {
10790            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10791            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10792            this.refresh_edit_prediction(true, false, window, cx);
10793        });
10794    }
10795
10796    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10797        if self.read_only(cx) {
10798            return;
10799        }
10800        if self.mode.is_single_line() {
10801            cx.propagate();
10802            return;
10803        }
10804
10805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10806        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10807        let mut prev_edited_row = 0;
10808        let mut row_delta = 0;
10809        let mut edits = Vec::new();
10810        let buffer = self.buffer.read(cx);
10811        let snapshot = buffer.snapshot(cx);
10812        for selection in &mut selections {
10813            if selection.start.row != prev_edited_row {
10814                row_delta = 0;
10815            }
10816            prev_edited_row = selection.end.row;
10817
10818            row_delta =
10819                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10820        }
10821
10822        self.transact(window, cx, |this, window, cx| {
10823            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10824            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10825        });
10826    }
10827
10828    fn indent_selection(
10829        buffer: &MultiBuffer,
10830        snapshot: &MultiBufferSnapshot,
10831        selection: &mut Selection<Point>,
10832        edits: &mut Vec<(Range<Point>, String)>,
10833        delta_for_start_row: u32,
10834        cx: &App,
10835    ) -> u32 {
10836        let settings = buffer.language_settings_at(selection.start, cx);
10837        let tab_size = settings.tab_size.get();
10838        let indent_kind = if settings.hard_tabs {
10839            IndentKind::Tab
10840        } else {
10841            IndentKind::Space
10842        };
10843        let mut start_row = selection.start.row;
10844        let mut end_row = selection.end.row + 1;
10845
10846        // If a selection ends at the beginning of a line, don't indent
10847        // that last line.
10848        if selection.end.column == 0 && selection.end.row > selection.start.row {
10849            end_row -= 1;
10850        }
10851
10852        // Avoid re-indenting a row that has already been indented by a
10853        // previous selection, but still update this selection's column
10854        // to reflect that indentation.
10855        if delta_for_start_row > 0 {
10856            start_row += 1;
10857            selection.start.column += delta_for_start_row;
10858            if selection.end.row == selection.start.row {
10859                selection.end.column += delta_for_start_row;
10860            }
10861        }
10862
10863        let mut delta_for_end_row = 0;
10864        let has_multiple_rows = start_row + 1 != end_row;
10865        for row in start_row..end_row {
10866            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10867            let indent_delta = match (current_indent.kind, indent_kind) {
10868                (IndentKind::Space, IndentKind::Space) => {
10869                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10870                    IndentSize::spaces(columns_to_next_tab_stop)
10871                }
10872                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10873                (_, IndentKind::Tab) => IndentSize::tab(),
10874            };
10875
10876            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10877                0
10878            } else {
10879                selection.start.column
10880            };
10881            let row_start = Point::new(row, start);
10882            edits.push((
10883                row_start..row_start,
10884                indent_delta.chars().collect::<String>(),
10885            ));
10886
10887            // Update this selection's endpoints to reflect the indentation.
10888            if row == selection.start.row {
10889                selection.start.column += indent_delta.len;
10890            }
10891            if row == selection.end.row {
10892                selection.end.column += indent_delta.len;
10893                delta_for_end_row = indent_delta.len;
10894            }
10895        }
10896
10897        if selection.start.row == selection.end.row {
10898            delta_for_start_row + delta_for_end_row
10899        } else {
10900            delta_for_end_row
10901        }
10902    }
10903
10904    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10905        if self.read_only(cx) {
10906            return;
10907        }
10908        if self.mode.is_single_line() {
10909            cx.propagate();
10910            return;
10911        }
10912
10913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10915        let selections = self.selections.all::<Point>(&display_map);
10916        let mut deletion_ranges = Vec::new();
10917        let mut last_outdent = None;
10918        {
10919            let buffer = self.buffer.read(cx);
10920            let snapshot = buffer.snapshot(cx);
10921            for selection in &selections {
10922                let settings = buffer.language_settings_at(selection.start, cx);
10923                let tab_size = settings.tab_size.get();
10924                let mut rows = selection.spanned_rows(false, &display_map);
10925
10926                // Avoid re-outdenting a row that has already been outdented by a
10927                // previous selection.
10928                if let Some(last_row) = last_outdent
10929                    && last_row == rows.start
10930                {
10931                    rows.start = rows.start.next_row();
10932                }
10933                let has_multiple_rows = rows.len() > 1;
10934                for row in rows.iter_rows() {
10935                    let indent_size = snapshot.indent_size_for_line(row);
10936                    if indent_size.len > 0 {
10937                        let deletion_len = match indent_size.kind {
10938                            IndentKind::Space => {
10939                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10940                                if columns_to_prev_tab_stop == 0 {
10941                                    tab_size
10942                                } else {
10943                                    columns_to_prev_tab_stop
10944                                }
10945                            }
10946                            IndentKind::Tab => 1,
10947                        };
10948                        let start = if has_multiple_rows
10949                            || deletion_len > selection.start.column
10950                            || indent_size.len < selection.start.column
10951                        {
10952                            0
10953                        } else {
10954                            selection.start.column - deletion_len
10955                        };
10956                        deletion_ranges.push(
10957                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10958                        );
10959                        last_outdent = Some(row);
10960                    }
10961                }
10962            }
10963        }
10964
10965        self.transact(window, cx, |this, window, cx| {
10966            this.buffer.update(cx, |buffer, cx| {
10967                let empty_str: Arc<str> = Arc::default();
10968                buffer.edit(
10969                    deletion_ranges
10970                        .into_iter()
10971                        .map(|range| (range, empty_str.clone())),
10972                    None,
10973                    cx,
10974                );
10975            });
10976            let selections = this
10977                .selections
10978                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10979            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10980        });
10981    }
10982
10983    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10984        if self.read_only(cx) {
10985            return;
10986        }
10987        if self.mode.is_single_line() {
10988            cx.propagate();
10989            return;
10990        }
10991
10992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10993        let selections = self
10994            .selections
10995            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10996            .into_iter()
10997            .map(|s| s.range());
10998
10999        self.transact(window, cx, |this, window, cx| {
11000            this.buffer.update(cx, |buffer, cx| {
11001                buffer.autoindent_ranges(selections, cx);
11002            });
11003            let selections = this
11004                .selections
11005                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11006            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11007        });
11008    }
11009
11010    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11012        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11013        let selections = self.selections.all::<Point>(&display_map);
11014
11015        let mut new_cursors = Vec::new();
11016        let mut edit_ranges = Vec::new();
11017        let mut selections = selections.iter().peekable();
11018        while let Some(selection) = selections.next() {
11019            let mut rows = selection.spanned_rows(false, &display_map);
11020
11021            // Accumulate contiguous regions of rows that we want to delete.
11022            while let Some(next_selection) = selections.peek() {
11023                let next_rows = next_selection.spanned_rows(false, &display_map);
11024                if next_rows.start <= rows.end {
11025                    rows.end = next_rows.end;
11026                    selections.next().unwrap();
11027                } else {
11028                    break;
11029                }
11030            }
11031
11032            let buffer = display_map.buffer_snapshot();
11033            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11034            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11035                // If there's a line after the range, delete the \n from the end of the row range
11036                (
11037                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11038                    rows.end,
11039                )
11040            } else {
11041                // If there isn't a line after the range, delete the \n from the line before the
11042                // start of the row range
11043                edit_start = edit_start.saturating_sub_usize(1);
11044                (buffer.len(), rows.start.previous_row())
11045            };
11046
11047            let text_layout_details = self.text_layout_details(window);
11048            let x = display_map.x_for_display_point(
11049                selection.head().to_display_point(&display_map),
11050                &text_layout_details,
11051            );
11052            let row = Point::new(target_row.0, 0)
11053                .to_display_point(&display_map)
11054                .row();
11055            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11056
11057            new_cursors.push((
11058                selection.id,
11059                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11060                SelectionGoal::None,
11061            ));
11062            edit_ranges.push(edit_start..edit_end);
11063        }
11064
11065        self.transact(window, cx, |this, window, cx| {
11066            let buffer = this.buffer.update(cx, |buffer, cx| {
11067                let empty_str: Arc<str> = Arc::default();
11068                buffer.edit(
11069                    edit_ranges
11070                        .into_iter()
11071                        .map(|range| (range, empty_str.clone())),
11072                    None,
11073                    cx,
11074                );
11075                buffer.snapshot(cx)
11076            });
11077            let new_selections = new_cursors
11078                .into_iter()
11079                .map(|(id, cursor, goal)| {
11080                    let cursor = cursor.to_point(&buffer);
11081                    Selection {
11082                        id,
11083                        start: cursor,
11084                        end: cursor,
11085                        reversed: false,
11086                        goal,
11087                    }
11088                })
11089                .collect();
11090
11091            this.change_selections(Default::default(), window, cx, |s| {
11092                s.select(new_selections);
11093            });
11094        });
11095    }
11096
11097    pub fn join_lines_impl(
11098        &mut self,
11099        insert_whitespace: bool,
11100        window: &mut Window,
11101        cx: &mut Context<Self>,
11102    ) {
11103        if self.read_only(cx) {
11104            return;
11105        }
11106        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11107        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11108            let start = MultiBufferRow(selection.start.row);
11109            // Treat single line selections as if they include the next line. Otherwise this action
11110            // would do nothing for single line selections individual cursors.
11111            let end = if selection.start.row == selection.end.row {
11112                MultiBufferRow(selection.start.row + 1)
11113            } else {
11114                MultiBufferRow(selection.end.row)
11115            };
11116
11117            if let Some(last_row_range) = row_ranges.last_mut()
11118                && start <= last_row_range.end
11119            {
11120                last_row_range.end = end;
11121                continue;
11122            }
11123            row_ranges.push(start..end);
11124        }
11125
11126        let snapshot = self.buffer.read(cx).snapshot(cx);
11127        let mut cursor_positions = Vec::new();
11128        for row_range in &row_ranges {
11129            let anchor = snapshot.anchor_before(Point::new(
11130                row_range.end.previous_row().0,
11131                snapshot.line_len(row_range.end.previous_row()),
11132            ));
11133            cursor_positions.push(anchor..anchor);
11134        }
11135
11136        self.transact(window, cx, |this, window, cx| {
11137            for row_range in row_ranges.into_iter().rev() {
11138                for row in row_range.iter_rows().rev() {
11139                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11140                    let next_line_row = row.next_row();
11141                    let indent = snapshot.indent_size_for_line(next_line_row);
11142                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
11143
11144                    let replace =
11145                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
11146                            " "
11147                        } else {
11148                            ""
11149                        };
11150
11151                    this.buffer.update(cx, |buffer, cx| {
11152                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11153                    });
11154                }
11155            }
11156
11157            this.change_selections(Default::default(), window, cx, |s| {
11158                s.select_anchor_ranges(cursor_positions)
11159            });
11160        });
11161    }
11162
11163    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11165        self.join_lines_impl(true, window, cx);
11166    }
11167
11168    pub fn sort_lines_case_sensitive(
11169        &mut self,
11170        _: &SortLinesCaseSensitive,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11175    }
11176
11177    pub fn sort_lines_by_length(
11178        &mut self,
11179        _: &SortLinesByLength,
11180        window: &mut Window,
11181        cx: &mut Context<Self>,
11182    ) {
11183        self.manipulate_immutable_lines(window, cx, |lines| {
11184            lines.sort_by_key(|&line| line.chars().count())
11185        })
11186    }
11187
11188    pub fn sort_lines_case_insensitive(
11189        &mut self,
11190        _: &SortLinesCaseInsensitive,
11191        window: &mut Window,
11192        cx: &mut Context<Self>,
11193    ) {
11194        self.manipulate_immutable_lines(window, cx, |lines| {
11195            lines.sort_by_key(|line| line.to_lowercase())
11196        })
11197    }
11198
11199    pub fn unique_lines_case_insensitive(
11200        &mut self,
11201        _: &UniqueLinesCaseInsensitive,
11202        window: &mut Window,
11203        cx: &mut Context<Self>,
11204    ) {
11205        self.manipulate_immutable_lines(window, cx, |lines| {
11206            let mut seen = HashSet::default();
11207            lines.retain(|line| seen.insert(line.to_lowercase()));
11208        })
11209    }
11210
11211    pub fn unique_lines_case_sensitive(
11212        &mut self,
11213        _: &UniqueLinesCaseSensitive,
11214        window: &mut Window,
11215        cx: &mut Context<Self>,
11216    ) {
11217        self.manipulate_immutable_lines(window, cx, |lines| {
11218            let mut seen = HashSet::default();
11219            lines.retain(|line| seen.insert(*line));
11220        })
11221    }
11222
11223    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11224        let snapshot = self.buffer.read(cx).snapshot(cx);
11225        for selection in self.selections.disjoint_anchors_arc().iter() {
11226            if snapshot
11227                .language_at(selection.start)
11228                .and_then(|lang| lang.config().wrap_characters.as_ref())
11229                .is_some()
11230            {
11231                return true;
11232            }
11233        }
11234        false
11235    }
11236
11237    fn wrap_selections_in_tag(
11238        &mut self,
11239        _: &WrapSelectionsInTag,
11240        window: &mut Window,
11241        cx: &mut Context<Self>,
11242    ) {
11243        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11244
11245        let snapshot = self.buffer.read(cx).snapshot(cx);
11246
11247        let mut edits = Vec::new();
11248        let mut boundaries = Vec::new();
11249
11250        for selection in self
11251            .selections
11252            .all_adjusted(&self.display_snapshot(cx))
11253            .iter()
11254        {
11255            let Some(wrap_config) = snapshot
11256                .language_at(selection.start)
11257                .and_then(|lang| lang.config().wrap_characters.clone())
11258            else {
11259                continue;
11260            };
11261
11262            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11263            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11264
11265            let start_before = snapshot.anchor_before(selection.start);
11266            let end_after = snapshot.anchor_after(selection.end);
11267
11268            edits.push((start_before..start_before, open_tag));
11269            edits.push((end_after..end_after, close_tag));
11270
11271            boundaries.push((
11272                start_before,
11273                end_after,
11274                wrap_config.start_prefix.len(),
11275                wrap_config.end_suffix.len(),
11276            ));
11277        }
11278
11279        if edits.is_empty() {
11280            return;
11281        }
11282
11283        self.transact(window, cx, |this, window, cx| {
11284            let buffer = this.buffer.update(cx, |buffer, cx| {
11285                buffer.edit(edits, None, cx);
11286                buffer.snapshot(cx)
11287            });
11288
11289            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11290            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11291                boundaries.into_iter()
11292            {
11293                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11294                let close_offset = end_after
11295                    .to_offset(&buffer)
11296                    .saturating_sub_usize(end_suffix_len);
11297                new_selections.push(open_offset..open_offset);
11298                new_selections.push(close_offset..close_offset);
11299            }
11300
11301            this.change_selections(Default::default(), window, cx, |s| {
11302                s.select_ranges(new_selections);
11303            });
11304
11305            this.request_autoscroll(Autoscroll::fit(), cx);
11306        });
11307    }
11308
11309    pub fn toggle_read_only(
11310        &mut self,
11311        _: &workspace::ToggleReadOnlyFile,
11312        _: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11316            buffer.update(cx, |buffer, cx| {
11317                buffer.set_capability(
11318                    match buffer.capability() {
11319                        Capability::ReadWrite => Capability::Read,
11320                        Capability::Read => Capability::ReadWrite,
11321                        Capability::ReadOnly => Capability::ReadOnly,
11322                    },
11323                    cx,
11324                );
11325            })
11326        }
11327    }
11328
11329    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11330        let Some(project) = self.project.clone() else {
11331            return;
11332        };
11333        self.reload(project, window, cx)
11334            .detach_and_notify_err(window, cx);
11335    }
11336
11337    pub fn restore_file(
11338        &mut self,
11339        _: &::git::RestoreFile,
11340        window: &mut Window,
11341        cx: &mut Context<Self>,
11342    ) {
11343        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11344        let mut buffer_ids = HashSet::default();
11345        let snapshot = self.buffer().read(cx).snapshot(cx);
11346        for selection in self
11347            .selections
11348            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11349        {
11350            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11351        }
11352
11353        let buffer = self.buffer().read(cx);
11354        let ranges = buffer_ids
11355            .into_iter()
11356            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11357            .collect::<Vec<_>>();
11358
11359        self.restore_hunks_in_ranges(ranges, window, cx);
11360    }
11361
11362    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11364        let selections = self
11365            .selections
11366            .all(&self.display_snapshot(cx))
11367            .into_iter()
11368            .map(|s| s.range())
11369            .collect();
11370        self.restore_hunks_in_ranges(selections, window, cx);
11371    }
11372
11373    pub fn restore_hunks_in_ranges(
11374        &mut self,
11375        ranges: Vec<Range<Point>>,
11376        window: &mut Window,
11377        cx: &mut Context<Editor>,
11378    ) {
11379        let mut revert_changes = HashMap::default();
11380        let chunk_by = self
11381            .snapshot(window, cx)
11382            .hunks_for_ranges(ranges)
11383            .into_iter()
11384            .chunk_by(|hunk| hunk.buffer_id);
11385        for (buffer_id, hunks) in &chunk_by {
11386            let hunks = hunks.collect::<Vec<_>>();
11387            for hunk in &hunks {
11388                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11389            }
11390            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11391        }
11392        drop(chunk_by);
11393        if !revert_changes.is_empty() {
11394            self.transact(window, cx, |editor, window, cx| {
11395                editor.restore(revert_changes, window, cx);
11396            });
11397        }
11398    }
11399
11400    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11401        if let Some(status) = self
11402            .addons
11403            .iter()
11404            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11405        {
11406            return Some(status);
11407        }
11408        self.project
11409            .as_ref()?
11410            .read(cx)
11411            .status_for_buffer_id(buffer_id, cx)
11412    }
11413
11414    pub fn open_active_item_in_terminal(
11415        &mut self,
11416        _: &OpenInTerminal,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11421            let project_path = buffer.read(cx).project_path(cx)?;
11422            let project = self.project()?.read(cx);
11423            let entry = project.entry_for_path(&project_path, cx)?;
11424            let parent = match &entry.canonical_path {
11425                Some(canonical_path) => canonical_path.to_path_buf(),
11426                None => project.absolute_path(&project_path, cx)?,
11427            }
11428            .parent()?
11429            .to_path_buf();
11430            Some(parent)
11431        }) {
11432            window.dispatch_action(
11433                OpenTerminal {
11434                    working_directory,
11435                    local: false,
11436                }
11437                .boxed_clone(),
11438                cx,
11439            );
11440        }
11441    }
11442
11443    fn set_breakpoint_context_menu(
11444        &mut self,
11445        display_row: DisplayRow,
11446        position: Option<Anchor>,
11447        clicked_point: gpui::Point<Pixels>,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        let source = self
11452            .buffer
11453            .read(cx)
11454            .snapshot(cx)
11455            .anchor_before(Point::new(display_row.0, 0u32));
11456
11457        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11458
11459        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11460            self,
11461            source,
11462            clicked_point,
11463            context_menu,
11464            window,
11465            cx,
11466        );
11467    }
11468
11469    fn add_edit_breakpoint_block(
11470        &mut self,
11471        anchor: Anchor,
11472        breakpoint: &Breakpoint,
11473        edit_action: BreakpointPromptEditAction,
11474        window: &mut Window,
11475        cx: &mut Context<Self>,
11476    ) {
11477        let weak_editor = cx.weak_entity();
11478        let bp_prompt = cx.new(|cx| {
11479            BreakpointPromptEditor::new(
11480                weak_editor,
11481                anchor,
11482                breakpoint.clone(),
11483                edit_action,
11484                window,
11485                cx,
11486            )
11487        });
11488
11489        let height = bp_prompt.update(cx, |this, cx| {
11490            this.prompt
11491                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11492        });
11493        let cloned_prompt = bp_prompt.clone();
11494        let blocks = vec![BlockProperties {
11495            style: BlockStyle::Sticky,
11496            placement: BlockPlacement::Above(anchor),
11497            height: Some(height),
11498            render: Arc::new(move |cx| {
11499                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11500                cloned_prompt.clone().into_any_element()
11501            }),
11502            priority: 0,
11503        }];
11504
11505        let focus_handle = bp_prompt.focus_handle(cx);
11506        window.focus(&focus_handle, cx);
11507
11508        let block_ids = self.insert_blocks(blocks, None, cx);
11509        bp_prompt.update(cx, |prompt, _| {
11510            prompt.add_block_ids(block_ids);
11511        });
11512    }
11513
11514    pub(crate) fn breakpoint_at_row(
11515        &self,
11516        row: u32,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) -> Option<(Anchor, Breakpoint)> {
11520        let snapshot = self.snapshot(window, cx);
11521        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11522
11523        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11524    }
11525
11526    pub(crate) fn breakpoint_at_anchor(
11527        &self,
11528        breakpoint_position: Anchor,
11529        snapshot: &EditorSnapshot,
11530        cx: &mut Context<Self>,
11531    ) -> Option<(Anchor, Breakpoint)> {
11532        let buffer = self
11533            .buffer
11534            .read(cx)
11535            .buffer_for_anchor(breakpoint_position, cx)?;
11536
11537        let enclosing_excerpt = breakpoint_position.excerpt_id;
11538        let buffer_snapshot = buffer.read(cx).snapshot();
11539
11540        let row = buffer_snapshot
11541            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11542            .row;
11543
11544        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11545        let anchor_end = snapshot
11546            .buffer_snapshot()
11547            .anchor_after(Point::new(row, line_len));
11548
11549        self.breakpoint_store
11550            .as_ref()?
11551            .read_with(cx, |breakpoint_store, cx| {
11552                breakpoint_store
11553                    .breakpoints(
11554                        &buffer,
11555                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11556                        &buffer_snapshot,
11557                        cx,
11558                    )
11559                    .next()
11560                    .and_then(|(bp, _)| {
11561                        let breakpoint_row = buffer_snapshot
11562                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11563                            .row;
11564
11565                        if breakpoint_row == row {
11566                            snapshot
11567                                .buffer_snapshot()
11568                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11569                                .map(|position| (position, bp.bp.clone()))
11570                        } else {
11571                            None
11572                        }
11573                    })
11574            })
11575    }
11576
11577    pub fn edit_log_breakpoint(
11578        &mut self,
11579        _: &EditLogBreakpoint,
11580        window: &mut Window,
11581        cx: &mut Context<Self>,
11582    ) {
11583        if self.breakpoint_store.is_none() {
11584            return;
11585        }
11586
11587        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11588            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11589                message: None,
11590                state: BreakpointState::Enabled,
11591                condition: None,
11592                hit_condition: None,
11593            });
11594
11595            self.add_edit_breakpoint_block(
11596                anchor,
11597                &breakpoint,
11598                BreakpointPromptEditAction::Log,
11599                window,
11600                cx,
11601            );
11602        }
11603    }
11604
11605    fn breakpoints_at_cursors(
11606        &self,
11607        window: &mut Window,
11608        cx: &mut Context<Self>,
11609    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11610        let snapshot = self.snapshot(window, cx);
11611        let cursors = self
11612            .selections
11613            .disjoint_anchors_arc()
11614            .iter()
11615            .map(|selection| {
11616                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11617
11618                let breakpoint_position = self
11619                    .breakpoint_at_row(cursor_position.row, window, cx)
11620                    .map(|bp| bp.0)
11621                    .unwrap_or_else(|| {
11622                        snapshot
11623                            .display_snapshot
11624                            .buffer_snapshot()
11625                            .anchor_after(Point::new(cursor_position.row, 0))
11626                    });
11627
11628                let breakpoint = self
11629                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11630                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11631
11632                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11633            })
11634            // 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.
11635            .collect::<HashMap<Anchor, _>>();
11636
11637        cursors.into_iter().collect()
11638    }
11639
11640    pub fn enable_breakpoint(
11641        &mut self,
11642        _: &crate::actions::EnableBreakpoint,
11643        window: &mut Window,
11644        cx: &mut Context<Self>,
11645    ) {
11646        if self.breakpoint_store.is_none() {
11647            return;
11648        }
11649
11650        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11651            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11652                continue;
11653            };
11654            self.edit_breakpoint_at_anchor(
11655                anchor,
11656                breakpoint,
11657                BreakpointEditAction::InvertState,
11658                cx,
11659            );
11660        }
11661    }
11662
11663    pub fn disable_breakpoint(
11664        &mut self,
11665        _: &crate::actions::DisableBreakpoint,
11666        window: &mut Window,
11667        cx: &mut Context<Self>,
11668    ) {
11669        if self.breakpoint_store.is_none() {
11670            return;
11671        }
11672
11673        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11674            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11675                continue;
11676            };
11677            self.edit_breakpoint_at_anchor(
11678                anchor,
11679                breakpoint,
11680                BreakpointEditAction::InvertState,
11681                cx,
11682            );
11683        }
11684    }
11685
11686    pub fn toggle_breakpoint(
11687        &mut self,
11688        _: &crate::actions::ToggleBreakpoint,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        if self.breakpoint_store.is_none() {
11693            return;
11694        }
11695
11696        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11697            if let Some(breakpoint) = breakpoint {
11698                self.edit_breakpoint_at_anchor(
11699                    anchor,
11700                    breakpoint,
11701                    BreakpointEditAction::Toggle,
11702                    cx,
11703                );
11704            } else {
11705                self.edit_breakpoint_at_anchor(
11706                    anchor,
11707                    Breakpoint::new_standard(),
11708                    BreakpointEditAction::Toggle,
11709                    cx,
11710                );
11711            }
11712        }
11713    }
11714
11715    pub fn edit_breakpoint_at_anchor(
11716        &mut self,
11717        breakpoint_position: Anchor,
11718        breakpoint: Breakpoint,
11719        edit_action: BreakpointEditAction,
11720        cx: &mut Context<Self>,
11721    ) {
11722        let Some(breakpoint_store) = &self.breakpoint_store else {
11723            return;
11724        };
11725
11726        let Some(buffer) = self
11727            .buffer
11728            .read(cx)
11729            .buffer_for_anchor(breakpoint_position, cx)
11730        else {
11731            return;
11732        };
11733
11734        breakpoint_store.update(cx, |breakpoint_store, cx| {
11735            breakpoint_store.toggle_breakpoint(
11736                buffer,
11737                BreakpointWithPosition {
11738                    position: breakpoint_position.text_anchor,
11739                    bp: breakpoint,
11740                },
11741                edit_action,
11742                cx,
11743            );
11744        });
11745
11746        cx.notify();
11747    }
11748
11749    #[cfg(any(test, feature = "test-support"))]
11750    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11751        self.breakpoint_store.clone()
11752    }
11753
11754    pub fn prepare_restore_change(
11755        &self,
11756        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11757        hunk: &MultiBufferDiffHunk,
11758        cx: &mut App,
11759    ) -> Option<()> {
11760        if hunk.is_created_file() {
11761            return None;
11762        }
11763        let buffer = self.buffer.read(cx);
11764        let diff = buffer.diff_for(hunk.buffer_id)?;
11765        let buffer = buffer.buffer(hunk.buffer_id)?;
11766        let buffer = buffer.read(cx);
11767        let original_text = diff
11768            .read(cx)
11769            .base_text(cx)
11770            .as_rope()
11771            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11772        let buffer_snapshot = buffer.snapshot();
11773        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11774        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11775            probe
11776                .0
11777                .start
11778                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11779                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11780        }) {
11781            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11782            Some(())
11783        } else {
11784            None
11785        }
11786    }
11787
11788    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11789        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11790    }
11791
11792    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11793        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11794    }
11795
11796    pub fn rotate_selections_forward(
11797        &mut self,
11798        _: &RotateSelectionsForward,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.rotate_selections(window, cx, false)
11803    }
11804
11805    pub fn rotate_selections_backward(
11806        &mut self,
11807        _: &RotateSelectionsBackward,
11808        window: &mut Window,
11809        cx: &mut Context<Self>,
11810    ) {
11811        self.rotate_selections(window, cx, true)
11812    }
11813
11814    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        let display_snapshot = self.display_snapshot(cx);
11817        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11818
11819        if selections.len() < 2 {
11820            return;
11821        }
11822
11823        let (edits, new_selections) = {
11824            let buffer = self.buffer.read(cx).read(cx);
11825            let has_selections = selections.iter().any(|s| !s.is_empty());
11826            if has_selections {
11827                let mut selected_texts: Vec<String> = selections
11828                    .iter()
11829                    .map(|selection| {
11830                        buffer
11831                            .text_for_range(selection.start..selection.end)
11832                            .collect()
11833                    })
11834                    .collect();
11835
11836                if reverse {
11837                    selected_texts.rotate_left(1);
11838                } else {
11839                    selected_texts.rotate_right(1);
11840                }
11841
11842                let mut offset_delta: i64 = 0;
11843                let mut new_selections = Vec::new();
11844                let edits: Vec<_> = selections
11845                    .iter()
11846                    .zip(selected_texts.iter())
11847                    .map(|(selection, new_text)| {
11848                        let old_len = (selection.end.0 - selection.start.0) as i64;
11849                        let new_len = new_text.len() as i64;
11850                        let adjusted_start =
11851                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11852                        let adjusted_end =
11853                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11854
11855                        new_selections.push(Selection {
11856                            id: selection.id,
11857                            start: adjusted_start,
11858                            end: adjusted_end,
11859                            reversed: selection.reversed,
11860                            goal: selection.goal,
11861                        });
11862
11863                        offset_delta += new_len - old_len;
11864                        (selection.start..selection.end, new_text.clone())
11865                    })
11866                    .collect();
11867                (edits, new_selections)
11868            } else {
11869                let mut all_rows: Vec<u32> = selections
11870                    .iter()
11871                    .map(|selection| buffer.offset_to_point(selection.start).row)
11872                    .collect();
11873                all_rows.sort_unstable();
11874                all_rows.dedup();
11875
11876                if all_rows.len() < 2 {
11877                    return;
11878                }
11879
11880                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11881                    .iter()
11882                    .map(|&row| {
11883                        let start = Point::new(row, 0);
11884                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11885                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11886                    })
11887                    .collect();
11888
11889                let mut line_texts: Vec<String> = line_ranges
11890                    .iter()
11891                    .map(|range| buffer.text_for_range(range.clone()).collect())
11892                    .collect();
11893
11894                if reverse {
11895                    line_texts.rotate_left(1);
11896                } else {
11897                    line_texts.rotate_right(1);
11898                }
11899
11900                let edits = line_ranges
11901                    .iter()
11902                    .zip(line_texts.iter())
11903                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11904                    .collect();
11905
11906                let num_rows = all_rows.len();
11907                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11908                    .iter()
11909                    .enumerate()
11910                    .map(|(i, &row)| (row, i))
11911                    .collect();
11912
11913                // Compute new line start offsets after rotation (handles CRLF)
11914                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11915                let first_line_start = line_ranges[0].start.0;
11916                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11917                for text in line_texts.iter().take(num_rows - 1) {
11918                    let prev_start = *new_line_starts.last().unwrap();
11919                    new_line_starts.push(prev_start + text.len() + newline_len);
11920                }
11921
11922                let new_selections = selections
11923                    .iter()
11924                    .map(|selection| {
11925                        let point = buffer.offset_to_point(selection.start);
11926                        let old_index = row_to_index[&point.row];
11927                        let new_index = if reverse {
11928                            (old_index + num_rows - 1) % num_rows
11929                        } else {
11930                            (old_index + 1) % num_rows
11931                        };
11932                        let new_offset =
11933                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11934                        Selection {
11935                            id: selection.id,
11936                            start: new_offset,
11937                            end: new_offset,
11938                            reversed: selection.reversed,
11939                            goal: selection.goal,
11940                        }
11941                    })
11942                    .collect();
11943
11944                (edits, new_selections)
11945            }
11946        };
11947
11948        self.transact(window, cx, |this, window, cx| {
11949            this.buffer.update(cx, |buffer, cx| {
11950                buffer.edit(edits, None, cx);
11951            });
11952            this.change_selections(Default::default(), window, cx, |s| {
11953                s.select(new_selections);
11954            });
11955        });
11956    }
11957
11958    fn manipulate_lines<M>(
11959        &mut self,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962        mut manipulate: M,
11963    ) where
11964        M: FnMut(&str) -> LineManipulationResult,
11965    {
11966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11967
11968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11969        let buffer = self.buffer.read(cx).snapshot(cx);
11970
11971        let mut edits = Vec::new();
11972
11973        let selections = self.selections.all::<Point>(&display_map);
11974        let mut selections = selections.iter().peekable();
11975        let mut contiguous_row_selections = Vec::new();
11976        let mut new_selections = Vec::new();
11977        let mut added_lines = 0;
11978        let mut removed_lines = 0;
11979
11980        while let Some(selection) = selections.next() {
11981            let (start_row, end_row) = consume_contiguous_rows(
11982                &mut contiguous_row_selections,
11983                selection,
11984                &display_map,
11985                &mut selections,
11986            );
11987
11988            let start_point = Point::new(start_row.0, 0);
11989            let end_point = Point::new(
11990                end_row.previous_row().0,
11991                buffer.line_len(end_row.previous_row()),
11992            );
11993            let text = buffer
11994                .text_for_range(start_point..end_point)
11995                .collect::<String>();
11996
11997            let LineManipulationResult {
11998                new_text,
11999                line_count_before,
12000                line_count_after,
12001            } = manipulate(&text);
12002
12003            edits.push((start_point..end_point, new_text));
12004
12005            // Selections must change based on added and removed line count
12006            let start_row =
12007                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12008            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12009            new_selections.push(Selection {
12010                id: selection.id,
12011                start: start_row,
12012                end: end_row,
12013                goal: SelectionGoal::None,
12014                reversed: selection.reversed,
12015            });
12016
12017            if line_count_after > line_count_before {
12018                added_lines += line_count_after - line_count_before;
12019            } else if line_count_before > line_count_after {
12020                removed_lines += line_count_before - line_count_after;
12021            }
12022        }
12023
12024        self.transact(window, cx, |this, window, cx| {
12025            let buffer = this.buffer.update(cx, |buffer, cx| {
12026                buffer.edit(edits, None, cx);
12027                buffer.snapshot(cx)
12028            });
12029
12030            // Recalculate offsets on newly edited buffer
12031            let new_selections = new_selections
12032                .iter()
12033                .map(|s| {
12034                    let start_point = Point::new(s.start.0, 0);
12035                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12036                    Selection {
12037                        id: s.id,
12038                        start: buffer.point_to_offset(start_point),
12039                        end: buffer.point_to_offset(end_point),
12040                        goal: s.goal,
12041                        reversed: s.reversed,
12042                    }
12043                })
12044                .collect();
12045
12046            this.change_selections(Default::default(), window, cx, |s| {
12047                s.select(new_selections);
12048            });
12049
12050            this.request_autoscroll(Autoscroll::fit(), cx);
12051        });
12052    }
12053
12054    fn manipulate_immutable_lines<Fn>(
12055        &mut self,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058        mut callback: Fn,
12059    ) where
12060        Fn: FnMut(&mut Vec<&str>),
12061    {
12062        self.manipulate_lines(window, cx, |text| {
12063            let mut lines: Vec<&str> = text.split('\n').collect();
12064            let line_count_before = lines.len();
12065
12066            callback(&mut lines);
12067
12068            LineManipulationResult {
12069                new_text: lines.join("\n"),
12070                line_count_before,
12071                line_count_after: lines.len(),
12072            }
12073        });
12074    }
12075
12076    fn manipulate_mutable_lines<Fn>(
12077        &mut self,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080        mut callback: Fn,
12081    ) where
12082        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12083    {
12084        self.manipulate_lines(window, cx, |text| {
12085            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12086            let line_count_before = lines.len();
12087
12088            callback(&mut lines);
12089
12090            LineManipulationResult {
12091                new_text: lines.join("\n"),
12092                line_count_before,
12093                line_count_after: lines.len(),
12094            }
12095        });
12096    }
12097
12098    pub fn convert_indentation_to_spaces(
12099        &mut self,
12100        _: &ConvertIndentationToSpaces,
12101        window: &mut Window,
12102        cx: &mut Context<Self>,
12103    ) {
12104        let settings = self.buffer.read(cx).language_settings(cx);
12105        let tab_size = settings.tab_size.get() as usize;
12106
12107        self.manipulate_mutable_lines(window, cx, |lines| {
12108            // Allocates a reasonably sized scratch buffer once for the whole loop
12109            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12110            // Avoids recomputing spaces that could be inserted many times
12111            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12112                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12113                .collect();
12114
12115            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12116                let mut chars = line.as_ref().chars();
12117                let mut col = 0;
12118                let mut changed = false;
12119
12120                for ch in chars.by_ref() {
12121                    match ch {
12122                        ' ' => {
12123                            reindented_line.push(' ');
12124                            col += 1;
12125                        }
12126                        '\t' => {
12127                            // \t are converted to spaces depending on the current column
12128                            let spaces_len = tab_size - (col % tab_size);
12129                            reindented_line.extend(&space_cache[spaces_len - 1]);
12130                            col += spaces_len;
12131                            changed = true;
12132                        }
12133                        _ => {
12134                            // If we dont append before break, the character is consumed
12135                            reindented_line.push(ch);
12136                            break;
12137                        }
12138                    }
12139                }
12140
12141                if !changed {
12142                    reindented_line.clear();
12143                    continue;
12144                }
12145                // Append the rest of the line and replace old reference with new one
12146                reindented_line.extend(chars);
12147                *line = Cow::Owned(reindented_line.clone());
12148                reindented_line.clear();
12149            }
12150        });
12151    }
12152
12153    pub fn convert_indentation_to_tabs(
12154        &mut self,
12155        _: &ConvertIndentationToTabs,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        let settings = self.buffer.read(cx).language_settings(cx);
12160        let tab_size = settings.tab_size.get() as usize;
12161
12162        self.manipulate_mutable_lines(window, cx, |lines| {
12163            // Allocates a reasonably sized buffer once for the whole loop
12164            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12165            // Avoids recomputing spaces that could be inserted many times
12166            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12167                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12168                .collect();
12169
12170            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12171                let mut chars = line.chars();
12172                let mut spaces_count = 0;
12173                let mut first_non_indent_char = None;
12174                let mut changed = false;
12175
12176                for ch in chars.by_ref() {
12177                    match ch {
12178                        ' ' => {
12179                            // Keep track of spaces. Append \t when we reach tab_size
12180                            spaces_count += 1;
12181                            changed = true;
12182                            if spaces_count == tab_size {
12183                                reindented_line.push('\t');
12184                                spaces_count = 0;
12185                            }
12186                        }
12187                        '\t' => {
12188                            reindented_line.push('\t');
12189                            spaces_count = 0;
12190                        }
12191                        _ => {
12192                            // Dont append it yet, we might have remaining spaces
12193                            first_non_indent_char = Some(ch);
12194                            break;
12195                        }
12196                    }
12197                }
12198
12199                if !changed {
12200                    reindented_line.clear();
12201                    continue;
12202                }
12203                // Remaining spaces that didn't make a full tab stop
12204                if spaces_count > 0 {
12205                    reindented_line.extend(&space_cache[spaces_count - 1]);
12206                }
12207                // If we consume an extra character that was not indentation, add it back
12208                if let Some(extra_char) = first_non_indent_char {
12209                    reindented_line.push(extra_char);
12210                }
12211                // Append the rest of the line and replace old reference with new one
12212                reindented_line.extend(chars);
12213                *line = Cow::Owned(reindented_line.clone());
12214                reindented_line.clear();
12215            }
12216        });
12217    }
12218
12219    pub fn convert_to_upper_case(
12220        &mut self,
12221        _: &ConvertToUpperCase,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        self.manipulate_text(window, cx, |text| text.to_uppercase())
12226    }
12227
12228    pub fn convert_to_lower_case(
12229        &mut self,
12230        _: &ConvertToLowerCase,
12231        window: &mut Window,
12232        cx: &mut Context<Self>,
12233    ) {
12234        self.manipulate_text(window, cx, |text| text.to_lowercase())
12235    }
12236
12237    pub fn convert_to_title_case(
12238        &mut self,
12239        _: &ConvertToTitleCase,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        self.manipulate_text(window, cx, |text| {
12244            text.split('\n')
12245                .map(|line| line.to_case(Case::Title))
12246                .join("\n")
12247        })
12248    }
12249
12250    pub fn convert_to_snake_case(
12251        &mut self,
12252        _: &ConvertToSnakeCase,
12253        window: &mut Window,
12254        cx: &mut Context<Self>,
12255    ) {
12256        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12257    }
12258
12259    pub fn convert_to_kebab_case(
12260        &mut self,
12261        _: &ConvertToKebabCase,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) {
12265        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12266    }
12267
12268    pub fn convert_to_upper_camel_case(
12269        &mut self,
12270        _: &ConvertToUpperCamelCase,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) {
12274        self.manipulate_text(window, cx, |text| {
12275            text.split('\n')
12276                .map(|line| line.to_case(Case::UpperCamel))
12277                .join("\n")
12278        })
12279    }
12280
12281    pub fn convert_to_lower_camel_case(
12282        &mut self,
12283        _: &ConvertToLowerCamelCase,
12284        window: &mut Window,
12285        cx: &mut Context<Self>,
12286    ) {
12287        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12288    }
12289
12290    pub fn convert_to_opposite_case(
12291        &mut self,
12292        _: &ConvertToOppositeCase,
12293        window: &mut Window,
12294        cx: &mut Context<Self>,
12295    ) {
12296        self.manipulate_text(window, cx, |text| {
12297            text.chars()
12298                .fold(String::with_capacity(text.len()), |mut t, c| {
12299                    if c.is_uppercase() {
12300                        t.extend(c.to_lowercase());
12301                    } else {
12302                        t.extend(c.to_uppercase());
12303                    }
12304                    t
12305                })
12306        })
12307    }
12308
12309    pub fn convert_to_sentence_case(
12310        &mut self,
12311        _: &ConvertToSentenceCase,
12312        window: &mut Window,
12313        cx: &mut Context<Self>,
12314    ) {
12315        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12316    }
12317
12318    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12319        self.manipulate_text(window, cx, |text| {
12320            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12321            if has_upper_case_characters {
12322                text.to_lowercase()
12323            } else {
12324                text.to_uppercase()
12325            }
12326        })
12327    }
12328
12329    pub fn convert_to_rot13(
12330        &mut self,
12331        _: &ConvertToRot13,
12332        window: &mut Window,
12333        cx: &mut Context<Self>,
12334    ) {
12335        self.manipulate_text(window, cx, |text| {
12336            text.chars()
12337                .map(|c| match c {
12338                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12339                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12340                    _ => c,
12341                })
12342                .collect()
12343        })
12344    }
12345
12346    pub fn convert_to_rot47(
12347        &mut self,
12348        _: &ConvertToRot47,
12349        window: &mut Window,
12350        cx: &mut Context<Self>,
12351    ) {
12352        self.manipulate_text(window, cx, |text| {
12353            text.chars()
12354                .map(|c| {
12355                    let code_point = c as u32;
12356                    if code_point >= 33 && code_point <= 126 {
12357                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12358                    }
12359                    c
12360                })
12361                .collect()
12362        })
12363    }
12364
12365    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12366    where
12367        Fn: FnMut(&str) -> String,
12368    {
12369        let buffer = self.buffer.read(cx).snapshot(cx);
12370
12371        let mut new_selections = Vec::new();
12372        let mut edits = Vec::new();
12373        let mut selection_adjustment = 0isize;
12374
12375        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12376            let selection_is_empty = selection.is_empty();
12377
12378            let (start, end) = if selection_is_empty {
12379                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12380                (word_range.start, word_range.end)
12381            } else {
12382                (
12383                    buffer.point_to_offset(selection.start),
12384                    buffer.point_to_offset(selection.end),
12385                )
12386            };
12387
12388            let text = buffer.text_for_range(start..end).collect::<String>();
12389            let old_length = text.len() as isize;
12390            let text = callback(&text);
12391
12392            new_selections.push(Selection {
12393                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12394                end: MultiBufferOffset(
12395                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12396                ),
12397                goal: SelectionGoal::None,
12398                id: selection.id,
12399                reversed: selection.reversed,
12400            });
12401
12402            selection_adjustment += old_length - text.len() as isize;
12403
12404            edits.push((start..end, text));
12405        }
12406
12407        self.transact(window, cx, |this, window, cx| {
12408            this.buffer.update(cx, |buffer, cx| {
12409                buffer.edit(edits, None, cx);
12410            });
12411
12412            this.change_selections(Default::default(), window, cx, |s| {
12413                s.select(new_selections);
12414            });
12415
12416            this.request_autoscroll(Autoscroll::fit(), cx);
12417        });
12418    }
12419
12420    pub fn move_selection_on_drop(
12421        &mut self,
12422        selection: &Selection<Anchor>,
12423        target: DisplayPoint,
12424        is_cut: bool,
12425        window: &mut Window,
12426        cx: &mut Context<Self>,
12427    ) {
12428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12429        let buffer = display_map.buffer_snapshot();
12430        let mut edits = Vec::new();
12431        let insert_point = display_map
12432            .clip_point(target, Bias::Left)
12433            .to_point(&display_map);
12434        let text = buffer
12435            .text_for_range(selection.start..selection.end)
12436            .collect::<String>();
12437        if is_cut {
12438            edits.push(((selection.start..selection.end), String::new()));
12439        }
12440        let insert_anchor = buffer.anchor_before(insert_point);
12441        edits.push(((insert_anchor..insert_anchor), text));
12442        let last_edit_start = insert_anchor.bias_left(buffer);
12443        let last_edit_end = insert_anchor.bias_right(buffer);
12444        self.transact(window, cx, |this, window, cx| {
12445            this.buffer.update(cx, |buffer, cx| {
12446                buffer.edit(edits, None, cx);
12447            });
12448            this.change_selections(Default::default(), window, cx, |s| {
12449                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12450            });
12451        });
12452    }
12453
12454    pub fn clear_selection_drag_state(&mut self) {
12455        self.selection_drag_state = SelectionDragState::None;
12456    }
12457
12458    pub fn duplicate(
12459        &mut self,
12460        upwards: bool,
12461        whole_lines: bool,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) {
12465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12466
12467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12468        let buffer = display_map.buffer_snapshot();
12469        let selections = self.selections.all::<Point>(&display_map);
12470
12471        let mut edits = Vec::new();
12472        let mut selections_iter = selections.iter().peekable();
12473        while let Some(selection) = selections_iter.next() {
12474            let mut rows = selection.spanned_rows(false, &display_map);
12475            // duplicate line-wise
12476            if whole_lines || selection.start == selection.end {
12477                // Avoid duplicating the same lines twice.
12478                while let Some(next_selection) = selections_iter.peek() {
12479                    let next_rows = next_selection.spanned_rows(false, &display_map);
12480                    if next_rows.start < rows.end {
12481                        rows.end = next_rows.end;
12482                        selections_iter.next().unwrap();
12483                    } else {
12484                        break;
12485                    }
12486                }
12487
12488                // Copy the text from the selected row region and splice it either at the start
12489                // or end of the region.
12490                let start = Point::new(rows.start.0, 0);
12491                let end = Point::new(
12492                    rows.end.previous_row().0,
12493                    buffer.line_len(rows.end.previous_row()),
12494                );
12495
12496                let mut text = buffer.text_for_range(start..end).collect::<String>();
12497
12498                let insert_location = if upwards {
12499                    // When duplicating upward, we need to insert before the current line.
12500                    // If we're on the last line and it doesn't end with a newline,
12501                    // we need to add a newline before the duplicated content.
12502                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12503                        && buffer.max_point().column > 0
12504                        && !text.ends_with('\n');
12505
12506                    if needs_leading_newline {
12507                        text.insert(0, '\n');
12508                        end
12509                    } else {
12510                        text.push('\n');
12511                        Point::new(rows.start.0, 0)
12512                    }
12513                } else {
12514                    text.push('\n');
12515                    start
12516                };
12517                edits.push((insert_location..insert_location, text));
12518            } else {
12519                // duplicate character-wise
12520                let start = selection.start;
12521                let end = selection.end;
12522                let text = buffer.text_for_range(start..end).collect::<String>();
12523                edits.push((selection.end..selection.end, text));
12524            }
12525        }
12526
12527        self.transact(window, cx, |this, window, cx| {
12528            this.buffer.update(cx, |buffer, cx| {
12529                buffer.edit(edits, None, cx);
12530            });
12531
12532            // When duplicating upward with whole lines, move the cursor to the duplicated line
12533            if upwards && whole_lines {
12534                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12535
12536                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12537                    let mut new_ranges = Vec::new();
12538                    let selections = s.all::<Point>(&display_map);
12539                    let mut selections_iter = selections.iter().peekable();
12540
12541                    while let Some(first_selection) = selections_iter.next() {
12542                        // Group contiguous selections together to find the total row span
12543                        let mut group_selections = vec![first_selection];
12544                        let mut rows = first_selection.spanned_rows(false, &display_map);
12545
12546                        while let Some(next_selection) = selections_iter.peek() {
12547                            let next_rows = next_selection.spanned_rows(false, &display_map);
12548                            if next_rows.start < rows.end {
12549                                rows.end = next_rows.end;
12550                                group_selections.push(selections_iter.next().unwrap());
12551                            } else {
12552                                break;
12553                            }
12554                        }
12555
12556                        let row_count = rows.end.0 - rows.start.0;
12557
12558                        // Move all selections in this group up by the total number of duplicated rows
12559                        for selection in group_selections {
12560                            let new_start = Point::new(
12561                                selection.start.row.saturating_sub(row_count),
12562                                selection.start.column,
12563                            );
12564
12565                            let new_end = Point::new(
12566                                selection.end.row.saturating_sub(row_count),
12567                                selection.end.column,
12568                            );
12569
12570                            new_ranges.push(new_start..new_end);
12571                        }
12572                    }
12573
12574                    s.select_ranges(new_ranges);
12575                });
12576            }
12577
12578            this.request_autoscroll(Autoscroll::fit(), cx);
12579        });
12580    }
12581
12582    pub fn duplicate_line_up(
12583        &mut self,
12584        _: &DuplicateLineUp,
12585        window: &mut Window,
12586        cx: &mut Context<Self>,
12587    ) {
12588        self.duplicate(true, true, window, cx);
12589    }
12590
12591    pub fn duplicate_line_down(
12592        &mut self,
12593        _: &DuplicateLineDown,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        self.duplicate(false, true, window, cx);
12598    }
12599
12600    pub fn duplicate_selection(
12601        &mut self,
12602        _: &DuplicateSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        self.duplicate(false, false, window, cx);
12607    }
12608
12609    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12611        if self.mode.is_single_line() {
12612            cx.propagate();
12613            return;
12614        }
12615
12616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12617        let buffer = self.buffer.read(cx).snapshot(cx);
12618
12619        let mut edits = Vec::new();
12620        let mut unfold_ranges = Vec::new();
12621        let mut refold_creases = Vec::new();
12622
12623        let selections = self.selections.all::<Point>(&display_map);
12624        let mut selections = selections.iter().peekable();
12625        let mut contiguous_row_selections = Vec::new();
12626        let mut new_selections = Vec::new();
12627
12628        while let Some(selection) = selections.next() {
12629            // Find all the selections that span a contiguous row range
12630            let (start_row, end_row) = consume_contiguous_rows(
12631                &mut contiguous_row_selections,
12632                selection,
12633                &display_map,
12634                &mut selections,
12635            );
12636
12637            // Move the text spanned by the row range to be before the line preceding the row range
12638            if start_row.0 > 0 {
12639                let range_to_move = Point::new(
12640                    start_row.previous_row().0,
12641                    buffer.line_len(start_row.previous_row()),
12642                )
12643                    ..Point::new(
12644                        end_row.previous_row().0,
12645                        buffer.line_len(end_row.previous_row()),
12646                    );
12647                let insertion_point = display_map
12648                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12649                    .0;
12650
12651                // Don't move lines across excerpts
12652                if buffer
12653                    .excerpt_containing(insertion_point..range_to_move.end)
12654                    .is_some()
12655                {
12656                    let text = buffer
12657                        .text_for_range(range_to_move.clone())
12658                        .flat_map(|s| s.chars())
12659                        .skip(1)
12660                        .chain(['\n'])
12661                        .collect::<String>();
12662
12663                    edits.push((
12664                        buffer.anchor_after(range_to_move.start)
12665                            ..buffer.anchor_before(range_to_move.end),
12666                        String::new(),
12667                    ));
12668                    let insertion_anchor = buffer.anchor_after(insertion_point);
12669                    edits.push((insertion_anchor..insertion_anchor, text));
12670
12671                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12672
12673                    // Move selections up
12674                    new_selections.extend(contiguous_row_selections.drain(..).map(
12675                        |mut selection| {
12676                            selection.start.row -= row_delta;
12677                            selection.end.row -= row_delta;
12678                            selection
12679                        },
12680                    ));
12681
12682                    // Move folds up
12683                    unfold_ranges.push(range_to_move.clone());
12684                    for fold in display_map.folds_in_range(
12685                        buffer.anchor_before(range_to_move.start)
12686                            ..buffer.anchor_after(range_to_move.end),
12687                    ) {
12688                        let mut start = fold.range.start.to_point(&buffer);
12689                        let mut end = fold.range.end.to_point(&buffer);
12690                        start.row -= row_delta;
12691                        end.row -= row_delta;
12692                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12693                    }
12694                }
12695            }
12696
12697            // If we didn't move line(s), preserve the existing selections
12698            new_selections.append(&mut contiguous_row_selections);
12699        }
12700
12701        self.transact(window, cx, |this, window, cx| {
12702            this.unfold_ranges(&unfold_ranges, true, true, cx);
12703            this.buffer.update(cx, |buffer, cx| {
12704                for (range, text) in edits {
12705                    buffer.edit([(range, text)], None, cx);
12706                }
12707            });
12708            this.fold_creases(refold_creases, true, window, cx);
12709            this.change_selections(Default::default(), window, cx, |s| {
12710                s.select(new_selections);
12711            })
12712        });
12713    }
12714
12715    pub fn move_line_down(
12716        &mut self,
12717        _: &MoveLineDown,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12722        if self.mode.is_single_line() {
12723            cx.propagate();
12724            return;
12725        }
12726
12727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12728        let buffer = self.buffer.read(cx).snapshot(cx);
12729
12730        let mut edits = Vec::new();
12731        let mut unfold_ranges = Vec::new();
12732        let mut refold_creases = Vec::new();
12733
12734        let selections = self.selections.all::<Point>(&display_map);
12735        let mut selections = selections.iter().peekable();
12736        let mut contiguous_row_selections = Vec::new();
12737        let mut new_selections = Vec::new();
12738
12739        while let Some(selection) = selections.next() {
12740            // Find all the selections that span a contiguous row range
12741            let (start_row, end_row) = consume_contiguous_rows(
12742                &mut contiguous_row_selections,
12743                selection,
12744                &display_map,
12745                &mut selections,
12746            );
12747
12748            // Move the text spanned by the row range to be after the last line of the row range
12749            if end_row.0 <= buffer.max_point().row {
12750                let range_to_move =
12751                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12752                let insertion_point = display_map
12753                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12754                    .0;
12755
12756                // Don't move lines across excerpt boundaries
12757                if buffer
12758                    .excerpt_containing(range_to_move.start..insertion_point)
12759                    .is_some()
12760                {
12761                    let mut text = String::from("\n");
12762                    text.extend(buffer.text_for_range(range_to_move.clone()));
12763                    text.pop(); // Drop trailing newline
12764                    edits.push((
12765                        buffer.anchor_after(range_to_move.start)
12766                            ..buffer.anchor_before(range_to_move.end),
12767                        String::new(),
12768                    ));
12769                    let insertion_anchor = buffer.anchor_after(insertion_point);
12770                    edits.push((insertion_anchor..insertion_anchor, text));
12771
12772                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12773
12774                    // Move selections down
12775                    new_selections.extend(contiguous_row_selections.drain(..).map(
12776                        |mut selection| {
12777                            selection.start.row += row_delta;
12778                            selection.end.row += row_delta;
12779                            selection
12780                        },
12781                    ));
12782
12783                    // Move folds down
12784                    unfold_ranges.push(range_to_move.clone());
12785                    for fold in display_map.folds_in_range(
12786                        buffer.anchor_before(range_to_move.start)
12787                            ..buffer.anchor_after(range_to_move.end),
12788                    ) {
12789                        let mut start = fold.range.start.to_point(&buffer);
12790                        let mut end = fold.range.end.to_point(&buffer);
12791                        start.row += row_delta;
12792                        end.row += row_delta;
12793                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12794                    }
12795                }
12796            }
12797
12798            // If we didn't move line(s), preserve the existing selections
12799            new_selections.append(&mut contiguous_row_selections);
12800        }
12801
12802        self.transact(window, cx, |this, window, cx| {
12803            this.unfold_ranges(&unfold_ranges, true, true, cx);
12804            this.buffer.update(cx, |buffer, cx| {
12805                for (range, text) in edits {
12806                    buffer.edit([(range, text)], None, cx);
12807                }
12808            });
12809            this.fold_creases(refold_creases, true, window, cx);
12810            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12811        });
12812    }
12813
12814    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12816        let text_layout_details = &self.text_layout_details(window);
12817        self.transact(window, cx, |this, window, cx| {
12818            let edits = this.change_selections(Default::default(), window, cx, |s| {
12819                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12820                s.move_with(|display_map, selection| {
12821                    if !selection.is_empty() {
12822                        return;
12823                    }
12824
12825                    let mut head = selection.head();
12826                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12827                    if head.column() == display_map.line_len(head.row()) {
12828                        transpose_offset = display_map
12829                            .buffer_snapshot()
12830                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12831                    }
12832
12833                    if transpose_offset == MultiBufferOffset(0) {
12834                        return;
12835                    }
12836
12837                    *head.column_mut() += 1;
12838                    head = display_map.clip_point(head, Bias::Right);
12839                    let goal = SelectionGoal::HorizontalPosition(
12840                        display_map
12841                            .x_for_display_point(head, text_layout_details)
12842                            .into(),
12843                    );
12844                    selection.collapse_to(head, goal);
12845
12846                    let transpose_start = display_map
12847                        .buffer_snapshot()
12848                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12849                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12850                        let transpose_end = display_map
12851                            .buffer_snapshot()
12852                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12853                        if let Some(ch) = display_map
12854                            .buffer_snapshot()
12855                            .chars_at(transpose_start)
12856                            .next()
12857                        {
12858                            edits.push((transpose_start..transpose_offset, String::new()));
12859                            edits.push((transpose_end..transpose_end, ch.to_string()));
12860                        }
12861                    }
12862                });
12863                edits
12864            });
12865            this.buffer
12866                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12867            let selections = this
12868                .selections
12869                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12870            this.change_selections(Default::default(), window, cx, |s| {
12871                s.select(selections);
12872            });
12873        });
12874    }
12875
12876    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12878        if self.mode.is_single_line() {
12879            cx.propagate();
12880            return;
12881        }
12882
12883        self.rewrap_impl(RewrapOptions::default(), cx)
12884    }
12885
12886    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12887        let buffer = self.buffer.read(cx).snapshot(cx);
12888        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12889
12890        #[derive(Clone, Debug, PartialEq)]
12891        enum CommentFormat {
12892            /// single line comment, with prefix for line
12893            Line(String),
12894            /// single line within a block comment, with prefix for line
12895            BlockLine(String),
12896            /// a single line of a block comment that includes the initial delimiter
12897            BlockCommentWithStart(BlockCommentConfig),
12898            /// a single line of a block comment that includes the ending delimiter
12899            BlockCommentWithEnd(BlockCommentConfig),
12900        }
12901
12902        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12903        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12904            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12905                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12906                .peekable();
12907
12908            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12909                row
12910            } else {
12911                return Vec::new();
12912            };
12913
12914            let language_settings = buffer.language_settings_at(selection.head(), cx);
12915            let language_scope = buffer.language_scope_at(selection.head());
12916
12917            let indent_and_prefix_for_row =
12918                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12919                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12920                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12921                        &language_scope
12922                    {
12923                        let indent_end = Point::new(row, indent.len);
12924                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12925                        let line_text_after_indent = buffer
12926                            .text_for_range(indent_end..line_end)
12927                            .collect::<String>();
12928
12929                        let is_within_comment_override = buffer
12930                            .language_scope_at(indent_end)
12931                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12932                        let comment_delimiters = if is_within_comment_override {
12933                            // we are within a comment syntax node, but we don't
12934                            // yet know what kind of comment: block, doc or line
12935                            match (
12936                                language_scope.documentation_comment(),
12937                                language_scope.block_comment(),
12938                            ) {
12939                                (Some(config), _) | (_, Some(config))
12940                                    if buffer.contains_str_at(indent_end, &config.start) =>
12941                                {
12942                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12943                                }
12944                                (Some(config), _) | (_, Some(config))
12945                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12946                                {
12947                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12948                                }
12949                                (Some(config), _) | (_, Some(config))
12950                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12951                                {
12952                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12953                                }
12954                                (_, _) => language_scope
12955                                    .line_comment_prefixes()
12956                                    .iter()
12957                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12958                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12959                            }
12960                        } else {
12961                            // we not in an overridden comment node, but we may
12962                            // be within a non-overridden line comment node
12963                            language_scope
12964                                .line_comment_prefixes()
12965                                .iter()
12966                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12967                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12968                        };
12969
12970                        let rewrap_prefix = language_scope
12971                            .rewrap_prefixes()
12972                            .iter()
12973                            .find_map(|prefix_regex| {
12974                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12975                                    if mat.start() == 0 {
12976                                        Some(mat.as_str().to_string())
12977                                    } else {
12978                                        None
12979                                    }
12980                                })
12981                            })
12982                            .flatten();
12983                        (comment_delimiters, rewrap_prefix)
12984                    } else {
12985                        (None, None)
12986                    };
12987                    (indent, comment_prefix, rewrap_prefix)
12988                };
12989
12990            let mut ranges = Vec::new();
12991            let from_empty_selection = selection.is_empty();
12992
12993            let mut current_range_start = first_row;
12994            let mut prev_row = first_row;
12995            let (
12996                mut current_range_indent,
12997                mut current_range_comment_delimiters,
12998                mut current_range_rewrap_prefix,
12999            ) = indent_and_prefix_for_row(first_row);
13000
13001            for row in non_blank_rows_iter.skip(1) {
13002                let has_paragraph_break = row > prev_row + 1;
13003
13004                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13005                    indent_and_prefix_for_row(row);
13006
13007                let has_indent_change = row_indent != current_range_indent;
13008                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13009
13010                let has_boundary_change = has_comment_change
13011                    || row_rewrap_prefix.is_some()
13012                    || (has_indent_change && current_range_comment_delimiters.is_some());
13013
13014                if has_paragraph_break || has_boundary_change {
13015                    ranges.push((
13016                        language_settings.clone(),
13017                        Point::new(current_range_start, 0)
13018                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13019                        current_range_indent,
13020                        current_range_comment_delimiters.clone(),
13021                        current_range_rewrap_prefix.clone(),
13022                        from_empty_selection,
13023                    ));
13024                    current_range_start = row;
13025                    current_range_indent = row_indent;
13026                    current_range_comment_delimiters = row_comment_delimiters;
13027                    current_range_rewrap_prefix = row_rewrap_prefix;
13028                }
13029                prev_row = row;
13030            }
13031
13032            ranges.push((
13033                language_settings.clone(),
13034                Point::new(current_range_start, 0)
13035                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13036                current_range_indent,
13037                current_range_comment_delimiters,
13038                current_range_rewrap_prefix,
13039                from_empty_selection,
13040            ));
13041
13042            ranges
13043        });
13044
13045        let mut edits = Vec::new();
13046        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13047
13048        for (
13049            language_settings,
13050            wrap_range,
13051            mut indent_size,
13052            comment_prefix,
13053            rewrap_prefix,
13054            from_empty_selection,
13055        ) in wrap_ranges
13056        {
13057            let mut start_row = wrap_range.start.row;
13058            let mut end_row = wrap_range.end.row;
13059
13060            // Skip selections that overlap with a range that has already been rewrapped.
13061            let selection_range = start_row..end_row;
13062            if rewrapped_row_ranges
13063                .iter()
13064                .any(|range| range.overlaps(&selection_range))
13065            {
13066                continue;
13067            }
13068
13069            let tab_size = language_settings.tab_size;
13070
13071            let (line_prefix, inside_comment) = match &comment_prefix {
13072                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13073                    (Some(prefix.as_str()), true)
13074                }
13075                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13076                    (Some(prefix.as_ref()), true)
13077                }
13078                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13079                    start: _,
13080                    end: _,
13081                    prefix,
13082                    tab_size,
13083                })) => {
13084                    indent_size.len += tab_size;
13085                    (Some(prefix.as_ref()), true)
13086                }
13087                None => (None, false),
13088            };
13089            let indent_prefix = indent_size.chars().collect::<String>();
13090            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13091
13092            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13093                RewrapBehavior::InComments => inside_comment,
13094                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13095                RewrapBehavior::Anywhere => true,
13096            };
13097
13098            let should_rewrap = options.override_language_settings
13099                || allow_rewrap_based_on_language
13100                || self.hard_wrap.is_some();
13101            if !should_rewrap {
13102                continue;
13103            }
13104
13105            if from_empty_selection {
13106                'expand_upwards: while start_row > 0 {
13107                    let prev_row = start_row - 1;
13108                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13109                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13110                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13111                    {
13112                        start_row = prev_row;
13113                    } else {
13114                        break 'expand_upwards;
13115                    }
13116                }
13117
13118                'expand_downwards: while end_row < buffer.max_point().row {
13119                    let next_row = end_row + 1;
13120                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13121                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13122                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13123                    {
13124                        end_row = next_row;
13125                    } else {
13126                        break 'expand_downwards;
13127                    }
13128                }
13129            }
13130
13131            let start = Point::new(start_row, 0);
13132            let start_offset = ToOffset::to_offset(&start, &buffer);
13133            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13134            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13135            let mut first_line_delimiter = None;
13136            let mut last_line_delimiter = None;
13137            let Some(lines_without_prefixes) = selection_text
13138                .lines()
13139                .enumerate()
13140                .map(|(ix, line)| {
13141                    let line_trimmed = line.trim_start();
13142                    if rewrap_prefix.is_some() && ix > 0 {
13143                        Ok(line_trimmed)
13144                    } else if let Some(
13145                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13146                            start,
13147                            prefix,
13148                            end,
13149                            tab_size,
13150                        })
13151                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13152                            start,
13153                            prefix,
13154                            end,
13155                            tab_size,
13156                        }),
13157                    ) = &comment_prefix
13158                    {
13159                        let line_trimmed = line_trimmed
13160                            .strip_prefix(start.as_ref())
13161                            .map(|s| {
13162                                let mut indent_size = indent_size;
13163                                indent_size.len -= tab_size;
13164                                let indent_prefix: String = indent_size.chars().collect();
13165                                first_line_delimiter = Some((indent_prefix, start));
13166                                s.trim_start()
13167                            })
13168                            .unwrap_or(line_trimmed);
13169                        let line_trimmed = line_trimmed
13170                            .strip_suffix(end.as_ref())
13171                            .map(|s| {
13172                                last_line_delimiter = Some(end);
13173                                s.trim_end()
13174                            })
13175                            .unwrap_or(line_trimmed);
13176                        let line_trimmed = line_trimmed
13177                            .strip_prefix(prefix.as_ref())
13178                            .unwrap_or(line_trimmed);
13179                        Ok(line_trimmed)
13180                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13181                        line_trimmed.strip_prefix(prefix).with_context(|| {
13182                            format!("line did not start with prefix {prefix:?}: {line:?}")
13183                        })
13184                    } else {
13185                        line_trimmed
13186                            .strip_prefix(&line_prefix.trim_start())
13187                            .with_context(|| {
13188                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13189                            })
13190                    }
13191                })
13192                .collect::<Result<Vec<_>, _>>()
13193                .log_err()
13194            else {
13195                continue;
13196            };
13197
13198            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13199                buffer
13200                    .language_settings_at(Point::new(start_row, 0), cx)
13201                    .preferred_line_length as usize
13202            });
13203
13204            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13205                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13206            } else {
13207                line_prefix.clone()
13208            };
13209
13210            let wrapped_text = {
13211                let mut wrapped_text = wrap_with_prefix(
13212                    line_prefix,
13213                    subsequent_lines_prefix,
13214                    lines_without_prefixes.join("\n"),
13215                    wrap_column,
13216                    tab_size,
13217                    options.preserve_existing_whitespace,
13218                );
13219
13220                if let Some((indent, delimiter)) = first_line_delimiter {
13221                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13222                }
13223                if let Some(last_line) = last_line_delimiter {
13224                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13225                }
13226
13227                wrapped_text
13228            };
13229
13230            // TODO: should always use char-based diff while still supporting cursor behavior that
13231            // matches vim.
13232            let mut diff_options = DiffOptions::default();
13233            if options.override_language_settings {
13234                diff_options.max_word_diff_len = 0;
13235                diff_options.max_word_diff_line_count = 0;
13236            } else {
13237                diff_options.max_word_diff_len = usize::MAX;
13238                diff_options.max_word_diff_line_count = usize::MAX;
13239            }
13240
13241            for (old_range, new_text) in
13242                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13243            {
13244                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13245                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13246                edits.push((edit_start..edit_end, new_text));
13247            }
13248
13249            rewrapped_row_ranges.push(start_row..=end_row);
13250        }
13251
13252        self.buffer
13253            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13254    }
13255
13256    pub fn cut_common(
13257        &mut self,
13258        cut_no_selection_line: bool,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) -> ClipboardItem {
13262        let mut text = String::new();
13263        let buffer = self.buffer.read(cx).snapshot(cx);
13264        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13265        let mut clipboard_selections = Vec::with_capacity(selections.len());
13266        {
13267            let max_point = buffer.max_point();
13268            let mut is_first = true;
13269            let mut prev_selection_was_entire_line = false;
13270            for selection in &mut selections {
13271                let is_entire_line =
13272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13273                if is_entire_line {
13274                    selection.start = Point::new(selection.start.row, 0);
13275                    if !selection.is_empty() && selection.end.column == 0 {
13276                        selection.end = cmp::min(max_point, selection.end);
13277                    } else {
13278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13279                    }
13280                    selection.goal = SelectionGoal::None;
13281                }
13282                if is_first {
13283                    is_first = false;
13284                } else if !prev_selection_was_entire_line {
13285                    text += "\n";
13286                }
13287                prev_selection_was_entire_line = is_entire_line;
13288                let mut len = 0;
13289                for chunk in buffer.text_for_range(selection.start..selection.end) {
13290                    text.push_str(chunk);
13291                    len += chunk.len();
13292                }
13293
13294                clipboard_selections.push(ClipboardSelection::for_buffer(
13295                    len,
13296                    is_entire_line,
13297                    selection.range(),
13298                    &buffer,
13299                    self.project.as_ref(),
13300                    cx,
13301                ));
13302            }
13303        }
13304
13305        self.transact(window, cx, |this, window, cx| {
13306            this.change_selections(Default::default(), window, cx, |s| {
13307                s.select(selections);
13308            });
13309            this.insert("", window, cx);
13310        });
13311        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13312    }
13313
13314    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13316        let item = self.cut_common(true, window, cx);
13317        cx.write_to_clipboard(item);
13318    }
13319
13320    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13322        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13323            s.move_with(|snapshot, sel| {
13324                if sel.is_empty() {
13325                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13326                }
13327                if sel.is_empty() {
13328                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13329                }
13330            });
13331        });
13332        let item = self.cut_common(false, window, cx);
13333        cx.set_global(KillRing(item))
13334    }
13335
13336    pub fn kill_ring_yank(
13337        &mut self,
13338        _: &KillRingYank,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13343        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13344            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13345                (kill_ring.text().to_string(), kill_ring.metadata_json())
13346            } else {
13347                return;
13348            }
13349        } else {
13350            return;
13351        };
13352        self.do_paste(&text, metadata, false, window, cx);
13353    }
13354
13355    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13356        self.do_copy(true, cx);
13357    }
13358
13359    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13360        self.do_copy(false, cx);
13361    }
13362
13363    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13364        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13365        let buffer = self.buffer.read(cx).read(cx);
13366        let mut text = String::new();
13367
13368        let mut clipboard_selections = Vec::with_capacity(selections.len());
13369        {
13370            let max_point = buffer.max_point();
13371            let mut is_first = true;
13372            let mut prev_selection_was_entire_line = false;
13373            for selection in &selections {
13374                let mut start = selection.start;
13375                let mut end = selection.end;
13376                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13377                let mut add_trailing_newline = false;
13378                if is_entire_line {
13379                    start = Point::new(start.row, 0);
13380                    let next_line_start = Point::new(end.row + 1, 0);
13381                    if next_line_start <= max_point {
13382                        end = next_line_start;
13383                    } else {
13384                        // We're on the last line without a trailing newline.
13385                        // Copy to the end of the line and add a newline afterwards.
13386                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13387                        add_trailing_newline = true;
13388                    }
13389                }
13390
13391                let mut trimmed_selections = Vec::new();
13392                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13393                    let row = MultiBufferRow(start.row);
13394                    let first_indent = buffer.indent_size_for_line(row);
13395                    if first_indent.len == 0 || start.column > first_indent.len {
13396                        trimmed_selections.push(start..end);
13397                    } else {
13398                        trimmed_selections.push(
13399                            Point::new(row.0, first_indent.len)
13400                                ..Point::new(row.0, buffer.line_len(row)),
13401                        );
13402                        for row in start.row + 1..=end.row {
13403                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13404                            if row == end.row {
13405                                line_len = end.column;
13406                            }
13407                            if line_len == 0 {
13408                                trimmed_selections
13409                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13410                                continue;
13411                            }
13412                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13413                            if row_indent_size.len >= first_indent.len {
13414                                trimmed_selections.push(
13415                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13416                                );
13417                            } else {
13418                                trimmed_selections.clear();
13419                                trimmed_selections.push(start..end);
13420                                break;
13421                            }
13422                        }
13423                    }
13424                } else {
13425                    trimmed_selections.push(start..end);
13426                }
13427
13428                let is_multiline_trim = trimmed_selections.len() > 1;
13429                for trimmed_range in trimmed_selections {
13430                    if is_first {
13431                        is_first = false;
13432                    } else if is_multiline_trim || !prev_selection_was_entire_line {
13433                        text += "\n";
13434                    }
13435                    prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13436                    let mut len = 0;
13437                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13438                        text.push_str(chunk);
13439                        len += chunk.len();
13440                    }
13441                    if add_trailing_newline {
13442                        text.push('\n');
13443                        len += 1;
13444                    }
13445                    clipboard_selections.push(ClipboardSelection::for_buffer(
13446                        len,
13447                        is_entire_line,
13448                        trimmed_range,
13449                        &buffer,
13450                        self.project.as_ref(),
13451                        cx,
13452                    ));
13453                }
13454            }
13455        }
13456
13457        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13458            text,
13459            clipboard_selections,
13460        ));
13461    }
13462
13463    pub fn do_paste(
13464        &mut self,
13465        text: &String,
13466        clipboard_selections: Option<Vec<ClipboardSelection>>,
13467        handle_entire_lines: bool,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        if self.read_only(cx) {
13472            return;
13473        }
13474
13475        let clipboard_text = Cow::Borrowed(text.as_str());
13476
13477        self.transact(window, cx, |this, window, cx| {
13478            let had_active_edit_prediction = this.has_active_edit_prediction();
13479            let display_map = this.display_snapshot(cx);
13480            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13481            let cursor_offset = this
13482                .selections
13483                .last::<MultiBufferOffset>(&display_map)
13484                .head();
13485
13486            if let Some(mut clipboard_selections) = clipboard_selections {
13487                let all_selections_were_entire_line =
13488                    clipboard_selections.iter().all(|s| s.is_entire_line);
13489                let first_selection_indent_column =
13490                    clipboard_selections.first().map(|s| s.first_line_indent);
13491                if clipboard_selections.len() != old_selections.len() {
13492                    clipboard_selections.drain(..);
13493                }
13494                let mut auto_indent_on_paste = true;
13495
13496                this.buffer.update(cx, |buffer, cx| {
13497                    let snapshot = buffer.read(cx);
13498                    auto_indent_on_paste = snapshot
13499                        .language_settings_at(cursor_offset, cx)
13500                        .auto_indent_on_paste;
13501
13502                    let mut start_offset = 0;
13503                    let mut edits = Vec::new();
13504                    let mut original_indent_columns = Vec::new();
13505                    for (ix, selection) in old_selections.iter().enumerate() {
13506                        let to_insert;
13507                        let entire_line;
13508                        let original_indent_column;
13509                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13510                            let end_offset = start_offset + clipboard_selection.len;
13511                            to_insert = &clipboard_text[start_offset..end_offset];
13512                            entire_line = clipboard_selection.is_entire_line;
13513                            start_offset = if entire_line {
13514                                end_offset
13515                            } else {
13516                                end_offset + 1
13517                            };
13518                            original_indent_column = Some(clipboard_selection.first_line_indent);
13519                        } else {
13520                            to_insert = &*clipboard_text;
13521                            entire_line = all_selections_were_entire_line;
13522                            original_indent_column = first_selection_indent_column
13523                        }
13524
13525                        let (range, to_insert) =
13526                            if selection.is_empty() && handle_entire_lines && entire_line {
13527                                // If the corresponding selection was empty when this slice of the
13528                                // clipboard text was written, then the entire line containing the
13529                                // selection was copied. If this selection is also currently empty,
13530                                // then paste the line before the current line of the buffer.
13531                                let column = selection.start.to_point(&snapshot).column as usize;
13532                                let line_start = selection.start - column;
13533                                (line_start..line_start, Cow::Borrowed(to_insert))
13534                            } else {
13535                                let language = snapshot.language_at(selection.head());
13536                                let range = selection.range();
13537                                if let Some(language) = language
13538                                    && language.name() == "Markdown".into()
13539                                {
13540                                    edit_for_markdown_paste(
13541                                        &snapshot,
13542                                        range,
13543                                        to_insert,
13544                                        url::Url::parse(to_insert).ok(),
13545                                    )
13546                                } else {
13547                                    (range, Cow::Borrowed(to_insert))
13548                                }
13549                            };
13550
13551                        edits.push((range, to_insert));
13552                        original_indent_columns.push(original_indent_column);
13553                    }
13554                    drop(snapshot);
13555
13556                    buffer.edit(
13557                        edits,
13558                        if auto_indent_on_paste {
13559                            Some(AutoindentMode::Block {
13560                                original_indent_columns,
13561                            })
13562                        } else {
13563                            None
13564                        },
13565                        cx,
13566                    );
13567                });
13568
13569                let selections = this
13570                    .selections
13571                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13572                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13573            } else {
13574                let url = url::Url::parse(&clipboard_text).ok();
13575
13576                let auto_indent_mode = if !clipboard_text.is_empty() {
13577                    Some(AutoindentMode::Block {
13578                        original_indent_columns: Vec::new(),
13579                    })
13580                } else {
13581                    None
13582                };
13583
13584                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13585                    let snapshot = buffer.snapshot(cx);
13586
13587                    let anchors = old_selections
13588                        .iter()
13589                        .map(|s| {
13590                            let anchor = snapshot.anchor_after(s.head());
13591                            s.map(|_| anchor)
13592                        })
13593                        .collect::<Vec<_>>();
13594
13595                    let mut edits = Vec::new();
13596
13597                    for selection in old_selections.iter() {
13598                        let language = snapshot.language_at(selection.head());
13599                        let range = selection.range();
13600
13601                        let (edit_range, edit_text) = if let Some(language) = language
13602                            && language.name() == "Markdown".into()
13603                        {
13604                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13605                        } else {
13606                            (range, clipboard_text.clone())
13607                        };
13608
13609                        edits.push((edit_range, edit_text));
13610                    }
13611
13612                    drop(snapshot);
13613                    buffer.edit(edits, auto_indent_mode, cx);
13614
13615                    anchors
13616                });
13617
13618                this.change_selections(Default::default(), window, cx, |s| {
13619                    s.select_anchors(selection_anchors);
13620                });
13621            }
13622
13623            //   🤔                 |    ..     | show_in_menu |
13624            // | ..                  |   true        true
13625            // | had_edit_prediction |   false       true
13626
13627            let trigger_in_words =
13628                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13629
13630            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13631        });
13632    }
13633
13634    pub fn diff_clipboard_with_selection(
13635        &mut self,
13636        _: &DiffClipboardWithSelection,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        let selections = self
13641            .selections
13642            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13643
13644        if selections.is_empty() {
13645            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13646            return;
13647        };
13648
13649        let clipboard_text = match cx.read_from_clipboard() {
13650            Some(item) => match item.entries().first() {
13651                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13652                _ => None,
13653            },
13654            None => None,
13655        };
13656
13657        let Some(clipboard_text) = clipboard_text else {
13658            log::warn!("Clipboard doesn't contain text.");
13659            return;
13660        };
13661
13662        window.dispatch_action(
13663            Box::new(DiffClipboardWithSelectionData {
13664                clipboard_text,
13665                editor: cx.entity(),
13666            }),
13667            cx,
13668        );
13669    }
13670
13671    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13673        if let Some(item) = cx.read_from_clipboard() {
13674            let entries = item.entries();
13675
13676            match entries.first() {
13677                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13678                // of all the pasted entries.
13679                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13680                    .do_paste(
13681                        clipboard_string.text(),
13682                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13683                        true,
13684                        window,
13685                        cx,
13686                    ),
13687                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13688            }
13689        }
13690    }
13691
13692    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13693        if self.read_only(cx) {
13694            return;
13695        }
13696
13697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13698
13699        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13700            if let Some((selections, _)) =
13701                self.selection_history.transaction(transaction_id).cloned()
13702            {
13703                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13704                    s.select_anchors(selections.to_vec());
13705                });
13706            } else {
13707                log::error!(
13708                    "No entry in selection_history found for undo. \
13709                     This may correspond to a bug where undo does not update the selection. \
13710                     If this is occurring, please add details to \
13711                     https://github.com/zed-industries/zed/issues/22692"
13712                );
13713            }
13714            self.request_autoscroll(Autoscroll::fit(), cx);
13715            self.unmark_text(window, cx);
13716            self.refresh_edit_prediction(true, false, window, cx);
13717            cx.emit(EditorEvent::Edited { transaction_id });
13718            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13719        }
13720    }
13721
13722    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13723        if self.read_only(cx) {
13724            return;
13725        }
13726
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13728
13729        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13730            if let Some((_, Some(selections))) =
13731                self.selection_history.transaction(transaction_id).cloned()
13732            {
13733                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13734                    s.select_anchors(selections.to_vec());
13735                });
13736            } else {
13737                log::error!(
13738                    "No entry in selection_history found for redo. \
13739                     This may correspond to a bug where undo does not update the selection. \
13740                     If this is occurring, please add details to \
13741                     https://github.com/zed-industries/zed/issues/22692"
13742                );
13743            }
13744            self.request_autoscroll(Autoscroll::fit(), cx);
13745            self.unmark_text(window, cx);
13746            self.refresh_edit_prediction(true, false, window, cx);
13747            cx.emit(EditorEvent::Edited { transaction_id });
13748        }
13749    }
13750
13751    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13752        self.buffer
13753            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13754    }
13755
13756    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13757        self.buffer
13758            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13759    }
13760
13761    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13763        self.change_selections(Default::default(), window, cx, |s| {
13764            s.move_with(|map, selection| {
13765                let cursor = if selection.is_empty() {
13766                    movement::left(map, selection.start)
13767                } else {
13768                    selection.start
13769                };
13770                selection.collapse_to(cursor, SelectionGoal::None);
13771            });
13772        })
13773    }
13774
13775    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13779        })
13780    }
13781
13782    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13784        self.change_selections(Default::default(), window, cx, |s| {
13785            s.move_with(|map, selection| {
13786                let cursor = if selection.is_empty() {
13787                    movement::right(map, selection.end)
13788                } else {
13789                    selection.end
13790                };
13791                selection.collapse_to(cursor, SelectionGoal::None)
13792            });
13793        })
13794    }
13795
13796    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13800        });
13801    }
13802
13803    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13804        if self.take_rename(true, window, cx).is_some() {
13805            return;
13806        }
13807
13808        if self.mode.is_single_line() {
13809            cx.propagate();
13810            return;
13811        }
13812
13813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13814
13815        let text_layout_details = &self.text_layout_details(window);
13816        let selection_count = self.selections.count();
13817        let first_selection = self.selections.first_anchor();
13818
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.move_with(|map, selection| {
13821                if !selection.is_empty() {
13822                    selection.goal = SelectionGoal::None;
13823                }
13824                let (cursor, goal) = movement::up(
13825                    map,
13826                    selection.start,
13827                    selection.goal,
13828                    false,
13829                    text_layout_details,
13830                );
13831                selection.collapse_to(cursor, goal);
13832            });
13833        });
13834
13835        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13836        {
13837            cx.propagate();
13838        }
13839    }
13840
13841    pub fn move_up_by_lines(
13842        &mut self,
13843        action: &MoveUpByLines,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        if self.take_rename(true, window, cx).is_some() {
13848            return;
13849        }
13850
13851        if self.mode.is_single_line() {
13852            cx.propagate();
13853            return;
13854        }
13855
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13857
13858        let text_layout_details = &self.text_layout_details(window);
13859
13860        self.change_selections(Default::default(), window, cx, |s| {
13861            s.move_with(|map, selection| {
13862                if !selection.is_empty() {
13863                    selection.goal = SelectionGoal::None;
13864                }
13865                let (cursor, goal) = movement::up_by_rows(
13866                    map,
13867                    selection.start,
13868                    action.lines,
13869                    selection.goal,
13870                    false,
13871                    text_layout_details,
13872                );
13873                selection.collapse_to(cursor, goal);
13874            });
13875        })
13876    }
13877
13878    pub fn move_down_by_lines(
13879        &mut self,
13880        action: &MoveDownByLines,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        if self.take_rename(true, window, cx).is_some() {
13885            return;
13886        }
13887
13888        if self.mode.is_single_line() {
13889            cx.propagate();
13890            return;
13891        }
13892
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894
13895        let text_layout_details = &self.text_layout_details(window);
13896
13897        self.change_selections(Default::default(), window, cx, |s| {
13898            s.move_with(|map, selection| {
13899                if !selection.is_empty() {
13900                    selection.goal = SelectionGoal::None;
13901                }
13902                let (cursor, goal) = movement::down_by_rows(
13903                    map,
13904                    selection.start,
13905                    action.lines,
13906                    selection.goal,
13907                    false,
13908                    text_layout_details,
13909                );
13910                selection.collapse_to(cursor, goal);
13911            });
13912        })
13913    }
13914
13915    pub fn select_down_by_lines(
13916        &mut self,
13917        action: &SelectDownByLines,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13922        let text_layout_details = &self.text_layout_details(window);
13923        self.change_selections(Default::default(), window, cx, |s| {
13924            s.move_heads_with(|map, head, goal| {
13925                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13926            })
13927        })
13928    }
13929
13930    pub fn select_up_by_lines(
13931        &mut self,
13932        action: &SelectUpByLines,
13933        window: &mut Window,
13934        cx: &mut Context<Self>,
13935    ) {
13936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13937        let text_layout_details = &self.text_layout_details(window);
13938        self.change_selections(Default::default(), window, cx, |s| {
13939            s.move_heads_with(|map, head, goal| {
13940                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13941            })
13942        })
13943    }
13944
13945    pub fn select_page_up(
13946        &mut self,
13947        _: &SelectPageUp,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        let Some(row_count) = self.visible_row_count() else {
13952            return;
13953        };
13954
13955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13956
13957        let text_layout_details = &self.text_layout_details(window);
13958
13959        self.change_selections(Default::default(), window, cx, |s| {
13960            s.move_heads_with(|map, head, goal| {
13961                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13962            })
13963        })
13964    }
13965
13966    pub fn move_page_up(
13967        &mut self,
13968        action: &MovePageUp,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        if self.take_rename(true, window, cx).is_some() {
13973            return;
13974        }
13975
13976        if self
13977            .context_menu
13978            .borrow_mut()
13979            .as_mut()
13980            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13981            .unwrap_or(false)
13982        {
13983            return;
13984        }
13985
13986        if matches!(self.mode, EditorMode::SingleLine) {
13987            cx.propagate();
13988            return;
13989        }
13990
13991        let Some(row_count) = self.visible_row_count() else {
13992            return;
13993        };
13994
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996
13997        let effects = if action.center_cursor {
13998            SelectionEffects::scroll(Autoscroll::center())
13999        } else {
14000            SelectionEffects::default()
14001        };
14002
14003        let text_layout_details = &self.text_layout_details(window);
14004
14005        self.change_selections(effects, window, cx, |s| {
14006            s.move_with(|map, selection| {
14007                if !selection.is_empty() {
14008                    selection.goal = SelectionGoal::None;
14009                }
14010                let (cursor, goal) = movement::up_by_rows(
14011                    map,
14012                    selection.end,
14013                    row_count,
14014                    selection.goal,
14015                    false,
14016                    text_layout_details,
14017                );
14018                selection.collapse_to(cursor, goal);
14019            });
14020        });
14021    }
14022
14023    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14025        let text_layout_details = &self.text_layout_details(window);
14026        self.change_selections(Default::default(), window, cx, |s| {
14027            s.move_heads_with(|map, head, goal| {
14028                movement::up(map, head, goal, false, text_layout_details)
14029            })
14030        })
14031    }
14032
14033    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14034        self.take_rename(true, window, cx);
14035
14036        if self.mode.is_single_line() {
14037            cx.propagate();
14038            return;
14039        }
14040
14041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14042
14043        let text_layout_details = &self.text_layout_details(window);
14044        let selection_count = self.selections.count();
14045        let first_selection = self.selections.first_anchor();
14046
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.move_with(|map, selection| {
14049                if !selection.is_empty() {
14050                    selection.goal = SelectionGoal::None;
14051                }
14052                let (cursor, goal) = movement::down(
14053                    map,
14054                    selection.end,
14055                    selection.goal,
14056                    false,
14057                    text_layout_details,
14058                );
14059                selection.collapse_to(cursor, goal);
14060            });
14061        });
14062
14063        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14064        {
14065            cx.propagate();
14066        }
14067    }
14068
14069    pub fn select_page_down(
14070        &mut self,
14071        _: &SelectPageDown,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        let Some(row_count) = self.visible_row_count() else {
14076            return;
14077        };
14078
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080
14081        let text_layout_details = &self.text_layout_details(window);
14082
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.move_heads_with(|map, head, goal| {
14085                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14086            })
14087        })
14088    }
14089
14090    pub fn move_page_down(
14091        &mut self,
14092        action: &MovePageDown,
14093        window: &mut Window,
14094        cx: &mut Context<Self>,
14095    ) {
14096        if self.take_rename(true, window, cx).is_some() {
14097            return;
14098        }
14099
14100        if self
14101            .context_menu
14102            .borrow_mut()
14103            .as_mut()
14104            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14105            .unwrap_or(false)
14106        {
14107            return;
14108        }
14109
14110        if matches!(self.mode, EditorMode::SingleLine) {
14111            cx.propagate();
14112            return;
14113        }
14114
14115        let Some(row_count) = self.visible_row_count() else {
14116            return;
14117        };
14118
14119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14120
14121        let effects = if action.center_cursor {
14122            SelectionEffects::scroll(Autoscroll::center())
14123        } else {
14124            SelectionEffects::default()
14125        };
14126
14127        let text_layout_details = &self.text_layout_details(window);
14128        self.change_selections(effects, window, cx, |s| {
14129            s.move_with(|map, selection| {
14130                if !selection.is_empty() {
14131                    selection.goal = SelectionGoal::None;
14132                }
14133                let (cursor, goal) = movement::down_by_rows(
14134                    map,
14135                    selection.end,
14136                    row_count,
14137                    selection.goal,
14138                    false,
14139                    text_layout_details,
14140                );
14141                selection.collapse_to(cursor, goal);
14142            });
14143        });
14144    }
14145
14146    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14148        let text_layout_details = &self.text_layout_details(window);
14149        self.change_selections(Default::default(), window, cx, |s| {
14150            s.move_heads_with(|map, head, goal| {
14151                movement::down(map, head, goal, false, text_layout_details)
14152            })
14153        });
14154    }
14155
14156    pub fn context_menu_first(
14157        &mut self,
14158        _: &ContextMenuFirst,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) {
14162        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14163            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14164        }
14165    }
14166
14167    pub fn context_menu_prev(
14168        &mut self,
14169        _: &ContextMenuPrevious,
14170        window: &mut Window,
14171        cx: &mut Context<Self>,
14172    ) {
14173        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14174            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14175        }
14176    }
14177
14178    pub fn context_menu_next(
14179        &mut self,
14180        _: &ContextMenuNext,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14185            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14186        }
14187    }
14188
14189    pub fn context_menu_last(
14190        &mut self,
14191        _: &ContextMenuLast,
14192        window: &mut Window,
14193        cx: &mut Context<Self>,
14194    ) {
14195        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14196            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14197        }
14198    }
14199
14200    pub fn signature_help_prev(
14201        &mut self,
14202        _: &SignatureHelpPrevious,
14203        _: &mut Window,
14204        cx: &mut Context<Self>,
14205    ) {
14206        if let Some(popover) = self.signature_help_state.popover_mut() {
14207            if popover.current_signature == 0 {
14208                popover.current_signature = popover.signatures.len() - 1;
14209            } else {
14210                popover.current_signature -= 1;
14211            }
14212            cx.notify();
14213        }
14214    }
14215
14216    pub fn signature_help_next(
14217        &mut self,
14218        _: &SignatureHelpNext,
14219        _: &mut Window,
14220        cx: &mut Context<Self>,
14221    ) {
14222        if let Some(popover) = self.signature_help_state.popover_mut() {
14223            if popover.current_signature + 1 == popover.signatures.len() {
14224                popover.current_signature = 0;
14225            } else {
14226                popover.current_signature += 1;
14227            }
14228            cx.notify();
14229        }
14230    }
14231
14232    pub fn move_to_previous_word_start(
14233        &mut self,
14234        _: &MoveToPreviousWordStart,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) {
14238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14239        self.change_selections(Default::default(), window, cx, |s| {
14240            s.move_cursors_with(|map, head, _| {
14241                (
14242                    movement::previous_word_start(map, head),
14243                    SelectionGoal::None,
14244                )
14245            });
14246        })
14247    }
14248
14249    pub fn move_to_previous_subword_start(
14250        &mut self,
14251        _: &MoveToPreviousSubwordStart,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14256        self.change_selections(Default::default(), window, cx, |s| {
14257            s.move_cursors_with(|map, head, _| {
14258                (
14259                    movement::previous_subword_start(map, head),
14260                    SelectionGoal::None,
14261                )
14262            });
14263        })
14264    }
14265
14266    pub fn select_to_previous_word_start(
14267        &mut self,
14268        _: &SelectToPreviousWordStart,
14269        window: &mut Window,
14270        cx: &mut Context<Self>,
14271    ) {
14272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14273        self.change_selections(Default::default(), window, cx, |s| {
14274            s.move_heads_with(|map, head, _| {
14275                (
14276                    movement::previous_word_start(map, head),
14277                    SelectionGoal::None,
14278                )
14279            });
14280        })
14281    }
14282
14283    pub fn select_to_previous_subword_start(
14284        &mut self,
14285        _: &SelectToPreviousSubwordStart,
14286        window: &mut Window,
14287        cx: &mut Context<Self>,
14288    ) {
14289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14290        self.change_selections(Default::default(), window, cx, |s| {
14291            s.move_heads_with(|map, head, _| {
14292                (
14293                    movement::previous_subword_start(map, head),
14294                    SelectionGoal::None,
14295                )
14296            });
14297        })
14298    }
14299
14300    pub fn delete_to_previous_word_start(
14301        &mut self,
14302        action: &DeleteToPreviousWordStart,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) {
14306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14307        self.transact(window, cx, |this, window, cx| {
14308            this.select_autoclose_pair(window, cx);
14309            this.change_selections(Default::default(), window, cx, |s| {
14310                s.move_with(|map, selection| {
14311                    if selection.is_empty() {
14312                        let mut cursor = if action.ignore_newlines {
14313                            movement::previous_word_start(map, selection.head())
14314                        } else {
14315                            movement::previous_word_start_or_newline(map, selection.head())
14316                        };
14317                        cursor = movement::adjust_greedy_deletion(
14318                            map,
14319                            selection.head(),
14320                            cursor,
14321                            action.ignore_brackets,
14322                        );
14323                        selection.set_head(cursor, SelectionGoal::None);
14324                    }
14325                });
14326            });
14327            this.insert("", window, cx);
14328        });
14329    }
14330
14331    pub fn delete_to_previous_subword_start(
14332        &mut self,
14333        action: &DeleteToPreviousSubwordStart,
14334        window: &mut Window,
14335        cx: &mut Context<Self>,
14336    ) {
14337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14338        self.transact(window, cx, |this, window, cx| {
14339            this.select_autoclose_pair(window, cx);
14340            this.change_selections(Default::default(), window, cx, |s| {
14341                s.move_with(|map, selection| {
14342                    if selection.is_empty() {
14343                        let mut cursor = if action.ignore_newlines {
14344                            movement::previous_subword_start(map, selection.head())
14345                        } else {
14346                            movement::previous_subword_start_or_newline(map, selection.head())
14347                        };
14348                        cursor = movement::adjust_greedy_deletion(
14349                            map,
14350                            selection.head(),
14351                            cursor,
14352                            action.ignore_brackets,
14353                        );
14354                        selection.set_head(cursor, SelectionGoal::None);
14355                    }
14356                });
14357            });
14358            this.insert("", window, cx);
14359        });
14360    }
14361
14362    pub fn move_to_next_word_end(
14363        &mut self,
14364        _: &MoveToNextWordEnd,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) {
14368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14369        self.change_selections(Default::default(), window, cx, |s| {
14370            s.move_cursors_with(|map, head, _| {
14371                (movement::next_word_end(map, head), SelectionGoal::None)
14372            });
14373        })
14374    }
14375
14376    pub fn move_to_next_subword_end(
14377        &mut self,
14378        _: &MoveToNextSubwordEnd,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14383        self.change_selections(Default::default(), window, cx, |s| {
14384            s.move_cursors_with(|map, head, _| {
14385                (movement::next_subword_end(map, head), SelectionGoal::None)
14386            });
14387        })
14388    }
14389
14390    pub fn select_to_next_word_end(
14391        &mut self,
14392        _: &SelectToNextWordEnd,
14393        window: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) {
14396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14397        self.change_selections(Default::default(), window, cx, |s| {
14398            s.move_heads_with(|map, head, _| {
14399                (movement::next_word_end(map, head), SelectionGoal::None)
14400            });
14401        })
14402    }
14403
14404    pub fn select_to_next_subword_end(
14405        &mut self,
14406        _: &SelectToNextSubwordEnd,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) {
14410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14411        self.change_selections(Default::default(), window, cx, |s| {
14412            s.move_heads_with(|map, head, _| {
14413                (movement::next_subword_end(map, head), SelectionGoal::None)
14414            });
14415        })
14416    }
14417
14418    pub fn delete_to_next_word_end(
14419        &mut self,
14420        action: &DeleteToNextWordEnd,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) {
14424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14425        self.transact(window, cx, |this, window, cx| {
14426            this.change_selections(Default::default(), window, cx, |s| {
14427                s.move_with(|map, selection| {
14428                    if selection.is_empty() {
14429                        let mut cursor = if action.ignore_newlines {
14430                            movement::next_word_end(map, selection.head())
14431                        } else {
14432                            movement::next_word_end_or_newline(map, selection.head())
14433                        };
14434                        cursor = movement::adjust_greedy_deletion(
14435                            map,
14436                            selection.head(),
14437                            cursor,
14438                            action.ignore_brackets,
14439                        );
14440                        selection.set_head(cursor, SelectionGoal::None);
14441                    }
14442                });
14443            });
14444            this.insert("", window, cx);
14445        });
14446    }
14447
14448    pub fn delete_to_next_subword_end(
14449        &mut self,
14450        action: &DeleteToNextSubwordEnd,
14451        window: &mut Window,
14452        cx: &mut Context<Self>,
14453    ) {
14454        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14455        self.transact(window, cx, |this, window, cx| {
14456            this.change_selections(Default::default(), window, cx, |s| {
14457                s.move_with(|map, selection| {
14458                    if selection.is_empty() {
14459                        let mut cursor = if action.ignore_newlines {
14460                            movement::next_subword_end(map, selection.head())
14461                        } else {
14462                            movement::next_subword_end_or_newline(map, selection.head())
14463                        };
14464                        cursor = movement::adjust_greedy_deletion(
14465                            map,
14466                            selection.head(),
14467                            cursor,
14468                            action.ignore_brackets,
14469                        );
14470                        selection.set_head(cursor, SelectionGoal::None);
14471                    }
14472                });
14473            });
14474            this.insert("", window, cx);
14475        });
14476    }
14477
14478    pub fn move_to_beginning_of_line(
14479        &mut self,
14480        action: &MoveToBeginningOfLine,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14485        self.change_selections(Default::default(), window, cx, |s| {
14486            s.move_cursors_with(|map, head, _| {
14487                (
14488                    movement::indented_line_beginning(
14489                        map,
14490                        head,
14491                        action.stop_at_soft_wraps,
14492                        action.stop_at_indent,
14493                    ),
14494                    SelectionGoal::None,
14495                )
14496            });
14497        })
14498    }
14499
14500    pub fn select_to_beginning_of_line(
14501        &mut self,
14502        action: &SelectToBeginningOfLine,
14503        window: &mut Window,
14504        cx: &mut Context<Self>,
14505    ) {
14506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14507        self.change_selections(Default::default(), window, cx, |s| {
14508            s.move_heads_with(|map, head, _| {
14509                (
14510                    movement::indented_line_beginning(
14511                        map,
14512                        head,
14513                        action.stop_at_soft_wraps,
14514                        action.stop_at_indent,
14515                    ),
14516                    SelectionGoal::None,
14517                )
14518            });
14519        });
14520    }
14521
14522    pub fn delete_to_beginning_of_line(
14523        &mut self,
14524        action: &DeleteToBeginningOfLine,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) {
14528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14529        self.transact(window, cx, |this, window, cx| {
14530            this.change_selections(Default::default(), window, cx, |s| {
14531                s.move_with(|_, selection| {
14532                    selection.reversed = true;
14533                });
14534            });
14535
14536            this.select_to_beginning_of_line(
14537                &SelectToBeginningOfLine {
14538                    stop_at_soft_wraps: false,
14539                    stop_at_indent: action.stop_at_indent,
14540                },
14541                window,
14542                cx,
14543            );
14544            this.backspace(&Backspace, window, cx);
14545        });
14546    }
14547
14548    pub fn move_to_end_of_line(
14549        &mut self,
14550        action: &MoveToEndOfLine,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) {
14554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14555        self.change_selections(Default::default(), window, cx, |s| {
14556            s.move_cursors_with(|map, head, _| {
14557                (
14558                    movement::line_end(map, head, action.stop_at_soft_wraps),
14559                    SelectionGoal::None,
14560                )
14561            });
14562        })
14563    }
14564
14565    pub fn select_to_end_of_line(
14566        &mut self,
14567        action: &SelectToEndOfLine,
14568        window: &mut Window,
14569        cx: &mut Context<Self>,
14570    ) {
14571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14572        self.change_selections(Default::default(), window, cx, |s| {
14573            s.move_heads_with(|map, head, _| {
14574                (
14575                    movement::line_end(map, head, action.stop_at_soft_wraps),
14576                    SelectionGoal::None,
14577                )
14578            });
14579        })
14580    }
14581
14582    pub fn delete_to_end_of_line(
14583        &mut self,
14584        _: &DeleteToEndOfLine,
14585        window: &mut Window,
14586        cx: &mut Context<Self>,
14587    ) {
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14589        self.transact(window, cx, |this, window, cx| {
14590            this.select_to_end_of_line(
14591                &SelectToEndOfLine {
14592                    stop_at_soft_wraps: false,
14593                },
14594                window,
14595                cx,
14596            );
14597            this.delete(&Delete, window, cx);
14598        });
14599    }
14600
14601    pub fn cut_to_end_of_line(
14602        &mut self,
14603        action: &CutToEndOfLine,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) {
14607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14608        self.transact(window, cx, |this, window, cx| {
14609            this.select_to_end_of_line(
14610                &SelectToEndOfLine {
14611                    stop_at_soft_wraps: false,
14612                },
14613                window,
14614                cx,
14615            );
14616            if !action.stop_at_newlines {
14617                this.change_selections(Default::default(), window, cx, |s| {
14618                    s.move_with(|_, sel| {
14619                        if sel.is_empty() {
14620                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14621                        }
14622                    });
14623                });
14624            }
14625            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14626            let item = this.cut_common(false, window, cx);
14627            cx.write_to_clipboard(item);
14628        });
14629    }
14630
14631    pub fn move_to_start_of_paragraph(
14632        &mut self,
14633        _: &MoveToStartOfParagraph,
14634        window: &mut Window,
14635        cx: &mut Context<Self>,
14636    ) {
14637        if matches!(self.mode, EditorMode::SingleLine) {
14638            cx.propagate();
14639            return;
14640        }
14641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14642        self.change_selections(Default::default(), window, cx, |s| {
14643            s.move_with(|map, selection| {
14644                selection.collapse_to(
14645                    movement::start_of_paragraph(map, selection.head(), 1),
14646                    SelectionGoal::None,
14647                )
14648            });
14649        })
14650    }
14651
14652    pub fn move_to_end_of_paragraph(
14653        &mut self,
14654        _: &MoveToEndOfParagraph,
14655        window: &mut Window,
14656        cx: &mut Context<Self>,
14657    ) {
14658        if matches!(self.mode, EditorMode::SingleLine) {
14659            cx.propagate();
14660            return;
14661        }
14662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14663        self.change_selections(Default::default(), window, cx, |s| {
14664            s.move_with(|map, selection| {
14665                selection.collapse_to(
14666                    movement::end_of_paragraph(map, selection.head(), 1),
14667                    SelectionGoal::None,
14668                )
14669            });
14670        })
14671    }
14672
14673    pub fn select_to_start_of_paragraph(
14674        &mut self,
14675        _: &SelectToStartOfParagraph,
14676        window: &mut Window,
14677        cx: &mut Context<Self>,
14678    ) {
14679        if matches!(self.mode, EditorMode::SingleLine) {
14680            cx.propagate();
14681            return;
14682        }
14683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14684        self.change_selections(Default::default(), window, cx, |s| {
14685            s.move_heads_with(|map, head, _| {
14686                (
14687                    movement::start_of_paragraph(map, head, 1),
14688                    SelectionGoal::None,
14689                )
14690            });
14691        })
14692    }
14693
14694    pub fn select_to_end_of_paragraph(
14695        &mut self,
14696        _: &SelectToEndOfParagraph,
14697        window: &mut Window,
14698        cx: &mut Context<Self>,
14699    ) {
14700        if matches!(self.mode, EditorMode::SingleLine) {
14701            cx.propagate();
14702            return;
14703        }
14704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14705        self.change_selections(Default::default(), window, cx, |s| {
14706            s.move_heads_with(|map, head, _| {
14707                (
14708                    movement::end_of_paragraph(map, head, 1),
14709                    SelectionGoal::None,
14710                )
14711            });
14712        })
14713    }
14714
14715    pub fn move_to_start_of_excerpt(
14716        &mut self,
14717        _: &MoveToStartOfExcerpt,
14718        window: &mut Window,
14719        cx: &mut Context<Self>,
14720    ) {
14721        if matches!(self.mode, EditorMode::SingleLine) {
14722            cx.propagate();
14723            return;
14724        }
14725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14726        self.change_selections(Default::default(), window, cx, |s| {
14727            s.move_with(|map, selection| {
14728                selection.collapse_to(
14729                    movement::start_of_excerpt(
14730                        map,
14731                        selection.head(),
14732                        workspace::searchable::Direction::Prev,
14733                    ),
14734                    SelectionGoal::None,
14735                )
14736            });
14737        })
14738    }
14739
14740    pub fn move_to_start_of_next_excerpt(
14741        &mut self,
14742        _: &MoveToStartOfNextExcerpt,
14743        window: &mut Window,
14744        cx: &mut Context<Self>,
14745    ) {
14746        if matches!(self.mode, EditorMode::SingleLine) {
14747            cx.propagate();
14748            return;
14749        }
14750
14751        self.change_selections(Default::default(), window, cx, |s| {
14752            s.move_with(|map, selection| {
14753                selection.collapse_to(
14754                    movement::start_of_excerpt(
14755                        map,
14756                        selection.head(),
14757                        workspace::searchable::Direction::Next,
14758                    ),
14759                    SelectionGoal::None,
14760                )
14761            });
14762        })
14763    }
14764
14765    pub fn move_to_end_of_excerpt(
14766        &mut self,
14767        _: &MoveToEndOfExcerpt,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) {
14771        if matches!(self.mode, EditorMode::SingleLine) {
14772            cx.propagate();
14773            return;
14774        }
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14776        self.change_selections(Default::default(), window, cx, |s| {
14777            s.move_with(|map, selection| {
14778                selection.collapse_to(
14779                    movement::end_of_excerpt(
14780                        map,
14781                        selection.head(),
14782                        workspace::searchable::Direction::Next,
14783                    ),
14784                    SelectionGoal::None,
14785                )
14786            });
14787        })
14788    }
14789
14790    pub fn move_to_end_of_previous_excerpt(
14791        &mut self,
14792        _: &MoveToEndOfPreviousExcerpt,
14793        window: &mut Window,
14794        cx: &mut Context<Self>,
14795    ) {
14796        if matches!(self.mode, EditorMode::SingleLine) {
14797            cx.propagate();
14798            return;
14799        }
14800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14801        self.change_selections(Default::default(), window, cx, |s| {
14802            s.move_with(|map, selection| {
14803                selection.collapse_to(
14804                    movement::end_of_excerpt(
14805                        map,
14806                        selection.head(),
14807                        workspace::searchable::Direction::Prev,
14808                    ),
14809                    SelectionGoal::None,
14810                )
14811            });
14812        })
14813    }
14814
14815    pub fn select_to_start_of_excerpt(
14816        &mut self,
14817        _: &SelectToStartOfExcerpt,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        if matches!(self.mode, EditorMode::SingleLine) {
14822            cx.propagate();
14823            return;
14824        }
14825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14826        self.change_selections(Default::default(), window, cx, |s| {
14827            s.move_heads_with(|map, head, _| {
14828                (
14829                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14830                    SelectionGoal::None,
14831                )
14832            });
14833        })
14834    }
14835
14836    pub fn select_to_start_of_next_excerpt(
14837        &mut self,
14838        _: &SelectToStartOfNextExcerpt,
14839        window: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) {
14842        if matches!(self.mode, EditorMode::SingleLine) {
14843            cx.propagate();
14844            return;
14845        }
14846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14847        self.change_selections(Default::default(), window, cx, |s| {
14848            s.move_heads_with(|map, head, _| {
14849                (
14850                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14851                    SelectionGoal::None,
14852                )
14853            });
14854        })
14855    }
14856
14857    pub fn select_to_end_of_excerpt(
14858        &mut self,
14859        _: &SelectToEndOfExcerpt,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) {
14863        if matches!(self.mode, EditorMode::SingleLine) {
14864            cx.propagate();
14865            return;
14866        }
14867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14868        self.change_selections(Default::default(), window, cx, |s| {
14869            s.move_heads_with(|map, head, _| {
14870                (
14871                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14872                    SelectionGoal::None,
14873                )
14874            });
14875        })
14876    }
14877
14878    pub fn select_to_end_of_previous_excerpt(
14879        &mut self,
14880        _: &SelectToEndOfPreviousExcerpt,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) {
14884        if matches!(self.mode, EditorMode::SingleLine) {
14885            cx.propagate();
14886            return;
14887        }
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889        self.change_selections(Default::default(), window, cx, |s| {
14890            s.move_heads_with(|map, head, _| {
14891                (
14892                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14893                    SelectionGoal::None,
14894                )
14895            });
14896        })
14897    }
14898
14899    pub fn move_to_beginning(
14900        &mut self,
14901        _: &MoveToBeginning,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        if matches!(self.mode, EditorMode::SingleLine) {
14906            cx.propagate();
14907            return;
14908        }
14909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14910        self.change_selections(Default::default(), window, cx, |s| {
14911            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14912        });
14913    }
14914
14915    pub fn select_to_beginning(
14916        &mut self,
14917        _: &SelectToBeginning,
14918        window: &mut Window,
14919        cx: &mut Context<Self>,
14920    ) {
14921        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14922        selection.set_head(Point::zero(), SelectionGoal::None);
14923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14924        self.change_selections(Default::default(), window, cx, |s| {
14925            s.select(vec![selection]);
14926        });
14927    }
14928
14929    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14930        if matches!(self.mode, EditorMode::SingleLine) {
14931            cx.propagate();
14932            return;
14933        }
14934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14935        let cursor = self.buffer.read(cx).read(cx).len();
14936        self.change_selections(Default::default(), window, cx, |s| {
14937            s.select_ranges(vec![cursor..cursor])
14938        });
14939    }
14940
14941    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14942        self.nav_history = nav_history;
14943    }
14944
14945    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14946        self.nav_history.as_ref()
14947    }
14948
14949    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14950        self.push_to_nav_history(
14951            self.selections.newest_anchor().head(),
14952            None,
14953            false,
14954            true,
14955            cx,
14956        );
14957    }
14958
14959    fn navigation_data(&self, cursor_anchor: Anchor, cx: &App) -> NavigationData {
14960        let buffer = self.buffer.read(cx).read(cx);
14961        let cursor_position = cursor_anchor.to_point(&buffer);
14962        let scroll_anchor = self.scroll_manager.anchor();
14963        let scroll_top_row = scroll_anchor.top_row(&buffer);
14964        drop(buffer);
14965
14966        NavigationData {
14967            cursor_anchor,
14968            cursor_position,
14969            scroll_anchor,
14970            scroll_top_row,
14971        }
14972    }
14973
14974    fn navigation_entry(&self, cursor_anchor: Anchor, cx: &App) -> Option<NavigationEntry> {
14975        let Some(history) = self.nav_history.clone() else {
14976            return None;
14977        };
14978        let data = self.navigation_data(cursor_anchor, cx);
14979        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
14980    }
14981
14982    fn push_to_nav_history(
14983        &mut self,
14984        cursor_anchor: Anchor,
14985        new_position: Option<Point>,
14986        is_deactivate: bool,
14987        always: bool,
14988        cx: &mut Context<Self>,
14989    ) {
14990        let data = self.navigation_data(cursor_anchor, cx);
14991        if let Some(nav_history) = self.nav_history.as_mut() {
14992            if let Some(new_position) = new_position {
14993                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
14994                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14995                    return;
14996                }
14997            }
14998
14999            nav_history.push(Some(data), cx);
15000            cx.emit(EditorEvent::PushedToNavHistory {
15001                anchor: cursor_anchor,
15002                is_deactivate,
15003            })
15004        }
15005    }
15006
15007    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15009        let buffer = self.buffer.read(cx).snapshot(cx);
15010        let mut selection = self
15011            .selections
15012            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15013        selection.set_head(buffer.len(), SelectionGoal::None);
15014        self.change_selections(Default::default(), window, cx, |s| {
15015            s.select(vec![selection]);
15016        });
15017    }
15018
15019    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15021        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15022            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
15023        });
15024    }
15025
15026    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15029        let mut selections = self.selections.all::<Point>(&display_map);
15030        let max_point = display_map.buffer_snapshot().max_point();
15031        for selection in &mut selections {
15032            let rows = selection.spanned_rows(true, &display_map);
15033            selection.start = Point::new(rows.start.0, 0);
15034            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15035            selection.reversed = false;
15036        }
15037        self.change_selections(Default::default(), window, cx, |s| {
15038            s.select(selections);
15039        });
15040    }
15041
15042    pub fn split_selection_into_lines(
15043        &mut self,
15044        action: &SplitSelectionIntoLines,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) {
15048        let selections = self
15049            .selections
15050            .all::<Point>(&self.display_snapshot(cx))
15051            .into_iter()
15052            .map(|selection| selection.start..selection.end)
15053            .collect::<Vec<_>>();
15054        self.unfold_ranges(&selections, true, true, cx);
15055
15056        let mut new_selection_ranges = Vec::new();
15057        {
15058            let buffer = self.buffer.read(cx).read(cx);
15059            for selection in selections {
15060                for row in selection.start.row..selection.end.row {
15061                    let line_start = Point::new(row, 0);
15062                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15063
15064                    if action.keep_selections {
15065                        // Keep the selection range for each line
15066                        let selection_start = if row == selection.start.row {
15067                            selection.start
15068                        } else {
15069                            line_start
15070                        };
15071                        new_selection_ranges.push(selection_start..line_end);
15072                    } else {
15073                        // Collapse to cursor at end of line
15074                        new_selection_ranges.push(line_end..line_end);
15075                    }
15076                }
15077
15078                let is_multiline_selection = selection.start.row != selection.end.row;
15079                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15080                // so this action feels more ergonomic when paired with other selection operations
15081                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15082                if !should_skip_last {
15083                    if action.keep_selections {
15084                        if is_multiline_selection {
15085                            let line_start = Point::new(selection.end.row, 0);
15086                            new_selection_ranges.push(line_start..selection.end);
15087                        } else {
15088                            new_selection_ranges.push(selection.start..selection.end);
15089                        }
15090                    } else {
15091                        new_selection_ranges.push(selection.end..selection.end);
15092                    }
15093                }
15094            }
15095        }
15096        self.change_selections(Default::default(), window, cx, |s| {
15097            s.select_ranges(new_selection_ranges);
15098        });
15099    }
15100
15101    pub fn add_selection_above(
15102        &mut self,
15103        action: &AddSelectionAbove,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) {
15107        self.add_selection(true, action.skip_soft_wrap, window, cx);
15108    }
15109
15110    pub fn add_selection_below(
15111        &mut self,
15112        action: &AddSelectionBelow,
15113        window: &mut Window,
15114        cx: &mut Context<Self>,
15115    ) {
15116        self.add_selection(false, action.skip_soft_wrap, window, cx);
15117    }
15118
15119    fn add_selection(
15120        &mut self,
15121        above: bool,
15122        skip_soft_wrap: bool,
15123        window: &mut Window,
15124        cx: &mut Context<Self>,
15125    ) {
15126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15127
15128        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15129        let all_selections = self.selections.all::<Point>(&display_map);
15130        let text_layout_details = self.text_layout_details(window);
15131
15132        let (mut columnar_selections, new_selections_to_columnarize) = {
15133            if let Some(state) = self.add_selections_state.as_ref() {
15134                let columnar_selection_ids: HashSet<_> = state
15135                    .groups
15136                    .iter()
15137                    .flat_map(|group| group.stack.iter())
15138                    .copied()
15139                    .collect();
15140
15141                all_selections
15142                    .into_iter()
15143                    .partition(|s| columnar_selection_ids.contains(&s.id))
15144            } else {
15145                (Vec::new(), all_selections)
15146            }
15147        };
15148
15149        let mut state = self
15150            .add_selections_state
15151            .take()
15152            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15153
15154        for selection in new_selections_to_columnarize {
15155            let range = selection.display_range(&display_map).sorted();
15156            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15157            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15158            let positions = start_x.min(end_x)..start_x.max(end_x);
15159            let mut stack = Vec::new();
15160            for row in range.start.row().0..=range.end.row().0 {
15161                if let Some(selection) = self.selections.build_columnar_selection(
15162                    &display_map,
15163                    DisplayRow(row),
15164                    &positions,
15165                    selection.reversed,
15166                    &text_layout_details,
15167                ) {
15168                    stack.push(selection.id);
15169                    columnar_selections.push(selection);
15170                }
15171            }
15172            if !stack.is_empty() {
15173                if above {
15174                    stack.reverse();
15175                }
15176                state.groups.push(AddSelectionsGroup { above, stack });
15177            }
15178        }
15179
15180        let mut final_selections = Vec::new();
15181        let end_row = if above {
15182            DisplayRow(0)
15183        } else {
15184            display_map.max_point().row()
15185        };
15186
15187        // When `skip_soft_wrap` is true, we use buffer columns instead of pixel
15188        // positions to place new selections, so we need to keep track of the
15189        // column range of the oldest selection in each group, because
15190        // intermediate selections may have been clamped to shorter lines.
15191        // selections may have been clamped to shorter lines.
15192        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15193            let mut map = HashMap::default();
15194            for group in state.groups.iter() {
15195                if let Some(oldest_id) = group.stack.first() {
15196                    if let Some(oldest_selection) =
15197                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15198                    {
15199                        let start_col = oldest_selection.start.column;
15200                        let end_col = oldest_selection.end.column;
15201                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15202                        for id in &group.stack {
15203                            map.insert(*id, goal_columns.clone());
15204                        }
15205                    }
15206                }
15207            }
15208            map
15209        } else {
15210            HashMap::default()
15211        };
15212
15213        let mut last_added_item_per_group = HashMap::default();
15214        for group in state.groups.iter_mut() {
15215            if let Some(last_id) = group.stack.last() {
15216                last_added_item_per_group.insert(*last_id, group);
15217            }
15218        }
15219
15220        for selection in columnar_selections {
15221            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15222                if above == group.above {
15223                    let range = selection.display_range(&display_map).sorted();
15224                    debug_assert_eq!(range.start.row(), range.end.row());
15225                    let row = range.start.row();
15226                    let positions =
15227                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15228                            Pixels::from(start)..Pixels::from(end)
15229                        } else {
15230                            let start_x =
15231                                display_map.x_for_display_point(range.start, &text_layout_details);
15232                            let end_x =
15233                                display_map.x_for_display_point(range.end, &text_layout_details);
15234                            start_x.min(end_x)..start_x.max(end_x)
15235                        };
15236
15237                    let maybe_new_selection = if skip_soft_wrap {
15238                        let goal_columns = goal_columns_by_selection_id
15239                            .remove(&selection.id)
15240                            .unwrap_or_else(|| {
15241                                let start_col = selection.start.column;
15242                                let end_col = selection.end.column;
15243                                start_col.min(end_col)..start_col.max(end_col)
15244                            });
15245                        self.selections.find_next_columnar_selection_by_buffer_row(
15246                            &display_map,
15247                            row,
15248                            end_row,
15249                            above,
15250                            &goal_columns,
15251                            selection.reversed,
15252                            &text_layout_details,
15253                        )
15254                    } else {
15255                        self.selections.find_next_columnar_selection_by_display_row(
15256                            &display_map,
15257                            row,
15258                            end_row,
15259                            above,
15260                            &positions,
15261                            selection.reversed,
15262                            &text_layout_details,
15263                        )
15264                    };
15265
15266                    if let Some(new_selection) = maybe_new_selection {
15267                        group.stack.push(new_selection.id);
15268                        if above {
15269                            final_selections.push(new_selection);
15270                            final_selections.push(selection);
15271                        } else {
15272                            final_selections.push(selection);
15273                            final_selections.push(new_selection);
15274                        }
15275                    } else {
15276                        final_selections.push(selection);
15277                    }
15278                } else {
15279                    group.stack.pop();
15280                }
15281            } else {
15282                final_selections.push(selection);
15283            }
15284        }
15285
15286        self.change_selections(Default::default(), window, cx, |s| {
15287            s.select(final_selections);
15288        });
15289
15290        let final_selection_ids: HashSet<_> = self
15291            .selections
15292            .all::<Point>(&display_map)
15293            .iter()
15294            .map(|s| s.id)
15295            .collect();
15296        state.groups.retain_mut(|group| {
15297            // selections might get merged above so we remove invalid items from stacks
15298            group.stack.retain(|id| final_selection_ids.contains(id));
15299
15300            // single selection in stack can be treated as initial state
15301            group.stack.len() > 1
15302        });
15303
15304        if !state.groups.is_empty() {
15305            self.add_selections_state = Some(state);
15306        }
15307    }
15308
15309    pub fn insert_snippet_at_selections(
15310        &mut self,
15311        action: &InsertSnippet,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) {
15315        self.try_insert_snippet_at_selections(action, window, cx)
15316            .log_err();
15317    }
15318
15319    fn try_insert_snippet_at_selections(
15320        &mut self,
15321        action: &InsertSnippet,
15322        window: &mut Window,
15323        cx: &mut Context<Self>,
15324    ) -> Result<()> {
15325        let insertion_ranges = self
15326            .selections
15327            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15328            .into_iter()
15329            .map(|selection| selection.range())
15330            .collect_vec();
15331
15332        let snippet = if let Some(snippet_body) = &action.snippet {
15333            if action.language.is_none() && action.name.is_none() {
15334                Snippet::parse(snippet_body)?
15335            } else {
15336                bail!("`snippet` is mutually exclusive with `language` and `name`")
15337            }
15338        } else if let Some(name) = &action.name {
15339            let project = self.project().context("no project")?;
15340            let snippet_store = project.read(cx).snippets().read(cx);
15341            let snippet = snippet_store
15342                .snippets_for(action.language.clone(), cx)
15343                .into_iter()
15344                .find(|snippet| snippet.name == *name)
15345                .context("snippet not found")?;
15346            Snippet::parse(&snippet.body)?
15347        } else {
15348            // todo(andrew): open modal to select snippet
15349            bail!("`name` or `snippet` is required")
15350        };
15351
15352        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15353    }
15354
15355    fn select_match_ranges(
15356        &mut self,
15357        range: Range<MultiBufferOffset>,
15358        reversed: bool,
15359        replace_newest: bool,
15360        auto_scroll: Option<Autoscroll>,
15361        window: &mut Window,
15362        cx: &mut Context<Editor>,
15363    ) {
15364        self.unfold_ranges(
15365            std::slice::from_ref(&range),
15366            false,
15367            auto_scroll.is_some(),
15368            cx,
15369        );
15370        let effects = if let Some(scroll) = auto_scroll {
15371            SelectionEffects::scroll(scroll)
15372        } else {
15373            SelectionEffects::no_scroll()
15374        };
15375        self.change_selections(effects, window, cx, |s| {
15376            if replace_newest {
15377                s.delete(s.newest_anchor().id);
15378            }
15379            if reversed {
15380                s.insert_range(range.end..range.start);
15381            } else {
15382                s.insert_range(range);
15383            }
15384        });
15385    }
15386
15387    pub fn select_next_match_internal(
15388        &mut self,
15389        display_map: &DisplaySnapshot,
15390        replace_newest: bool,
15391        autoscroll: Option<Autoscroll>,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) -> Result<()> {
15395        let buffer = display_map.buffer_snapshot();
15396        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15397        if let Some(mut select_next_state) = self.select_next_state.take() {
15398            let query = &select_next_state.query;
15399            if !select_next_state.done {
15400                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15401                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15402                let mut next_selected_range = None;
15403
15404                let bytes_after_last_selection =
15405                    buffer.bytes_in_range(last_selection.end..buffer.len());
15406                let bytes_before_first_selection =
15407                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15408                let query_matches = query
15409                    .stream_find_iter(bytes_after_last_selection)
15410                    .map(|result| (last_selection.end, result))
15411                    .chain(
15412                        query
15413                            .stream_find_iter(bytes_before_first_selection)
15414                            .map(|result| (MultiBufferOffset(0), result)),
15415                    );
15416
15417                for (start_offset, query_match) in query_matches {
15418                    let query_match = query_match.unwrap(); // can only fail due to I/O
15419                    let offset_range =
15420                        start_offset + query_match.start()..start_offset + query_match.end();
15421
15422                    if !select_next_state.wordwise
15423                        || (!buffer.is_inside_word(offset_range.start, None)
15424                            && !buffer.is_inside_word(offset_range.end, None))
15425                    {
15426                        let idx = selections
15427                            .partition_point(|selection| selection.end <= offset_range.start);
15428                        let overlaps = selections
15429                            .get(idx)
15430                            .map_or(false, |selection| selection.start < offset_range.end);
15431
15432                        if !overlaps {
15433                            next_selected_range = Some(offset_range);
15434                            break;
15435                        }
15436                    }
15437                }
15438
15439                if let Some(next_selected_range) = next_selected_range {
15440                    self.select_match_ranges(
15441                        next_selected_range,
15442                        last_selection.reversed,
15443                        replace_newest,
15444                        autoscroll,
15445                        window,
15446                        cx,
15447                    );
15448                } else {
15449                    select_next_state.done = true;
15450                }
15451            }
15452
15453            self.select_next_state = Some(select_next_state);
15454        } else {
15455            let mut only_carets = true;
15456            let mut same_text_selected = true;
15457            let mut selected_text = None;
15458
15459            let mut selections_iter = selections.iter().peekable();
15460            while let Some(selection) = selections_iter.next() {
15461                if selection.start != selection.end {
15462                    only_carets = false;
15463                }
15464
15465                if same_text_selected {
15466                    if selected_text.is_none() {
15467                        selected_text =
15468                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15469                    }
15470
15471                    if let Some(next_selection) = selections_iter.peek() {
15472                        if next_selection.len() == selection.len() {
15473                            let next_selected_text = buffer
15474                                .text_for_range(next_selection.range())
15475                                .collect::<String>();
15476                            if Some(next_selected_text) != selected_text {
15477                                same_text_selected = false;
15478                                selected_text = None;
15479                            }
15480                        } else {
15481                            same_text_selected = false;
15482                            selected_text = None;
15483                        }
15484                    }
15485                }
15486            }
15487
15488            if only_carets {
15489                for selection in &mut selections {
15490                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15491                    selection.start = word_range.start;
15492                    selection.end = word_range.end;
15493                    selection.goal = SelectionGoal::None;
15494                    selection.reversed = false;
15495                    self.select_match_ranges(
15496                        selection.start..selection.end,
15497                        selection.reversed,
15498                        replace_newest,
15499                        autoscroll,
15500                        window,
15501                        cx,
15502                    );
15503                }
15504
15505                if selections.len() == 1 {
15506                    let selection = selections
15507                        .last()
15508                        .expect("ensured that there's only one selection");
15509                    let query = buffer
15510                        .text_for_range(selection.start..selection.end)
15511                        .collect::<String>();
15512                    let is_empty = query.is_empty();
15513                    let select_state = SelectNextState {
15514                        query: self.build_query(&[query], cx)?,
15515                        wordwise: true,
15516                        done: is_empty,
15517                    };
15518                    self.select_next_state = Some(select_state);
15519                } else {
15520                    self.select_next_state = None;
15521                }
15522            } else if let Some(selected_text) = selected_text {
15523                self.select_next_state = Some(SelectNextState {
15524                    query: self.build_query(&[selected_text], cx)?,
15525                    wordwise: false,
15526                    done: false,
15527                });
15528                self.select_next_match_internal(
15529                    display_map,
15530                    replace_newest,
15531                    autoscroll,
15532                    window,
15533                    cx,
15534                )?;
15535            }
15536        }
15537        Ok(())
15538    }
15539
15540    pub fn select_all_matches(
15541        &mut self,
15542        _action: &SelectAllMatches,
15543        window: &mut Window,
15544        cx: &mut Context<Self>,
15545    ) -> Result<()> {
15546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15547
15548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15549
15550        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15551        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15552        else {
15553            return Ok(());
15554        };
15555
15556        let mut new_selections = Vec::new();
15557
15558        let reversed = self
15559            .selections
15560            .oldest::<MultiBufferOffset>(&display_map)
15561            .reversed;
15562        let buffer = display_map.buffer_snapshot();
15563        let query_matches = select_next_state
15564            .query
15565            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15566
15567        for query_match in query_matches.into_iter() {
15568            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15569            let offset_range = if reversed {
15570                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15571            } else {
15572                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15573            };
15574
15575            if !select_next_state.wordwise
15576                || (!buffer.is_inside_word(offset_range.start, None)
15577                    && !buffer.is_inside_word(offset_range.end, None))
15578            {
15579                new_selections.push(offset_range.start..offset_range.end);
15580            }
15581        }
15582
15583        select_next_state.done = true;
15584
15585        if new_selections.is_empty() {
15586            log::error!("bug: new_selections is empty in select_all_matches");
15587            return Ok(());
15588        }
15589
15590        self.unfold_ranges(&new_selections, false, false, cx);
15591        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15592            selections.select_ranges(new_selections)
15593        });
15594
15595        Ok(())
15596    }
15597
15598    pub fn select_next(
15599        &mut self,
15600        action: &SelectNext,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) -> Result<()> {
15604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15606        self.select_next_match_internal(
15607            &display_map,
15608            action.replace_newest,
15609            Some(Autoscroll::newest()),
15610            window,
15611            cx,
15612        )
15613    }
15614
15615    pub fn select_previous(
15616        &mut self,
15617        action: &SelectPrevious,
15618        window: &mut Window,
15619        cx: &mut Context<Self>,
15620    ) -> Result<()> {
15621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15623        let buffer = display_map.buffer_snapshot();
15624        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15625        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15626            let query = &select_prev_state.query;
15627            if !select_prev_state.done {
15628                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15629                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15630                let mut next_selected_range = None;
15631                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15632                let bytes_before_last_selection =
15633                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15634                let bytes_after_first_selection =
15635                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15636                let query_matches = query
15637                    .stream_find_iter(bytes_before_last_selection)
15638                    .map(|result| (last_selection.start, result))
15639                    .chain(
15640                        query
15641                            .stream_find_iter(bytes_after_first_selection)
15642                            .map(|result| (buffer.len(), result)),
15643                    );
15644                for (end_offset, query_match) in query_matches {
15645                    let query_match = query_match.unwrap(); // can only fail due to I/O
15646                    let offset_range =
15647                        end_offset - query_match.end()..end_offset - query_match.start();
15648
15649                    if !select_prev_state.wordwise
15650                        || (!buffer.is_inside_word(offset_range.start, None)
15651                            && !buffer.is_inside_word(offset_range.end, None))
15652                    {
15653                        next_selected_range = Some(offset_range);
15654                        break;
15655                    }
15656                }
15657
15658                if let Some(next_selected_range) = next_selected_range {
15659                    self.select_match_ranges(
15660                        next_selected_range,
15661                        last_selection.reversed,
15662                        action.replace_newest,
15663                        Some(Autoscroll::newest()),
15664                        window,
15665                        cx,
15666                    );
15667                } else {
15668                    select_prev_state.done = true;
15669                }
15670            }
15671
15672            self.select_prev_state = Some(select_prev_state);
15673        } else {
15674            let mut only_carets = true;
15675            let mut same_text_selected = true;
15676            let mut selected_text = None;
15677
15678            let mut selections_iter = selections.iter().peekable();
15679            while let Some(selection) = selections_iter.next() {
15680                if selection.start != selection.end {
15681                    only_carets = false;
15682                }
15683
15684                if same_text_selected {
15685                    if selected_text.is_none() {
15686                        selected_text =
15687                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15688                    }
15689
15690                    if let Some(next_selection) = selections_iter.peek() {
15691                        if next_selection.len() == selection.len() {
15692                            let next_selected_text = buffer
15693                                .text_for_range(next_selection.range())
15694                                .collect::<String>();
15695                            if Some(next_selected_text) != selected_text {
15696                                same_text_selected = false;
15697                                selected_text = None;
15698                            }
15699                        } else {
15700                            same_text_selected = false;
15701                            selected_text = None;
15702                        }
15703                    }
15704                }
15705            }
15706
15707            if only_carets {
15708                for selection in &mut selections {
15709                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15710                    selection.start = word_range.start;
15711                    selection.end = word_range.end;
15712                    selection.goal = SelectionGoal::None;
15713                    selection.reversed = false;
15714                    self.select_match_ranges(
15715                        selection.start..selection.end,
15716                        selection.reversed,
15717                        action.replace_newest,
15718                        Some(Autoscroll::newest()),
15719                        window,
15720                        cx,
15721                    );
15722                }
15723                if selections.len() == 1 {
15724                    let selection = selections
15725                        .last()
15726                        .expect("ensured that there's only one selection");
15727                    let query = buffer
15728                        .text_for_range(selection.start..selection.end)
15729                        .collect::<String>();
15730                    let is_empty = query.is_empty();
15731                    let select_state = SelectNextState {
15732                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15733                        wordwise: true,
15734                        done: is_empty,
15735                    };
15736                    self.select_prev_state = Some(select_state);
15737                } else {
15738                    self.select_prev_state = None;
15739                }
15740            } else if let Some(selected_text) = selected_text {
15741                self.select_prev_state = Some(SelectNextState {
15742                    query: self
15743                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15744                    wordwise: false,
15745                    done: false,
15746                });
15747                self.select_previous(action, window, cx)?;
15748            }
15749        }
15750        Ok(())
15751    }
15752
15753    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15754    /// setting the case sensitivity based on the global
15755    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15756    /// editor's settings.
15757    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15758    where
15759        I: IntoIterator<Item = P>,
15760        P: AsRef<[u8]>,
15761    {
15762        let case_sensitive = self
15763            .select_next_is_case_sensitive
15764            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15765
15766        let mut builder = AhoCorasickBuilder::new();
15767        builder.ascii_case_insensitive(!case_sensitive);
15768        builder.build(patterns)
15769    }
15770
15771    pub fn find_next_match(
15772        &mut self,
15773        _: &FindNextMatch,
15774        window: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) -> Result<()> {
15777        let selections = self.selections.disjoint_anchors_arc();
15778        match selections.first() {
15779            Some(first) if selections.len() >= 2 => {
15780                self.change_selections(Default::default(), window, cx, |s| {
15781                    s.select_ranges([first.range()]);
15782                });
15783            }
15784            _ => self.select_next(
15785                &SelectNext {
15786                    replace_newest: true,
15787                },
15788                window,
15789                cx,
15790            )?,
15791        }
15792        Ok(())
15793    }
15794
15795    pub fn find_previous_match(
15796        &mut self,
15797        _: &FindPreviousMatch,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) -> Result<()> {
15801        let selections = self.selections.disjoint_anchors_arc();
15802        match selections.last() {
15803            Some(last) if selections.len() >= 2 => {
15804                self.change_selections(Default::default(), window, cx, |s| {
15805                    s.select_ranges([last.range()]);
15806                });
15807            }
15808            _ => self.select_previous(
15809                &SelectPrevious {
15810                    replace_newest: true,
15811                },
15812                window,
15813                cx,
15814            )?,
15815        }
15816        Ok(())
15817    }
15818
15819    pub fn toggle_comments(
15820        &mut self,
15821        action: &ToggleComments,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        if self.read_only(cx) {
15826            return;
15827        }
15828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15829        let text_layout_details = &self.text_layout_details(window);
15830        self.transact(window, cx, |this, window, cx| {
15831            let mut selections = this
15832                .selections
15833                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15834            let mut edits = Vec::new();
15835            let mut selection_edit_ranges = Vec::new();
15836            let mut last_toggled_row = None;
15837            let snapshot = this.buffer.read(cx).read(cx);
15838            let empty_str: Arc<str> = Arc::default();
15839            let mut suffixes_inserted = Vec::new();
15840            let ignore_indent = action.ignore_indent;
15841
15842            fn comment_prefix_range(
15843                snapshot: &MultiBufferSnapshot,
15844                row: MultiBufferRow,
15845                comment_prefix: &str,
15846                comment_prefix_whitespace: &str,
15847                ignore_indent: bool,
15848            ) -> Range<Point> {
15849                let indent_size = if ignore_indent {
15850                    0
15851                } else {
15852                    snapshot.indent_size_for_line(row).len
15853                };
15854
15855                let start = Point::new(row.0, indent_size);
15856
15857                let mut line_bytes = snapshot
15858                    .bytes_in_range(start..snapshot.max_point())
15859                    .flatten()
15860                    .copied();
15861
15862                // If this line currently begins with the line comment prefix, then record
15863                // the range containing the prefix.
15864                if line_bytes
15865                    .by_ref()
15866                    .take(comment_prefix.len())
15867                    .eq(comment_prefix.bytes())
15868                {
15869                    // Include any whitespace that matches the comment prefix.
15870                    let matching_whitespace_len = line_bytes
15871                        .zip(comment_prefix_whitespace.bytes())
15872                        .take_while(|(a, b)| a == b)
15873                        .count() as u32;
15874                    let end = Point::new(
15875                        start.row,
15876                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15877                    );
15878                    start..end
15879                } else {
15880                    start..start
15881                }
15882            }
15883
15884            fn comment_suffix_range(
15885                snapshot: &MultiBufferSnapshot,
15886                row: MultiBufferRow,
15887                comment_suffix: &str,
15888                comment_suffix_has_leading_space: bool,
15889            ) -> Range<Point> {
15890                let end = Point::new(row.0, snapshot.line_len(row));
15891                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15892
15893                let mut line_end_bytes = snapshot
15894                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15895                    .flatten()
15896                    .copied();
15897
15898                let leading_space_len = if suffix_start_column > 0
15899                    && line_end_bytes.next() == Some(b' ')
15900                    && comment_suffix_has_leading_space
15901                {
15902                    1
15903                } else {
15904                    0
15905                };
15906
15907                // If this line currently begins with the line comment prefix, then record
15908                // the range containing the prefix.
15909                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15910                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15911                    start..end
15912                } else {
15913                    end..end
15914                }
15915            }
15916
15917            // TODO: Handle selections that cross excerpts
15918            for selection in &mut selections {
15919                let start_column = snapshot
15920                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15921                    .len;
15922                let language = if let Some(language) =
15923                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15924                {
15925                    language
15926                } else {
15927                    continue;
15928                };
15929
15930                selection_edit_ranges.clear();
15931
15932                // If multiple selections contain a given row, avoid processing that
15933                // row more than once.
15934                let mut start_row = MultiBufferRow(selection.start.row);
15935                if last_toggled_row == Some(start_row) {
15936                    start_row = start_row.next_row();
15937                }
15938                let end_row =
15939                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15940                        MultiBufferRow(selection.end.row - 1)
15941                    } else {
15942                        MultiBufferRow(selection.end.row)
15943                    };
15944                last_toggled_row = Some(end_row);
15945
15946                if start_row > end_row {
15947                    continue;
15948                }
15949
15950                // If the language has line comments, toggle those.
15951                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15952
15953                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15954                if ignore_indent {
15955                    full_comment_prefixes = full_comment_prefixes
15956                        .into_iter()
15957                        .map(|s| Arc::from(s.trim_end()))
15958                        .collect();
15959                }
15960
15961                if !full_comment_prefixes.is_empty() {
15962                    let first_prefix = full_comment_prefixes
15963                        .first()
15964                        .expect("prefixes is non-empty");
15965                    let prefix_trimmed_lengths = full_comment_prefixes
15966                        .iter()
15967                        .map(|p| p.trim_end_matches(' ').len())
15968                        .collect::<SmallVec<[usize; 4]>>();
15969
15970                    let mut all_selection_lines_are_comments = true;
15971
15972                    for row in start_row.0..=end_row.0 {
15973                        let row = MultiBufferRow(row);
15974                        if start_row < end_row && snapshot.is_line_blank(row) {
15975                            continue;
15976                        }
15977
15978                        let prefix_range = full_comment_prefixes
15979                            .iter()
15980                            .zip(prefix_trimmed_lengths.iter().copied())
15981                            .map(|(prefix, trimmed_prefix_len)| {
15982                                comment_prefix_range(
15983                                    snapshot.deref(),
15984                                    row,
15985                                    &prefix[..trimmed_prefix_len],
15986                                    &prefix[trimmed_prefix_len..],
15987                                    ignore_indent,
15988                                )
15989                            })
15990                            .max_by_key(|range| range.end.column - range.start.column)
15991                            .expect("prefixes is non-empty");
15992
15993                        if prefix_range.is_empty() {
15994                            all_selection_lines_are_comments = false;
15995                        }
15996
15997                        selection_edit_ranges.push(prefix_range);
15998                    }
15999
16000                    if all_selection_lines_are_comments {
16001                        edits.extend(
16002                            selection_edit_ranges
16003                                .iter()
16004                                .cloned()
16005                                .map(|range| (range, empty_str.clone())),
16006                        );
16007                    } else {
16008                        let min_column = selection_edit_ranges
16009                            .iter()
16010                            .map(|range| range.start.column)
16011                            .min()
16012                            .unwrap_or(0);
16013                        edits.extend(selection_edit_ranges.iter().map(|range| {
16014                            let position = Point::new(range.start.row, min_column);
16015                            (position..position, first_prefix.clone())
16016                        }));
16017                    }
16018                } else if let Some(BlockCommentConfig {
16019                    start: full_comment_prefix,
16020                    end: comment_suffix,
16021                    ..
16022                }) = language.block_comment()
16023                {
16024                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16025                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16026                    let prefix_range = comment_prefix_range(
16027                        snapshot.deref(),
16028                        start_row,
16029                        comment_prefix,
16030                        comment_prefix_whitespace,
16031                        ignore_indent,
16032                    );
16033                    let suffix_range = comment_suffix_range(
16034                        snapshot.deref(),
16035                        end_row,
16036                        comment_suffix.trim_start_matches(' '),
16037                        comment_suffix.starts_with(' '),
16038                    );
16039
16040                    if prefix_range.is_empty() || suffix_range.is_empty() {
16041                        edits.push((
16042                            prefix_range.start..prefix_range.start,
16043                            full_comment_prefix.clone(),
16044                        ));
16045                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16046                        suffixes_inserted.push((end_row, comment_suffix.len()));
16047                    } else {
16048                        edits.push((prefix_range, empty_str.clone()));
16049                        edits.push((suffix_range, empty_str.clone()));
16050                    }
16051                } else {
16052                    continue;
16053                }
16054            }
16055
16056            drop(snapshot);
16057            this.buffer.update(cx, |buffer, cx| {
16058                buffer.edit(edits, None, cx);
16059            });
16060
16061            // Adjust selections so that they end before any comment suffixes that
16062            // were inserted.
16063            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16064            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16065            let snapshot = this.buffer.read(cx).read(cx);
16066            for selection in &mut selections {
16067                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16068                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16069                        Ordering::Less => {
16070                            suffixes_inserted.next();
16071                            continue;
16072                        }
16073                        Ordering::Greater => break,
16074                        Ordering::Equal => {
16075                            if selection.end.column == snapshot.line_len(row) {
16076                                if selection.is_empty() {
16077                                    selection.start.column -= suffix_len as u32;
16078                                }
16079                                selection.end.column -= suffix_len as u32;
16080                            }
16081                            break;
16082                        }
16083                    }
16084                }
16085            }
16086
16087            drop(snapshot);
16088            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16089
16090            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16091            let selections_on_single_row = selections.windows(2).all(|selections| {
16092                selections[0].start.row == selections[1].start.row
16093                    && selections[0].end.row == selections[1].end.row
16094                    && selections[0].start.row == selections[0].end.row
16095            });
16096            let selections_selecting = selections
16097                .iter()
16098                .any(|selection| selection.start != selection.end);
16099            let advance_downwards = action.advance_downwards
16100                && selections_on_single_row
16101                && !selections_selecting
16102                && !matches!(this.mode, EditorMode::SingleLine);
16103
16104            if advance_downwards {
16105                let snapshot = this.buffer.read(cx).snapshot(cx);
16106
16107                this.change_selections(Default::default(), window, cx, |s| {
16108                    s.move_cursors_with(|display_snapshot, display_point, _| {
16109                        let mut point = display_point.to_point(display_snapshot);
16110                        point.row += 1;
16111                        point = snapshot.clip_point(point, Bias::Left);
16112                        let display_point = point.to_display_point(display_snapshot);
16113                        let goal = SelectionGoal::HorizontalPosition(
16114                            display_snapshot
16115                                .x_for_display_point(display_point, text_layout_details)
16116                                .into(),
16117                        );
16118                        (display_point, goal)
16119                    })
16120                });
16121            }
16122        });
16123    }
16124
16125    pub fn select_enclosing_symbol(
16126        &mut self,
16127        _: &SelectEnclosingSymbol,
16128        window: &mut Window,
16129        cx: &mut Context<Self>,
16130    ) {
16131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16132
16133        let buffer = self.buffer.read(cx).snapshot(cx);
16134        let old_selections = self
16135            .selections
16136            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16137            .into_boxed_slice();
16138
16139        fn update_selection(
16140            selection: &Selection<MultiBufferOffset>,
16141            buffer_snap: &MultiBufferSnapshot,
16142        ) -> Option<Selection<MultiBufferOffset>> {
16143            let cursor = selection.head();
16144            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16145            for symbol in symbols.iter().rev() {
16146                let start = symbol.range.start.to_offset(buffer_snap);
16147                let end = symbol.range.end.to_offset(buffer_snap);
16148                let new_range = start..end;
16149                if start < selection.start || end > selection.end {
16150                    return Some(Selection {
16151                        id: selection.id,
16152                        start: new_range.start,
16153                        end: new_range.end,
16154                        goal: SelectionGoal::None,
16155                        reversed: selection.reversed,
16156                    });
16157                }
16158            }
16159            None
16160        }
16161
16162        let mut selected_larger_symbol = false;
16163        let new_selections = old_selections
16164            .iter()
16165            .map(|selection| match update_selection(selection, &buffer) {
16166                Some(new_selection) => {
16167                    if new_selection.range() != selection.range() {
16168                        selected_larger_symbol = true;
16169                    }
16170                    new_selection
16171                }
16172                None => selection.clone(),
16173            })
16174            .collect::<Vec<_>>();
16175
16176        if selected_larger_symbol {
16177            self.change_selections(Default::default(), window, cx, |s| {
16178                s.select(new_selections);
16179            });
16180        }
16181    }
16182
16183    pub fn select_larger_syntax_node(
16184        &mut self,
16185        _: &SelectLargerSyntaxNode,
16186        window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        let Some(visible_row_count) = self.visible_row_count() else {
16190            return;
16191        };
16192        let old_selections: Box<[_]> = self
16193            .selections
16194            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16195            .into();
16196        if old_selections.is_empty() {
16197            return;
16198        }
16199
16200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16201
16202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16203        let buffer = self.buffer.read(cx).snapshot(cx);
16204
16205        let mut selected_larger_node = false;
16206        let mut new_selections = old_selections
16207            .iter()
16208            .map(|selection| {
16209                let old_range = selection.start..selection.end;
16210
16211                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16212                    // manually select word at selection
16213                    if ["string_content", "inline"].contains(&node.kind()) {
16214                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16215                        // ignore if word is already selected
16216                        if !word_range.is_empty() && old_range != word_range {
16217                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16218                            // only select word if start and end point belongs to same word
16219                            if word_range == last_word_range {
16220                                selected_larger_node = true;
16221                                return Selection {
16222                                    id: selection.id,
16223                                    start: word_range.start,
16224                                    end: word_range.end,
16225                                    goal: SelectionGoal::None,
16226                                    reversed: selection.reversed,
16227                                };
16228                            }
16229                        }
16230                    }
16231                }
16232
16233                let mut new_range = old_range.clone();
16234                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16235                    new_range = range;
16236                    if !node.is_named() {
16237                        continue;
16238                    }
16239                    if !display_map.intersects_fold(new_range.start)
16240                        && !display_map.intersects_fold(new_range.end)
16241                    {
16242                        break;
16243                    }
16244                }
16245
16246                selected_larger_node |= new_range != old_range;
16247                Selection {
16248                    id: selection.id,
16249                    start: new_range.start,
16250                    end: new_range.end,
16251                    goal: SelectionGoal::None,
16252                    reversed: selection.reversed,
16253                }
16254            })
16255            .collect::<Vec<_>>();
16256
16257        if !selected_larger_node {
16258            return; // don't put this call in the history
16259        }
16260
16261        // scroll based on transformation done to the last selection created by the user
16262        let (last_old, last_new) = old_selections
16263            .last()
16264            .zip(new_selections.last().cloned())
16265            .expect("old_selections isn't empty");
16266
16267        // revert selection
16268        let is_selection_reversed = {
16269            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16270            new_selections.last_mut().expect("checked above").reversed =
16271                should_newest_selection_be_reversed;
16272            should_newest_selection_be_reversed
16273        };
16274
16275        if selected_larger_node {
16276            self.select_syntax_node_history.disable_clearing = true;
16277            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16278                s.select(new_selections.clone());
16279            });
16280            self.select_syntax_node_history.disable_clearing = false;
16281        }
16282
16283        let start_row = last_new.start.to_display_point(&display_map).row().0;
16284        let end_row = last_new.end.to_display_point(&display_map).row().0;
16285        let selection_height = end_row - start_row + 1;
16286        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16287
16288        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16289        let scroll_behavior = if fits_on_the_screen {
16290            self.request_autoscroll(Autoscroll::fit(), cx);
16291            SelectSyntaxNodeScrollBehavior::FitSelection
16292        } else if is_selection_reversed {
16293            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16294            SelectSyntaxNodeScrollBehavior::CursorTop
16295        } else {
16296            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16297            SelectSyntaxNodeScrollBehavior::CursorBottom
16298        };
16299
16300        self.select_syntax_node_history.push((
16301            old_selections,
16302            scroll_behavior,
16303            is_selection_reversed,
16304        ));
16305    }
16306
16307    pub fn select_smaller_syntax_node(
16308        &mut self,
16309        _: &SelectSmallerSyntaxNode,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) {
16313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16314
16315        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16316            self.select_syntax_node_history.pop()
16317        {
16318            if let Some(selection) = selections.last_mut() {
16319                selection.reversed = is_selection_reversed;
16320            }
16321
16322            self.select_syntax_node_history.disable_clearing = true;
16323            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16324                s.select(selections.to_vec());
16325            });
16326            self.select_syntax_node_history.disable_clearing = false;
16327
16328            match scroll_behavior {
16329                SelectSyntaxNodeScrollBehavior::CursorTop => {
16330                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16331                }
16332                SelectSyntaxNodeScrollBehavior::FitSelection => {
16333                    self.request_autoscroll(Autoscroll::fit(), cx);
16334                }
16335                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16336                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16337                }
16338            }
16339        }
16340    }
16341
16342    pub fn unwrap_syntax_node(
16343        &mut self,
16344        _: &UnwrapSyntaxNode,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) {
16348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16349
16350        let buffer = self.buffer.read(cx).snapshot(cx);
16351        let selections = self
16352            .selections
16353            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16354            .into_iter()
16355            // subtracting the offset requires sorting
16356            .sorted_by_key(|i| i.start);
16357
16358        let full_edits = selections
16359            .into_iter()
16360            .filter_map(|selection| {
16361                let child = if selection.is_empty()
16362                    && let Some((_, ancestor_range)) =
16363                        buffer.syntax_ancestor(selection.start..selection.end)
16364                {
16365                    ancestor_range
16366                } else {
16367                    selection.range()
16368                };
16369
16370                let mut parent = child.clone();
16371                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16372                    parent = ancestor_range;
16373                    if parent.start < child.start || parent.end > child.end {
16374                        break;
16375                    }
16376                }
16377
16378                if parent == child {
16379                    return None;
16380                }
16381                let text = buffer.text_for_range(child).collect::<String>();
16382                Some((selection.id, parent, text))
16383            })
16384            .collect::<Vec<_>>();
16385        if full_edits.is_empty() {
16386            return;
16387        }
16388
16389        self.transact(window, cx, |this, window, cx| {
16390            this.buffer.update(cx, |buffer, cx| {
16391                buffer.edit(
16392                    full_edits
16393                        .iter()
16394                        .map(|(_, p, t)| (p.clone(), t.clone()))
16395                        .collect::<Vec<_>>(),
16396                    None,
16397                    cx,
16398                );
16399            });
16400            this.change_selections(Default::default(), window, cx, |s| {
16401                let mut offset = 0;
16402                let mut selections = vec![];
16403                for (id, parent, text) in full_edits {
16404                    let start = parent.start - offset;
16405                    offset += (parent.end - parent.start) - text.len();
16406                    selections.push(Selection {
16407                        id,
16408                        start,
16409                        end: start + text.len(),
16410                        reversed: false,
16411                        goal: Default::default(),
16412                    });
16413                }
16414                s.select(selections);
16415            });
16416        });
16417    }
16418
16419    pub fn select_next_syntax_node(
16420        &mut self,
16421        _: &SelectNextSyntaxNode,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        let old_selections: Box<[_]> = self
16426            .selections
16427            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16428            .into();
16429        if old_selections.is_empty() {
16430            return;
16431        }
16432
16433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16434
16435        let buffer = self.buffer.read(cx).snapshot(cx);
16436        let mut selected_sibling = false;
16437
16438        let new_selections = old_selections
16439            .iter()
16440            .map(|selection| {
16441                let old_range = selection.start..selection.end;
16442
16443                let old_range =
16444                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16445                let excerpt = buffer.excerpt_containing(old_range.clone());
16446
16447                if let Some(mut excerpt) = excerpt
16448                    && let Some(node) = excerpt
16449                        .buffer()
16450                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16451                {
16452                    let new_range = excerpt.map_range_from_buffer(
16453                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16454                    );
16455                    selected_sibling = true;
16456                    Selection {
16457                        id: selection.id,
16458                        start: new_range.start,
16459                        end: new_range.end,
16460                        goal: SelectionGoal::None,
16461                        reversed: selection.reversed,
16462                    }
16463                } else {
16464                    selection.clone()
16465                }
16466            })
16467            .collect::<Vec<_>>();
16468
16469        if selected_sibling {
16470            self.change_selections(
16471                SelectionEffects::scroll(Autoscroll::fit()),
16472                window,
16473                cx,
16474                |s| {
16475                    s.select(new_selections);
16476                },
16477            );
16478        }
16479    }
16480
16481    pub fn select_prev_syntax_node(
16482        &mut self,
16483        _: &SelectPreviousSyntaxNode,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) {
16487        let old_selections: Box<[_]> = self
16488            .selections
16489            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16490            .into();
16491        if old_selections.is_empty() {
16492            return;
16493        }
16494
16495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16496
16497        let buffer = self.buffer.read(cx).snapshot(cx);
16498        let mut selected_sibling = false;
16499
16500        let new_selections = old_selections
16501            .iter()
16502            .map(|selection| {
16503                let old_range = selection.start..selection.end;
16504                let old_range =
16505                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16506                let excerpt = buffer.excerpt_containing(old_range.clone());
16507
16508                if let Some(mut excerpt) = excerpt
16509                    && let Some(node) = excerpt
16510                        .buffer()
16511                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16512                {
16513                    let new_range = excerpt.map_range_from_buffer(
16514                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16515                    );
16516                    selected_sibling = true;
16517                    Selection {
16518                        id: selection.id,
16519                        start: new_range.start,
16520                        end: new_range.end,
16521                        goal: SelectionGoal::None,
16522                        reversed: selection.reversed,
16523                    }
16524                } else {
16525                    selection.clone()
16526                }
16527            })
16528            .collect::<Vec<_>>();
16529
16530        if selected_sibling {
16531            self.change_selections(
16532                SelectionEffects::scroll(Autoscroll::fit()),
16533                window,
16534                cx,
16535                |s| {
16536                    s.select(new_selections);
16537                },
16538            );
16539        }
16540    }
16541
16542    pub fn move_to_start_of_larger_syntax_node(
16543        &mut self,
16544        _: &MoveToStartOfLargerSyntaxNode,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) {
16548        self.move_cursors_to_syntax_nodes(window, cx, false);
16549    }
16550
16551    pub fn move_to_end_of_larger_syntax_node(
16552        &mut self,
16553        _: &MoveToEndOfLargerSyntaxNode,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) {
16557        self.move_cursors_to_syntax_nodes(window, cx, true);
16558    }
16559
16560    fn find_syntax_node_boundary(
16561        &self,
16562        selection_pos: MultiBufferOffset,
16563        move_to_end: bool,
16564        display_map: &DisplaySnapshot,
16565        buffer: &MultiBufferSnapshot,
16566    ) -> MultiBufferOffset {
16567        let old_range = selection_pos..selection_pos;
16568        let mut new_pos = selection_pos;
16569        let mut search_range = old_range;
16570        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16571            search_range = range.clone();
16572            if !node.is_named()
16573                || display_map.intersects_fold(range.start)
16574                || display_map.intersects_fold(range.end)
16575                // If cursor is already at the end of the syntax node, continue searching
16576                || (move_to_end && range.end == selection_pos)
16577                // If cursor is already at the start of the syntax node, continue searching
16578                || (!move_to_end && range.start == selection_pos)
16579            {
16580                continue;
16581            }
16582
16583            // If we found a string_content node, find the largest parent that is still string_content
16584            // Enables us to skip to the end of strings without taking multiple steps inside the string
16585            let (_, final_range) = if node.kind() == "string_content" {
16586                let mut current_node = node;
16587                let mut current_range = range;
16588                while let Some((parent, parent_range)) =
16589                    buffer.syntax_ancestor(current_range.clone())
16590                {
16591                    if parent.kind() == "string_content" {
16592                        current_node = parent;
16593                        current_range = parent_range;
16594                    } else {
16595                        break;
16596                    }
16597                }
16598
16599                (current_node, current_range)
16600            } else {
16601                (node, range)
16602            };
16603
16604            new_pos = if move_to_end {
16605                final_range.end
16606            } else {
16607                final_range.start
16608            };
16609
16610            break;
16611        }
16612
16613        new_pos
16614    }
16615
16616    fn move_cursors_to_syntax_nodes(
16617        &mut self,
16618        window: &mut Window,
16619        cx: &mut Context<Self>,
16620        move_to_end: bool,
16621    ) -> bool {
16622        let old_selections: Box<[_]> = self
16623            .selections
16624            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16625            .into();
16626        if old_selections.is_empty() {
16627            return false;
16628        }
16629
16630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16631
16632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16633        let buffer = self.buffer.read(cx).snapshot(cx);
16634
16635        let mut any_cursor_moved = false;
16636        let new_selections = old_selections
16637            .iter()
16638            .map(|selection| {
16639                if !selection.is_empty() {
16640                    return selection.clone();
16641                }
16642
16643                let selection_pos = selection.head();
16644                let new_pos = self.find_syntax_node_boundary(
16645                    selection_pos,
16646                    move_to_end,
16647                    &display_map,
16648                    &buffer,
16649                );
16650
16651                any_cursor_moved |= new_pos != selection_pos;
16652
16653                Selection {
16654                    id: selection.id,
16655                    start: new_pos,
16656                    end: new_pos,
16657                    goal: SelectionGoal::None,
16658                    reversed: false,
16659                }
16660            })
16661            .collect::<Vec<_>>();
16662
16663        self.change_selections(Default::default(), window, cx, |s| {
16664            s.select(new_selections);
16665        });
16666        self.request_autoscroll(Autoscroll::newest(), cx);
16667
16668        any_cursor_moved
16669    }
16670
16671    pub fn select_to_start_of_larger_syntax_node(
16672        &mut self,
16673        _: &SelectToStartOfLargerSyntaxNode,
16674        window: &mut Window,
16675        cx: &mut Context<Self>,
16676    ) {
16677        self.select_to_syntax_nodes(window, cx, false);
16678    }
16679
16680    pub fn select_to_end_of_larger_syntax_node(
16681        &mut self,
16682        _: &SelectToEndOfLargerSyntaxNode,
16683        window: &mut Window,
16684        cx: &mut Context<Self>,
16685    ) {
16686        self.select_to_syntax_nodes(window, cx, true);
16687    }
16688
16689    fn select_to_syntax_nodes(
16690        &mut self,
16691        window: &mut Window,
16692        cx: &mut Context<Self>,
16693        move_to_end: bool,
16694    ) {
16695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16696
16697        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16698        let buffer = self.buffer.read(cx).snapshot(cx);
16699        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
16700
16701        let new_selections = old_selections
16702            .iter()
16703            .map(|selection| {
16704                let new_pos = self.find_syntax_node_boundary(
16705                    selection.head(),
16706                    move_to_end,
16707                    &display_map,
16708                    &buffer,
16709                );
16710
16711                let mut new_selection = selection.clone();
16712                new_selection.set_head(new_pos, SelectionGoal::None);
16713                new_selection
16714            })
16715            .collect::<Vec<_>>();
16716
16717        self.change_selections(Default::default(), window, cx, |s| {
16718            s.select(new_selections);
16719        });
16720    }
16721
16722    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16723        if !EditorSettings::get_global(cx).gutter.runnables {
16724            self.clear_tasks();
16725            return Task::ready(());
16726        }
16727        let project = self.project().map(Entity::downgrade);
16728        let task_sources = self.lsp_task_sources(cx);
16729        let multi_buffer = self.buffer.downgrade();
16730        cx.spawn_in(window, async move |editor, cx| {
16731            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16732            let Some(project) = project.and_then(|p| p.upgrade()) else {
16733                return;
16734            };
16735            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16736                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16737            }) else {
16738                return;
16739            };
16740
16741            let hide_runnables = project.update(cx, |project, _| project.is_via_collab());
16742            if hide_runnables {
16743                return;
16744            }
16745            let new_rows =
16746                cx.background_spawn({
16747                    let snapshot = display_snapshot.clone();
16748                    async move {
16749                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16750                    }
16751                })
16752                    .await;
16753            let Ok(lsp_tasks) =
16754                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16755            else {
16756                return;
16757            };
16758            let lsp_tasks = lsp_tasks.await;
16759
16760            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16761                lsp_tasks
16762                    .into_iter()
16763                    .flat_map(|(kind, tasks)| {
16764                        tasks.into_iter().filter_map(move |(location, task)| {
16765                            Some((kind.clone(), location?, task))
16766                        })
16767                    })
16768                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16769                        let buffer = location.target.buffer;
16770                        let buffer_snapshot = buffer.read(cx).snapshot();
16771                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16772                            |(excerpt_id, snapshot, _)| {
16773                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16774                                    display_snapshot
16775                                        .buffer_snapshot()
16776                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16777                                } else {
16778                                    None
16779                                }
16780                            },
16781                        );
16782                        if let Some(offset) = offset {
16783                            let task_buffer_range =
16784                                location.target.range.to_point(&buffer_snapshot);
16785                            let context_buffer_range =
16786                                task_buffer_range.to_offset(&buffer_snapshot);
16787                            let context_range = BufferOffset(context_buffer_range.start)
16788                                ..BufferOffset(context_buffer_range.end);
16789
16790                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16791                                .or_insert_with(|| RunnableTasks {
16792                                    templates: Vec::new(),
16793                                    offset,
16794                                    column: task_buffer_range.start.column,
16795                                    extra_variables: HashMap::default(),
16796                                    context_range,
16797                                })
16798                                .templates
16799                                .push((kind, task.original_task().clone()));
16800                        }
16801
16802                        acc
16803                    })
16804            }) else {
16805                return;
16806            };
16807
16808            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16809                buffer.language_settings(cx).tasks.prefer_lsp
16810            }) else {
16811                return;
16812            };
16813
16814            let rows = Self::runnable_rows(
16815                project,
16816                display_snapshot,
16817                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16818                new_rows,
16819                cx.clone(),
16820            )
16821            .await;
16822            editor
16823                .update(cx, |editor, _| {
16824                    editor.clear_tasks();
16825                    for (key, mut value) in rows {
16826                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16827                            value.templates.extend(lsp_tasks.templates);
16828                        }
16829
16830                        editor.insert_tasks(key, value);
16831                    }
16832                    for (key, value) in lsp_tasks_by_rows {
16833                        editor.insert_tasks(key, value);
16834                    }
16835                })
16836                .ok();
16837        })
16838    }
16839    fn fetch_runnable_ranges(
16840        snapshot: &DisplaySnapshot,
16841        range: Range<Anchor>,
16842    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16843        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16844    }
16845
16846    fn runnable_rows(
16847        project: Entity<Project>,
16848        snapshot: DisplaySnapshot,
16849        prefer_lsp: bool,
16850        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16851        cx: AsyncWindowContext,
16852    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16853        cx.spawn(async move |cx| {
16854            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16855            for (run_range, mut runnable) in runnable_ranges {
16856                let Some(tasks) = cx
16857                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16858                    .ok()
16859                else {
16860                    continue;
16861                };
16862                let mut tasks = tasks.await;
16863
16864                if prefer_lsp {
16865                    tasks.retain(|(task_kind, _)| {
16866                        !matches!(task_kind, TaskSourceKind::Language { .. })
16867                    });
16868                }
16869                if tasks.is_empty() {
16870                    continue;
16871                }
16872
16873                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16874                let Some(row) = snapshot
16875                    .buffer_snapshot()
16876                    .buffer_line_for_row(MultiBufferRow(point.row))
16877                    .map(|(_, range)| range.start.row)
16878                else {
16879                    continue;
16880                };
16881
16882                let context_range =
16883                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16884                runnable_rows.push((
16885                    (runnable.buffer_id, row),
16886                    RunnableTasks {
16887                        templates: tasks,
16888                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16889                        context_range,
16890                        column: point.column,
16891                        extra_variables: runnable.extra_captures,
16892                    },
16893                ));
16894            }
16895            runnable_rows
16896        })
16897    }
16898
16899    fn templates_with_tags(
16900        project: &Entity<Project>,
16901        runnable: &mut Runnable,
16902        cx: &mut App,
16903    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16904        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16905            let (worktree_id, file) = project
16906                .buffer_for_id(runnable.buffer, cx)
16907                .and_then(|buffer| buffer.read(cx).file())
16908                .map(|file| (file.worktree_id(cx), file.clone()))
16909                .unzip();
16910
16911            (
16912                project.task_store().read(cx).task_inventory().cloned(),
16913                worktree_id,
16914                file,
16915            )
16916        });
16917
16918        let tags = mem::take(&mut runnable.tags);
16919        let language = runnable.language.clone();
16920        cx.spawn(async move |cx| {
16921            let mut templates_with_tags = Vec::new();
16922            if let Some(inventory) = inventory {
16923                for RunnableTag(tag) in tags {
16924                    let new_tasks = inventory.update(cx, |inventory, cx| {
16925                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16926                    });
16927                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16928                        move |(_, template)| {
16929                            template.tags.iter().any(|source_tag| source_tag == &tag)
16930                        },
16931                    ));
16932                }
16933            }
16934            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16935
16936            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16937                // Strongest source wins; if we have worktree tag binding, prefer that to
16938                // global and language bindings;
16939                // if we have a global binding, prefer that to language binding.
16940                let first_mismatch = templates_with_tags
16941                    .iter()
16942                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16943                if let Some(index) = first_mismatch {
16944                    templates_with_tags.truncate(index);
16945                }
16946            }
16947
16948            templates_with_tags
16949        })
16950    }
16951
16952    pub fn move_to_enclosing_bracket(
16953        &mut self,
16954        _: &MoveToEnclosingBracket,
16955        window: &mut Window,
16956        cx: &mut Context<Self>,
16957    ) {
16958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16959        self.change_selections(Default::default(), window, cx, |s| {
16960            s.move_offsets_with(|snapshot, selection| {
16961                let Some(enclosing_bracket_ranges) =
16962                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16963                else {
16964                    return;
16965                };
16966
16967                let mut best_length = usize::MAX;
16968                let mut best_inside = false;
16969                let mut best_in_bracket_range = false;
16970                let mut best_destination = None;
16971                for (open, close) in enclosing_bracket_ranges {
16972                    let close = close.to_inclusive();
16973                    let length = *close.end() - open.start;
16974                    let inside = selection.start >= open.end && selection.end <= *close.start();
16975                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16976                        || close.contains(&selection.head());
16977
16978                    // If best is next to a bracket and current isn't, skip
16979                    if !in_bracket_range && best_in_bracket_range {
16980                        continue;
16981                    }
16982
16983                    // Prefer smaller lengths unless best is inside and current isn't
16984                    if length > best_length && (best_inside || !inside) {
16985                        continue;
16986                    }
16987
16988                    best_length = length;
16989                    best_inside = inside;
16990                    best_in_bracket_range = in_bracket_range;
16991                    best_destination = Some(
16992                        if close.contains(&selection.start) && close.contains(&selection.end) {
16993                            if inside { open.end } else { open.start }
16994                        } else if inside {
16995                            *close.start()
16996                        } else {
16997                            *close.end()
16998                        },
16999                    );
17000                }
17001
17002                if let Some(destination) = best_destination {
17003                    selection.collapse_to(destination, SelectionGoal::None);
17004                }
17005            })
17006        });
17007    }
17008
17009    pub fn undo_selection(
17010        &mut self,
17011        _: &UndoSelection,
17012        window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17016        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17017            self.selection_history.mode = SelectionHistoryMode::Undoing;
17018            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17019                this.end_selection(window, cx);
17020                this.change_selections(
17021                    SelectionEffects::scroll(Autoscroll::newest()),
17022                    window,
17023                    cx,
17024                    |s| s.select_anchors(entry.selections.to_vec()),
17025                );
17026            });
17027            self.selection_history.mode = SelectionHistoryMode::Normal;
17028
17029            self.select_next_state = entry.select_next_state;
17030            self.select_prev_state = entry.select_prev_state;
17031            self.add_selections_state = entry.add_selections_state;
17032        }
17033    }
17034
17035    pub fn redo_selection(
17036        &mut self,
17037        _: &RedoSelection,
17038        window: &mut Window,
17039        cx: &mut Context<Self>,
17040    ) {
17041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17042        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17043            self.selection_history.mode = SelectionHistoryMode::Redoing;
17044            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17045                this.end_selection(window, cx);
17046                this.change_selections(
17047                    SelectionEffects::scroll(Autoscroll::newest()),
17048                    window,
17049                    cx,
17050                    |s| s.select_anchors(entry.selections.to_vec()),
17051                );
17052            });
17053            self.selection_history.mode = SelectionHistoryMode::Normal;
17054
17055            self.select_next_state = entry.select_next_state;
17056            self.select_prev_state = entry.select_prev_state;
17057            self.add_selections_state = entry.add_selections_state;
17058        }
17059    }
17060
17061    pub fn expand_excerpts(
17062        &mut self,
17063        action: &ExpandExcerpts,
17064        _: &mut Window,
17065        cx: &mut Context<Self>,
17066    ) {
17067        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17068    }
17069
17070    pub fn expand_excerpts_down(
17071        &mut self,
17072        action: &ExpandExcerptsDown,
17073        _: &mut Window,
17074        cx: &mut Context<Self>,
17075    ) {
17076        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17077    }
17078
17079    pub fn expand_excerpts_up(
17080        &mut self,
17081        action: &ExpandExcerptsUp,
17082        _: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) {
17085        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17086    }
17087
17088    pub fn expand_excerpts_for_direction(
17089        &mut self,
17090        lines: u32,
17091        direction: ExpandExcerptDirection,
17092        cx: &mut Context<Self>,
17093    ) {
17094        let selections = self.selections.disjoint_anchors_arc();
17095
17096        let lines = if lines == 0 {
17097            EditorSettings::get_global(cx).expand_excerpt_lines
17098        } else {
17099            lines
17100        };
17101
17102        let snapshot = self.buffer.read(cx).snapshot(cx);
17103        let mut excerpt_ids = selections
17104            .iter()
17105            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17106            .collect::<Vec<_>>();
17107        excerpt_ids.sort();
17108        excerpt_ids.dedup();
17109
17110        if self.delegate_expand_excerpts {
17111            cx.emit(EditorEvent::ExpandExcerptsRequested {
17112                excerpt_ids,
17113                lines,
17114                direction,
17115            });
17116            return;
17117        }
17118
17119        self.buffer.update(cx, |buffer, cx| {
17120            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17121        })
17122    }
17123
17124    pub fn expand_excerpt(
17125        &mut self,
17126        excerpt: ExcerptId,
17127        direction: ExpandExcerptDirection,
17128        window: &mut Window,
17129        cx: &mut Context<Self>,
17130    ) {
17131        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17132
17133        if self.delegate_expand_excerpts {
17134            cx.emit(EditorEvent::ExpandExcerptsRequested {
17135                excerpt_ids: vec![excerpt],
17136                lines: lines_to_expand,
17137                direction,
17138            });
17139            return;
17140        }
17141
17142        let current_scroll_position = self.scroll_position(cx);
17143        let mut scroll = None;
17144
17145        if direction == ExpandExcerptDirection::Down {
17146            let multi_buffer = self.buffer.read(cx);
17147            let snapshot = multi_buffer.snapshot(cx);
17148            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17149                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17150                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17151            {
17152                let buffer_snapshot = buffer.read(cx).snapshot();
17153                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17154                let last_row = buffer_snapshot.max_point().row;
17155                let lines_below = last_row.saturating_sub(excerpt_end_row);
17156                if lines_below >= lines_to_expand {
17157                    scroll = Some(
17158                        current_scroll_position
17159                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17160                    );
17161                }
17162            }
17163        }
17164        if direction == ExpandExcerptDirection::Up
17165            && self
17166                .buffer
17167                .read(cx)
17168                .snapshot(cx)
17169                .excerpt_before(excerpt)
17170                .is_none()
17171        {
17172            scroll = Some(current_scroll_position);
17173        }
17174
17175        self.buffer.update(cx, |buffer, cx| {
17176            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17177        });
17178
17179        if let Some(new_scroll_position) = scroll {
17180            self.set_scroll_position(new_scroll_position, window, cx);
17181        }
17182    }
17183
17184    pub fn go_to_singleton_buffer_point(
17185        &mut self,
17186        point: Point,
17187        window: &mut Window,
17188        cx: &mut Context<Self>,
17189    ) {
17190        self.go_to_singleton_buffer_range(point..point, window, cx);
17191    }
17192
17193    pub fn go_to_singleton_buffer_range(
17194        &mut self,
17195        range: Range<Point>,
17196        window: &mut Window,
17197        cx: &mut Context<Self>,
17198    ) {
17199        let multibuffer = self.buffer().read(cx);
17200        let Some(buffer) = multibuffer.as_singleton() else {
17201            return;
17202        };
17203        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17204            return;
17205        };
17206        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17207            return;
17208        };
17209        self.change_selections(
17210            SelectionEffects::default().nav_history(true),
17211            window,
17212            cx,
17213            |s| s.select_anchor_ranges([start..end]),
17214        );
17215    }
17216
17217    pub fn go_to_diagnostic(
17218        &mut self,
17219        action: &GoToDiagnostic,
17220        window: &mut Window,
17221        cx: &mut Context<Self>,
17222    ) {
17223        if !self.diagnostics_enabled() {
17224            return;
17225        }
17226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17227        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17228    }
17229
17230    pub fn go_to_prev_diagnostic(
17231        &mut self,
17232        action: &GoToPreviousDiagnostic,
17233        window: &mut Window,
17234        cx: &mut Context<Self>,
17235    ) {
17236        if !self.diagnostics_enabled() {
17237            return;
17238        }
17239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17240        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17241    }
17242
17243    pub fn go_to_diagnostic_impl(
17244        &mut self,
17245        direction: Direction,
17246        severity: GoToDiagnosticSeverityFilter,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        let buffer = self.buffer.read(cx).snapshot(cx);
17251        let selection = self
17252            .selections
17253            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17254
17255        let mut active_group_id = None;
17256        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17257            && active_group.active_range.start.to_offset(&buffer) == selection.start
17258        {
17259            active_group_id = Some(active_group.group_id);
17260        }
17261
17262        fn filtered<'a>(
17263            severity: GoToDiagnosticSeverityFilter,
17264            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17265        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17266            diagnostics
17267                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17268                .filter(|entry| entry.range.start != entry.range.end)
17269                .filter(|entry| !entry.diagnostic.is_unnecessary)
17270        }
17271
17272        let before = filtered(
17273            severity,
17274            buffer
17275                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17276                .filter(|entry| entry.range.start <= selection.start),
17277        );
17278        let after = filtered(
17279            severity,
17280            buffer
17281                .diagnostics_in_range(selection.start..buffer.len())
17282                .filter(|entry| entry.range.start >= selection.start),
17283        );
17284
17285        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17286        if direction == Direction::Prev {
17287            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17288            {
17289                for diagnostic in prev_diagnostics.into_iter().rev() {
17290                    if diagnostic.range.start != selection.start
17291                        || active_group_id
17292                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17293                    {
17294                        found = Some(diagnostic);
17295                        break 'outer;
17296                    }
17297                }
17298            }
17299        } else {
17300            for diagnostic in after.chain(before) {
17301                if diagnostic.range.start != selection.start
17302                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17303                {
17304                    found = Some(diagnostic);
17305                    break;
17306                }
17307            }
17308        }
17309        let Some(next_diagnostic) = found else {
17310            return;
17311        };
17312
17313        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17314        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17315            return;
17316        };
17317        let snapshot = self.snapshot(window, cx);
17318        if snapshot.intersects_fold(next_diagnostic.range.start) {
17319            self.unfold_ranges(
17320                std::slice::from_ref(&next_diagnostic.range),
17321                true,
17322                false,
17323                cx,
17324            );
17325        }
17326        self.change_selections(Default::default(), window, cx, |s| {
17327            s.select_ranges(vec![
17328                next_diagnostic.range.start..next_diagnostic.range.start,
17329            ])
17330        });
17331        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17332        self.refresh_edit_prediction(false, true, window, cx);
17333    }
17334
17335    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17337        let snapshot = self.snapshot(window, cx);
17338        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17339        self.go_to_hunk_before_or_after_position(
17340            &snapshot,
17341            selection.head(),
17342            Direction::Next,
17343            window,
17344            cx,
17345        );
17346    }
17347
17348    pub fn go_to_hunk_before_or_after_position(
17349        &mut self,
17350        snapshot: &EditorSnapshot,
17351        position: Point,
17352        direction: Direction,
17353        window: &mut Window,
17354        cx: &mut Context<Editor>,
17355    ) {
17356        let row = if direction == Direction::Next {
17357            self.hunk_after_position(snapshot, position)
17358                .map(|hunk| hunk.row_range.start)
17359        } else {
17360            self.hunk_before_position(snapshot, position)
17361        };
17362
17363        if let Some(row) = row {
17364            let destination = Point::new(row.0, 0);
17365            let autoscroll = Autoscroll::center();
17366
17367            self.unfold_ranges(&[destination..destination], false, false, cx);
17368            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17369                s.select_ranges([destination..destination]);
17370            });
17371        }
17372    }
17373
17374    fn hunk_after_position(
17375        &mut self,
17376        snapshot: &EditorSnapshot,
17377        position: Point,
17378    ) -> Option<MultiBufferDiffHunk> {
17379        snapshot
17380            .buffer_snapshot()
17381            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17382            .find(|hunk| hunk.row_range.start.0 > position.row)
17383            .or_else(|| {
17384                snapshot
17385                    .buffer_snapshot()
17386                    .diff_hunks_in_range(Point::zero()..position)
17387                    .find(|hunk| hunk.row_range.end.0 < position.row)
17388            })
17389    }
17390
17391    fn go_to_prev_hunk(
17392        &mut self,
17393        _: &GoToPreviousHunk,
17394        window: &mut Window,
17395        cx: &mut Context<Self>,
17396    ) {
17397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17398        let snapshot = self.snapshot(window, cx);
17399        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17400        self.go_to_hunk_before_or_after_position(
17401            &snapshot,
17402            selection.head(),
17403            Direction::Prev,
17404            window,
17405            cx,
17406        );
17407    }
17408
17409    fn hunk_before_position(
17410        &mut self,
17411        snapshot: &EditorSnapshot,
17412        position: Point,
17413    ) -> Option<MultiBufferRow> {
17414        snapshot
17415            .buffer_snapshot()
17416            .diff_hunk_before(position)
17417            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17418    }
17419
17420    fn go_to_next_change(
17421        &mut self,
17422        _: &GoToNextChange,
17423        window: &mut Window,
17424        cx: &mut Context<Self>,
17425    ) {
17426        if let Some(selections) = self
17427            .change_list
17428            .next_change(1, Direction::Next)
17429            .map(|s| s.to_vec())
17430        {
17431            self.change_selections(Default::default(), window, cx, |s| {
17432                let map = s.display_snapshot();
17433                s.select_display_ranges(selections.iter().map(|a| {
17434                    let point = a.to_display_point(&map);
17435                    point..point
17436                }))
17437            })
17438        }
17439    }
17440
17441    fn go_to_previous_change(
17442        &mut self,
17443        _: &GoToPreviousChange,
17444        window: &mut Window,
17445        cx: &mut Context<Self>,
17446    ) {
17447        if let Some(selections) = self
17448            .change_list
17449            .next_change(1, Direction::Prev)
17450            .map(|s| s.to_vec())
17451        {
17452            self.change_selections(Default::default(), window, cx, |s| {
17453                let map = s.display_snapshot();
17454                s.select_display_ranges(selections.iter().map(|a| {
17455                    let point = a.to_display_point(&map);
17456                    point..point
17457                }))
17458            })
17459        }
17460    }
17461
17462    pub fn go_to_next_document_highlight(
17463        &mut self,
17464        _: &GoToNextDocumentHighlight,
17465        window: &mut Window,
17466        cx: &mut Context<Self>,
17467    ) {
17468        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17469    }
17470
17471    pub fn go_to_prev_document_highlight(
17472        &mut self,
17473        _: &GoToPreviousDocumentHighlight,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) {
17477        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17478    }
17479
17480    pub fn go_to_document_highlight_before_or_after_position(
17481        &mut self,
17482        direction: Direction,
17483        window: &mut Window,
17484        cx: &mut Context<Editor>,
17485    ) {
17486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17487        let snapshot = self.snapshot(window, cx);
17488        let buffer = &snapshot.buffer_snapshot();
17489        let position = self
17490            .selections
17491            .newest::<Point>(&snapshot.display_snapshot)
17492            .head();
17493        let anchor_position = buffer.anchor_after(position);
17494
17495        // Get all document highlights (both read and write)
17496        let mut all_highlights = Vec::new();
17497
17498        if let Some((_, read_highlights)) = self
17499            .background_highlights
17500            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17501        {
17502            all_highlights.extend(read_highlights.iter());
17503        }
17504
17505        if let Some((_, write_highlights)) = self
17506            .background_highlights
17507            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17508        {
17509            all_highlights.extend(write_highlights.iter());
17510        }
17511
17512        if all_highlights.is_empty() {
17513            return;
17514        }
17515
17516        // Sort highlights by position
17517        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17518
17519        let target_highlight = match direction {
17520            Direction::Next => {
17521                // Find the first highlight after the current position
17522                all_highlights
17523                    .iter()
17524                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17525            }
17526            Direction::Prev => {
17527                // Find the last highlight before the current position
17528                all_highlights
17529                    .iter()
17530                    .rev()
17531                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17532            }
17533        };
17534
17535        if let Some(highlight) = target_highlight {
17536            let destination = highlight.start.to_point(buffer);
17537            let autoscroll = Autoscroll::center();
17538
17539            self.unfold_ranges(&[destination..destination], false, false, cx);
17540            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17541                s.select_ranges([destination..destination]);
17542            });
17543        }
17544    }
17545
17546    fn go_to_line<T: 'static>(
17547        &mut self,
17548        position: Anchor,
17549        highlight_color: Option<Hsla>,
17550        window: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) {
17553        let snapshot = self.snapshot(window, cx).display_snapshot;
17554        let position = position.to_point(&snapshot.buffer_snapshot());
17555        let start = snapshot
17556            .buffer_snapshot()
17557            .clip_point(Point::new(position.row, 0), Bias::Left);
17558        let end = start + Point::new(1, 0);
17559        let start = snapshot.buffer_snapshot().anchor_before(start);
17560        let end = snapshot.buffer_snapshot().anchor_before(end);
17561
17562        self.highlight_rows::<T>(
17563            start..end,
17564            highlight_color
17565                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17566            Default::default(),
17567            cx,
17568        );
17569
17570        if self.buffer.read(cx).is_singleton() {
17571            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17572        }
17573    }
17574
17575    pub fn go_to_definition(
17576        &mut self,
17577        _: &GoToDefinition,
17578        window: &mut Window,
17579        cx: &mut Context<Self>,
17580    ) -> Task<Result<Navigated>> {
17581        let definition =
17582            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17583        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17584        cx.spawn_in(window, async move |editor, cx| {
17585            if definition.await? == Navigated::Yes {
17586                return Ok(Navigated::Yes);
17587            }
17588            match fallback_strategy {
17589                GoToDefinitionFallback::None => Ok(Navigated::No),
17590                GoToDefinitionFallback::FindAllReferences => {
17591                    match editor.update_in(cx, |editor, window, cx| {
17592                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17593                    })? {
17594                        Some(references) => references.await,
17595                        None => Ok(Navigated::No),
17596                    }
17597                }
17598            }
17599        })
17600    }
17601
17602    pub fn go_to_declaration(
17603        &mut self,
17604        _: &GoToDeclaration,
17605        window: &mut Window,
17606        cx: &mut Context<Self>,
17607    ) -> Task<Result<Navigated>> {
17608        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17609    }
17610
17611    pub fn go_to_declaration_split(
17612        &mut self,
17613        _: &GoToDeclaration,
17614        window: &mut Window,
17615        cx: &mut Context<Self>,
17616    ) -> Task<Result<Navigated>> {
17617        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17618    }
17619
17620    pub fn go_to_implementation(
17621        &mut self,
17622        _: &GoToImplementation,
17623        window: &mut Window,
17624        cx: &mut Context<Self>,
17625    ) -> Task<Result<Navigated>> {
17626        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17627    }
17628
17629    pub fn go_to_implementation_split(
17630        &mut self,
17631        _: &GoToImplementationSplit,
17632        window: &mut Window,
17633        cx: &mut Context<Self>,
17634    ) -> Task<Result<Navigated>> {
17635        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17636    }
17637
17638    pub fn go_to_type_definition(
17639        &mut self,
17640        _: &GoToTypeDefinition,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643    ) -> Task<Result<Navigated>> {
17644        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17645    }
17646
17647    pub fn go_to_definition_split(
17648        &mut self,
17649        _: &GoToDefinitionSplit,
17650        window: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) -> Task<Result<Navigated>> {
17653        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17654    }
17655
17656    pub fn go_to_type_definition_split(
17657        &mut self,
17658        _: &GoToTypeDefinitionSplit,
17659        window: &mut Window,
17660        cx: &mut Context<Self>,
17661    ) -> Task<Result<Navigated>> {
17662        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17663    }
17664
17665    fn go_to_definition_of_kind(
17666        &mut self,
17667        kind: GotoDefinitionKind,
17668        split: bool,
17669        window: &mut Window,
17670        cx: &mut Context<Self>,
17671    ) -> Task<Result<Navigated>> {
17672        let Some(provider) = self.semantics_provider.clone() else {
17673            return Task::ready(Ok(Navigated::No));
17674        };
17675        let head = self
17676            .selections
17677            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17678            .head();
17679        let buffer = self.buffer.read(cx);
17680        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17681            return Task::ready(Ok(Navigated::No));
17682        };
17683        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17684            return Task::ready(Ok(Navigated::No));
17685        };
17686
17687        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
17688
17689        cx.spawn_in(window, async move |editor, cx| {
17690            let Some(definitions) = definitions.await? else {
17691                return Ok(Navigated::No);
17692            };
17693            let navigated = editor
17694                .update_in(cx, |editor, window, cx| {
17695                    editor.navigate_to_hover_links(
17696                        Some(kind),
17697                        definitions
17698                            .into_iter()
17699                            .filter(|location| {
17700                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17701                            })
17702                            .map(HoverLink::Text)
17703                            .collect::<Vec<_>>(),
17704                        nav_entry,
17705                        split,
17706                        window,
17707                        cx,
17708                    )
17709                })?
17710                .await?;
17711            anyhow::Ok(navigated)
17712        })
17713    }
17714
17715    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17716        let selection = self.selections.newest_anchor();
17717        let head = selection.head();
17718        let tail = selection.tail();
17719
17720        let Some((buffer, start_position)) =
17721            self.buffer.read(cx).text_anchor_for_position(head, cx)
17722        else {
17723            return;
17724        };
17725
17726        let end_position = if head != tail {
17727            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17728                return;
17729            };
17730            Some(pos)
17731        } else {
17732            None
17733        };
17734
17735        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17736            let url = if let Some(end_pos) = end_position {
17737                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17738            } else {
17739                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17740            };
17741
17742            if let Some(url) = url {
17743                cx.update(|window, cx| {
17744                    if parse_zed_link(&url, cx).is_some() {
17745                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17746                    } else {
17747                        cx.open_url(&url);
17748                    }
17749                })?;
17750            }
17751
17752            anyhow::Ok(())
17753        });
17754
17755        url_finder.detach();
17756    }
17757
17758    pub fn open_selected_filename(
17759        &mut self,
17760        _: &OpenSelectedFilename,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        let Some(workspace) = self.workspace() else {
17765            return;
17766        };
17767
17768        let position = self.selections.newest_anchor().head();
17769
17770        let Some((buffer, buffer_position)) =
17771            self.buffer.read(cx).text_anchor_for_position(position, cx)
17772        else {
17773            return;
17774        };
17775
17776        let project = self.project.clone();
17777
17778        cx.spawn_in(window, async move |_, cx| {
17779            let result = find_file(&buffer, project, buffer_position, cx).await;
17780
17781            if let Some((_, path)) = result {
17782                workspace
17783                    .update_in(cx, |workspace, window, cx| {
17784                        workspace.open_resolved_path(path, window, cx)
17785                    })?
17786                    .await?;
17787            }
17788            anyhow::Ok(())
17789        })
17790        .detach();
17791    }
17792
17793    pub(crate) fn navigate_to_hover_links(
17794        &mut self,
17795        kind: Option<GotoDefinitionKind>,
17796        definitions: Vec<HoverLink>,
17797        origin: Option<NavigationEntry>,
17798        split: bool,
17799        window: &mut Window,
17800        cx: &mut Context<Editor>,
17801    ) -> Task<Result<Navigated>> {
17802        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17803        let mut first_url_or_file = None;
17804        let definitions: Vec<_> = definitions
17805            .into_iter()
17806            .filter_map(|def| match def {
17807                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17808                HoverLink::InlayHint(lsp_location, server_id) => {
17809                    let computation =
17810                        self.compute_target_location(lsp_location, server_id, window, cx);
17811                    Some(cx.background_spawn(computation))
17812                }
17813                HoverLink::Url(url) => {
17814                    first_url_or_file = Some(Either::Left(url));
17815                    None
17816                }
17817                HoverLink::File(path) => {
17818                    first_url_or_file = Some(Either::Right(path));
17819                    None
17820                }
17821            })
17822            .collect();
17823
17824        let workspace = self.workspace();
17825
17826        cx.spawn_in(window, async move |editor, cx| {
17827            let locations: Vec<Location> = future::join_all(definitions)
17828                .await
17829                .into_iter()
17830                .filter_map(|location| location.transpose())
17831                .collect::<Result<_>>()
17832                .context("location tasks")?;
17833            let mut locations = cx.update(|_, cx| {
17834                locations
17835                    .into_iter()
17836                    .map(|location| {
17837                        let buffer = location.buffer.read(cx);
17838                        (location.buffer, location.range.to_point(buffer))
17839                    })
17840                    .into_group_map()
17841            })?;
17842            let mut num_locations = 0;
17843            for ranges in locations.values_mut() {
17844                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17845                ranges.dedup();
17846                num_locations += ranges.len();
17847            }
17848
17849            if num_locations > 1 {
17850                let tab_kind = match kind {
17851                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17852                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17853                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17854                    Some(GotoDefinitionKind::Type) => "Types",
17855                };
17856                let title = editor
17857                    .update_in(cx, |_, _, cx| {
17858                        let target = locations
17859                            .iter()
17860                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17861                            .map(|(buffer, location)| {
17862                                buffer
17863                                    .read(cx)
17864                                    .text_for_range(location.clone())
17865                                    .collect::<String>()
17866                            })
17867                            .filter(|text| !text.contains('\n'))
17868                            .unique()
17869                            .take(3)
17870                            .join(", ");
17871                        if target.is_empty() {
17872                            tab_kind.to_owned()
17873                        } else {
17874                            format!("{tab_kind} for {target}")
17875                        }
17876                    })
17877                    .context("buffer title")?;
17878
17879                let Some(workspace) = workspace else {
17880                    return Ok(Navigated::No);
17881                };
17882
17883                let opened = workspace
17884                    .update_in(cx, |workspace, window, cx| {
17885                        let allow_preview = PreviewTabsSettings::get_global(cx)
17886                            .enable_preview_multibuffer_from_code_navigation;
17887                        if let Some((target_editor, target_pane)) =
17888                            Self::open_locations_in_multibuffer(
17889                                workspace,
17890                                locations,
17891                                title,
17892                                split,
17893                                allow_preview,
17894                                MultibufferSelectionMode::First,
17895                                window,
17896                                cx,
17897                            )
17898                        {
17899                            // We create our own nav history instead of using
17900                            // `target_editor.nav_history` because `nav_history`
17901                            // seems to be populated asynchronously when an item
17902                            // is added to a pane
17903                            let mut nav_history = target_pane
17904                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17905                            target_editor.update(cx, |editor, cx| {
17906                                let nav_data = editor
17907                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
17908                                let target =
17909                                    Some(nav_history.navigation_entry(Some(
17910                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17911                                    )));
17912                                nav_history.push_tag(origin, target);
17913                            })
17914                        }
17915                    })
17916                    .is_ok();
17917
17918                anyhow::Ok(Navigated::from_bool(opened))
17919            } else if num_locations == 0 {
17920                // If there is one url or file, open it directly
17921                match first_url_or_file {
17922                    Some(Either::Left(url)) => {
17923                        cx.update(|window, cx| {
17924                            if parse_zed_link(&url, cx).is_some() {
17925                                window
17926                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17927                            } else {
17928                                cx.open_url(&url);
17929                            }
17930                        })?;
17931                        Ok(Navigated::Yes)
17932                    }
17933                    Some(Either::Right(path)) => {
17934                        // TODO(andrew): respect preview tab settings
17935                        //               `enable_keep_preview_on_code_navigation` and
17936                        //               `enable_preview_file_from_code_navigation`
17937                        let Some(workspace) = workspace else {
17938                            return Ok(Navigated::No);
17939                        };
17940                        workspace
17941                            .update_in(cx, |workspace, window, cx| {
17942                                workspace.open_resolved_path(path, window, cx)
17943                            })?
17944                            .await?;
17945                        Ok(Navigated::Yes)
17946                    }
17947                    None => Ok(Navigated::No),
17948                }
17949            } else {
17950                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17951                let target_range = target_ranges.first().unwrap().clone();
17952
17953                editor.update_in(cx, |editor, window, cx| {
17954                    let range = editor.range_for_match(&target_range);
17955                    let range = collapse_multiline_range(range);
17956
17957                    if !split
17958                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17959                    {
17960                        editor.go_to_singleton_buffer_range(range, window, cx);
17961
17962                        let target =
17963                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
17964                        if let Some(mut nav_history) = editor.nav_history.clone() {
17965                            nav_history.push_tag(origin, target);
17966                        }
17967                    } else {
17968                        let Some(workspace) = workspace else {
17969                            return Navigated::No;
17970                        };
17971                        let pane = workspace.read(cx).active_pane().clone();
17972                        window.defer(cx, move |window, cx| {
17973                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
17974                                workspace.update(cx, |workspace, cx| {
17975                                    let pane = if split {
17976                                        workspace.adjacent_pane(window, cx)
17977                                    } else {
17978                                        workspace.active_pane().clone()
17979                                    };
17980
17981                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17982                                    let keep_old_preview = preview_tabs_settings
17983                                        .enable_keep_preview_on_code_navigation;
17984                                    let allow_new_preview = preview_tabs_settings
17985                                        .enable_preview_file_from_code_navigation;
17986
17987                                    let editor = workspace.open_project_item(
17988                                        pane.clone(),
17989                                        target_buffer.clone(),
17990                                        true,
17991                                        true,
17992                                        keep_old_preview,
17993                                        allow_new_preview,
17994                                        window,
17995                                        cx,
17996                                    );
17997                                    (editor, pane)
17998                                });
17999                            // We create our own nav history instead of using
18000                            // `target_editor.nav_history` because `nav_history`
18001                            // seems to be populated asynchronously when an item
18002                            // is added to a pane
18003                            let mut nav_history = target_pane
18004                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18005                            target_editor.update(cx, |target_editor, cx| {
18006                                // When selecting a definition in a different buffer, disable the nav history
18007                                // to avoid creating a history entry at the previous cursor location.
18008                                pane.update(cx, |pane, _| pane.disable_history());
18009                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18010
18011                                let nav_data = target_editor.navigation_data(
18012                                    target_editor.selections.newest_anchor().head(),
18013                                    cx,
18014                                );
18015                                let target =
18016                                    Some(nav_history.navigation_entry(Some(
18017                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18018                                    )));
18019                                nav_history.push_tag(origin, target);
18020                                pane.update(cx, |pane, _| pane.enable_history());
18021                            });
18022                        });
18023                    }
18024                    Navigated::Yes
18025                })
18026            }
18027        })
18028    }
18029
18030    fn compute_target_location(
18031        &self,
18032        lsp_location: lsp::Location,
18033        server_id: LanguageServerId,
18034        window: &mut Window,
18035        cx: &mut Context<Self>,
18036    ) -> Task<anyhow::Result<Option<Location>>> {
18037        let Some(project) = self.project.clone() else {
18038            return Task::ready(Ok(None));
18039        };
18040
18041        cx.spawn_in(window, async move |editor, cx| {
18042            let location_task = editor.update(cx, |_, cx| {
18043                project.update(cx, |project, cx| {
18044                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18045                })
18046            })?;
18047            let location = Some({
18048                let target_buffer_handle = location_task.await.context("open local buffer")?;
18049                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18050                    let target_start = target_buffer
18051                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18052                    let target_end = target_buffer
18053                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18054                    target_buffer.anchor_after(target_start)
18055                        ..target_buffer.anchor_before(target_end)
18056                });
18057                Location {
18058                    buffer: target_buffer_handle,
18059                    range,
18060                }
18061            });
18062            Ok(location)
18063        })
18064    }
18065
18066    fn go_to_next_reference(
18067        &mut self,
18068        _: &GoToNextReference,
18069        window: &mut Window,
18070        cx: &mut Context<Self>,
18071    ) {
18072        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18073        if let Some(task) = task {
18074            task.detach();
18075        };
18076    }
18077
18078    fn go_to_prev_reference(
18079        &mut self,
18080        _: &GoToPreviousReference,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18085        if let Some(task) = task {
18086            task.detach();
18087        };
18088    }
18089
18090    pub fn go_to_reference_before_or_after_position(
18091        &mut self,
18092        direction: Direction,
18093        count: usize,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) -> Option<Task<Result<()>>> {
18097        let selection = self.selections.newest_anchor();
18098        let head = selection.head();
18099
18100        let multi_buffer = self.buffer.read(cx);
18101
18102        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18103        let workspace = self.workspace()?;
18104        let project = workspace.read(cx).project().clone();
18105        let references =
18106            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18107        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18108            let Some(locations) = references.await? else {
18109                return Ok(());
18110            };
18111
18112            if locations.is_empty() {
18113                // totally normal - the cursor may be on something which is not
18114                // a symbol (e.g. a keyword)
18115                log::info!("no references found under cursor");
18116                return Ok(());
18117            }
18118
18119            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18120
18121            let (locations, current_location_index) =
18122                multi_buffer.update(cx, |multi_buffer, cx| {
18123                    let mut locations = locations
18124                        .into_iter()
18125                        .filter_map(|loc| {
18126                            let start = multi_buffer.buffer_anchor_to_anchor(
18127                                &loc.buffer,
18128                                loc.range.start,
18129                                cx,
18130                            )?;
18131                            let end = multi_buffer.buffer_anchor_to_anchor(
18132                                &loc.buffer,
18133                                loc.range.end,
18134                                cx,
18135                            )?;
18136                            Some(start..end)
18137                        })
18138                        .collect::<Vec<_>>();
18139
18140                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18141                    // There is an O(n) implementation, but given this list will be
18142                    // small (usually <100 items), the extra O(log(n)) factor isn't
18143                    // worth the (surprisingly large amount of) extra complexity.
18144                    locations
18145                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18146
18147                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18148
18149                    let current_location_index = locations.iter().position(|loc| {
18150                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18151                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18152                    });
18153
18154                    (locations, current_location_index)
18155                });
18156
18157            let Some(current_location_index) = current_location_index else {
18158                // This indicates something has gone wrong, because we already
18159                // handle the "no references" case above
18160                log::error!(
18161                    "failed to find current reference under cursor. Total references: {}",
18162                    locations.len()
18163                );
18164                return Ok(());
18165            };
18166
18167            let destination_location_index = match direction {
18168                Direction::Next => (current_location_index + count) % locations.len(),
18169                Direction::Prev => {
18170                    (current_location_index + locations.len() - count % locations.len())
18171                        % locations.len()
18172                }
18173            };
18174
18175            // TODO(cameron): is this needed?
18176            // the thinking is to avoid "jumping to the current location" (avoid
18177            // polluting "jumplist" in vim terms)
18178            if current_location_index == destination_location_index {
18179                return Ok(());
18180            }
18181
18182            let Range { start, end } = locations[destination_location_index];
18183
18184            editor.update_in(cx, |editor, window, cx| {
18185                let effects = SelectionEffects::default();
18186
18187                editor.unfold_ranges(&[start..end], false, false, cx);
18188                editor.change_selections(effects, window, cx, |s| {
18189                    s.select_ranges([start..start]);
18190                });
18191            })?;
18192
18193            Ok(())
18194        }))
18195    }
18196
18197    pub fn find_all_references(
18198        &mut self,
18199        action: &FindAllReferences,
18200        window: &mut Window,
18201        cx: &mut Context<Self>,
18202    ) -> Option<Task<Result<Navigated>>> {
18203        let always_open_multibuffer = action.always_open_multibuffer;
18204        let selection = self.selections.newest_anchor();
18205        let multi_buffer = self.buffer.read(cx);
18206        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18207        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18208        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18209        let head = selection_offset.head();
18210
18211        let head_anchor = multi_buffer_snapshot.anchor_at(
18212            head,
18213            if head < selection_offset.tail() {
18214                Bias::Right
18215            } else {
18216                Bias::Left
18217            },
18218        );
18219
18220        match self
18221            .find_all_references_task_sources
18222            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18223        {
18224            Ok(_) => {
18225                log::info!(
18226                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18227                );
18228                return None;
18229            }
18230            Err(i) => {
18231                self.find_all_references_task_sources.insert(i, head_anchor);
18232            }
18233        }
18234
18235        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18236        let workspace = self.workspace()?;
18237        let project = workspace.read(cx).project().clone();
18238        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18239        Some(cx.spawn_in(window, async move |editor, cx| {
18240            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18241                if let Ok(i) = editor
18242                    .find_all_references_task_sources
18243                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18244                {
18245                    editor.find_all_references_task_sources.remove(i);
18246                }
18247            });
18248
18249            let Some(locations) = references.await? else {
18250                return anyhow::Ok(Navigated::No);
18251            };
18252            let mut locations = cx.update(|_, cx| {
18253                locations
18254                    .into_iter()
18255                    .map(|location| {
18256                        let buffer = location.buffer.read(cx);
18257                        (location.buffer, location.range.to_point(buffer))
18258                    })
18259                    // if special-casing the single-match case, remove ranges
18260                    // that intersect current selection
18261                    .filter(|(location_buffer, location)| {
18262                        if always_open_multibuffer || &buffer != location_buffer {
18263                            return true;
18264                        }
18265
18266                        !location.contains_inclusive(&selection_point.range())
18267                    })
18268                    .into_group_map()
18269            })?;
18270            if locations.is_empty() {
18271                return anyhow::Ok(Navigated::No);
18272            }
18273            for ranges in locations.values_mut() {
18274                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18275                ranges.dedup();
18276            }
18277            let mut num_locations = 0;
18278            for ranges in locations.values_mut() {
18279                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18280                ranges.dedup();
18281                num_locations += ranges.len();
18282            }
18283
18284            if num_locations == 1 && !always_open_multibuffer {
18285                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18286                let target_range = target_ranges.first().unwrap().clone();
18287
18288                return editor.update_in(cx, |editor, window, cx| {
18289                    let range = target_range.to_point(target_buffer.read(cx));
18290                    let range = editor.range_for_match(&range);
18291                    let range = range.start..range.start;
18292
18293                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18294                        editor.go_to_singleton_buffer_range(range, window, cx);
18295                    } else {
18296                        let pane = workspace.read(cx).active_pane().clone();
18297                        window.defer(cx, move |window, cx| {
18298                            let target_editor: Entity<Self> =
18299                                workspace.update(cx, |workspace, cx| {
18300                                    let pane = workspace.active_pane().clone();
18301
18302                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18303                                    let keep_old_preview = preview_tabs_settings
18304                                        .enable_keep_preview_on_code_navigation;
18305                                    let allow_new_preview = preview_tabs_settings
18306                                        .enable_preview_file_from_code_navigation;
18307
18308                                    workspace.open_project_item(
18309                                        pane,
18310                                        target_buffer.clone(),
18311                                        true,
18312                                        true,
18313                                        keep_old_preview,
18314                                        allow_new_preview,
18315                                        window,
18316                                        cx,
18317                                    )
18318                                });
18319                            target_editor.update(cx, |target_editor, cx| {
18320                                // When selecting a definition in a different buffer, disable the nav history
18321                                // to avoid creating a history entry at the previous cursor location.
18322                                pane.update(cx, |pane, _| pane.disable_history());
18323                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18324                                pane.update(cx, |pane, _| pane.enable_history());
18325                            });
18326                        });
18327                    }
18328                    Navigated::No
18329                });
18330            }
18331
18332            workspace.update_in(cx, |workspace, window, cx| {
18333                let target = locations
18334                    .iter()
18335                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18336                    .map(|(buffer, location)| {
18337                        buffer
18338                            .read(cx)
18339                            .text_for_range(location.clone())
18340                            .collect::<String>()
18341                    })
18342                    .filter(|text| !text.contains('\n'))
18343                    .unique()
18344                    .take(3)
18345                    .join(", ");
18346                let title = if target.is_empty() {
18347                    "References".to_owned()
18348                } else {
18349                    format!("References to {target}")
18350                };
18351                let allow_preview = PreviewTabsSettings::get_global(cx)
18352                    .enable_preview_multibuffer_from_code_navigation;
18353                Self::open_locations_in_multibuffer(
18354                    workspace,
18355                    locations,
18356                    title,
18357                    false,
18358                    allow_preview,
18359                    MultibufferSelectionMode::First,
18360                    window,
18361                    cx,
18362                );
18363                Navigated::Yes
18364            })
18365        }))
18366    }
18367
18368    /// Opens a multibuffer with the given project locations in it.
18369    pub fn open_locations_in_multibuffer(
18370        workspace: &mut Workspace,
18371        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18372        title: String,
18373        split: bool,
18374        allow_preview: bool,
18375        multibuffer_selection_mode: MultibufferSelectionMode,
18376        window: &mut Window,
18377        cx: &mut Context<Workspace>,
18378    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18379        if locations.is_empty() {
18380            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18381            return None;
18382        }
18383
18384        let capability = workspace.project().read(cx).capability();
18385        let mut ranges = <Vec<Range<Anchor>>>::new();
18386
18387        // a key to find existing multibuffer editors with the same set of locations
18388        // to prevent us from opening more and more multibuffer tabs for searches and the like
18389        let mut key = (title.clone(), vec![]);
18390        let excerpt_buffer = cx.new(|cx| {
18391            let key = &mut key.1;
18392            let mut multibuffer = MultiBuffer::new(capability);
18393            for (buffer, mut ranges_for_buffer) in locations {
18394                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18395                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18396                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18397                    PathKey::for_buffer(&buffer, cx),
18398                    buffer.clone(),
18399                    ranges_for_buffer,
18400                    multibuffer_context_lines(cx),
18401                    cx,
18402                );
18403                ranges.extend(new_ranges)
18404            }
18405
18406            multibuffer.with_title(title)
18407        });
18408        let existing = workspace.active_pane().update(cx, |pane, cx| {
18409            pane.items()
18410                .filter_map(|item| item.downcast::<Editor>())
18411                .find(|editor| {
18412                    editor
18413                        .read(cx)
18414                        .lookup_key
18415                        .as_ref()
18416                        .and_then(|it| {
18417                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18418                        })
18419                        .is_some_and(|it| *it == key)
18420                })
18421        });
18422        let was_existing = existing.is_some();
18423        let editor = existing.unwrap_or_else(|| {
18424            cx.new(|cx| {
18425                let mut editor = Editor::for_multibuffer(
18426                    excerpt_buffer,
18427                    Some(workspace.project().clone()),
18428                    window,
18429                    cx,
18430                );
18431                editor.lookup_key = Some(Box::new(key));
18432                editor
18433            })
18434        });
18435        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18436            MultibufferSelectionMode::First => {
18437                if let Some(first_range) = ranges.first() {
18438                    editor.change_selections(
18439                        SelectionEffects::no_scroll(),
18440                        window,
18441                        cx,
18442                        |selections| {
18443                            selections.clear_disjoint();
18444                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18445                        },
18446                    );
18447                }
18448                editor.highlight_background::<Self>(
18449                    &ranges,
18450                    |_, theme| theme.colors().editor_highlighted_line_background,
18451                    cx,
18452                );
18453            }
18454            MultibufferSelectionMode::All => {
18455                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18456                    selections.clear_disjoint();
18457                    selections.select_anchor_ranges(ranges);
18458                });
18459            }
18460        });
18461
18462        let item = Box::new(editor.clone());
18463
18464        let pane = if split {
18465            workspace.adjacent_pane(window, cx)
18466        } else {
18467            workspace.active_pane().clone()
18468        };
18469        let activate_pane = split;
18470
18471        let mut destination_index = None;
18472        pane.update(cx, |pane, cx| {
18473            if allow_preview && !was_existing {
18474                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18475            }
18476            if was_existing && !allow_preview {
18477                pane.unpreview_item_if_preview(item.item_id());
18478            }
18479            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18480        });
18481
18482        Some((editor, pane))
18483    }
18484
18485    pub fn rename(
18486        &mut self,
18487        _: &Rename,
18488        window: &mut Window,
18489        cx: &mut Context<Self>,
18490    ) -> Option<Task<Result<()>>> {
18491        use language::ToOffset as _;
18492
18493        let provider = self.semantics_provider.clone()?;
18494        let selection = self.selections.newest_anchor().clone();
18495        let (cursor_buffer, cursor_buffer_position) = self
18496            .buffer
18497            .read(cx)
18498            .text_anchor_for_position(selection.head(), cx)?;
18499        let (tail_buffer, cursor_buffer_position_end) = self
18500            .buffer
18501            .read(cx)
18502            .text_anchor_for_position(selection.tail(), cx)?;
18503        if tail_buffer != cursor_buffer {
18504            return None;
18505        }
18506
18507        let snapshot = cursor_buffer.read(cx).snapshot();
18508        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18509        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18510        let prepare_rename = provider
18511            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18512            .unwrap_or_else(|| Task::ready(Ok(None)));
18513        drop(snapshot);
18514
18515        Some(cx.spawn_in(window, async move |this, cx| {
18516            let rename_range = if let Some(range) = prepare_rename.await? {
18517                Some(range)
18518            } else {
18519                this.update(cx, |this, cx| {
18520                    let buffer = this.buffer.read(cx).snapshot(cx);
18521                    let mut buffer_highlights = this
18522                        .document_highlights_for_position(selection.head(), &buffer)
18523                        .filter(|highlight| {
18524                            highlight.start.excerpt_id == selection.head().excerpt_id
18525                                && highlight.end.excerpt_id == selection.head().excerpt_id
18526                        });
18527                    buffer_highlights
18528                        .next()
18529                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18530                })?
18531            };
18532            if let Some(rename_range) = rename_range {
18533                this.update_in(cx, |this, window, cx| {
18534                    let snapshot = cursor_buffer.read(cx).snapshot();
18535                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18536                    let cursor_offset_in_rename_range =
18537                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18538                    let cursor_offset_in_rename_range_end =
18539                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18540
18541                    this.take_rename(false, window, cx);
18542                    let buffer = this.buffer.read(cx).read(cx);
18543                    let cursor_offset = selection.head().to_offset(&buffer);
18544                    let rename_start =
18545                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18546                    let rename_end = rename_start + rename_buffer_range.len();
18547                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18548                    let mut old_highlight_id = None;
18549                    let old_name: Arc<str> = buffer
18550                        .chunks(rename_start..rename_end, true)
18551                        .map(|chunk| {
18552                            if old_highlight_id.is_none() {
18553                                old_highlight_id = chunk.syntax_highlight_id;
18554                            }
18555                            chunk.text
18556                        })
18557                        .collect::<String>()
18558                        .into();
18559
18560                    drop(buffer);
18561
18562                    // Position the selection in the rename editor so that it matches the current selection.
18563                    this.show_local_selections = false;
18564                    let rename_editor = cx.new(|cx| {
18565                        let mut editor = Editor::single_line(window, cx);
18566                        editor.buffer.update(cx, |buffer, cx| {
18567                            buffer.edit(
18568                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18569                                None,
18570                                cx,
18571                            )
18572                        });
18573                        let cursor_offset_in_rename_range =
18574                            MultiBufferOffset(cursor_offset_in_rename_range);
18575                        let cursor_offset_in_rename_range_end =
18576                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18577                        let rename_selection_range = match cursor_offset_in_rename_range
18578                            .cmp(&cursor_offset_in_rename_range_end)
18579                        {
18580                            Ordering::Equal => {
18581                                editor.select_all(&SelectAll, window, cx);
18582                                return editor;
18583                            }
18584                            Ordering::Less => {
18585                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18586                            }
18587                            Ordering::Greater => {
18588                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18589                            }
18590                        };
18591                        if rename_selection_range.end.0 > old_name.len() {
18592                            editor.select_all(&SelectAll, window, cx);
18593                        } else {
18594                            editor.change_selections(Default::default(), window, cx, |s| {
18595                                s.select_ranges([rename_selection_range]);
18596                            });
18597                        }
18598                        editor
18599                    });
18600                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18601                        if e == &EditorEvent::Focused {
18602                            cx.emit(EditorEvent::FocusedIn)
18603                        }
18604                    })
18605                    .detach();
18606
18607                    let write_highlights =
18608                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18609                    let read_highlights =
18610                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18611                    let ranges = write_highlights
18612                        .iter()
18613                        .flat_map(|(_, ranges)| ranges.iter())
18614                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18615                        .cloned()
18616                        .collect();
18617
18618                    this.highlight_text::<Rename>(
18619                        ranges,
18620                        HighlightStyle {
18621                            fade_out: Some(0.6),
18622                            ..Default::default()
18623                        },
18624                        cx,
18625                    );
18626                    let rename_focus_handle = rename_editor.focus_handle(cx);
18627                    window.focus(&rename_focus_handle, cx);
18628                    let block_id = this.insert_blocks(
18629                        [BlockProperties {
18630                            style: BlockStyle::Flex,
18631                            placement: BlockPlacement::Below(range.start),
18632                            height: Some(1),
18633                            render: Arc::new({
18634                                let rename_editor = rename_editor.clone();
18635                                move |cx: &mut BlockContext| {
18636                                    let mut text_style = cx.editor_style.text.clone();
18637                                    if let Some(highlight_style) = old_highlight_id
18638                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18639                                    {
18640                                        text_style = text_style.highlight(highlight_style);
18641                                    }
18642                                    div()
18643                                        .block_mouse_except_scroll()
18644                                        .pl(cx.anchor_x)
18645                                        .child(EditorElement::new(
18646                                            &rename_editor,
18647                                            EditorStyle {
18648                                                background: cx.theme().system().transparent,
18649                                                local_player: cx.editor_style.local_player,
18650                                                text: text_style,
18651                                                scrollbar_width: cx.editor_style.scrollbar_width,
18652                                                syntax: cx.editor_style.syntax.clone(),
18653                                                status: cx.editor_style.status.clone(),
18654                                                inlay_hints_style: HighlightStyle {
18655                                                    font_weight: Some(FontWeight::BOLD),
18656                                                    ..make_inlay_hints_style(cx.app)
18657                                                },
18658                                                edit_prediction_styles: make_suggestion_styles(
18659                                                    cx.app,
18660                                                ),
18661                                                ..EditorStyle::default()
18662                                            },
18663                                        ))
18664                                        .into_any_element()
18665                                }
18666                            }),
18667                            priority: 0,
18668                        }],
18669                        Some(Autoscroll::fit()),
18670                        cx,
18671                    )[0];
18672                    this.pending_rename = Some(RenameState {
18673                        range,
18674                        old_name,
18675                        editor: rename_editor,
18676                        block_id,
18677                    });
18678                })?;
18679            }
18680
18681            Ok(())
18682        }))
18683    }
18684
18685    pub fn confirm_rename(
18686        &mut self,
18687        _: &ConfirmRename,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) -> Option<Task<Result<()>>> {
18691        let rename = self.take_rename(false, window, cx)?;
18692        let workspace = self.workspace()?.downgrade();
18693        let (buffer, start) = self
18694            .buffer
18695            .read(cx)
18696            .text_anchor_for_position(rename.range.start, cx)?;
18697        let (end_buffer, _) = self
18698            .buffer
18699            .read(cx)
18700            .text_anchor_for_position(rename.range.end, cx)?;
18701        if buffer != end_buffer {
18702            return None;
18703        }
18704
18705        let old_name = rename.old_name;
18706        let new_name = rename.editor.read(cx).text(cx);
18707
18708        let rename = self.semantics_provider.as_ref()?.perform_rename(
18709            &buffer,
18710            start,
18711            new_name.clone(),
18712            cx,
18713        )?;
18714
18715        Some(cx.spawn_in(window, async move |editor, cx| {
18716            let project_transaction = rename.await?;
18717            Self::open_project_transaction(
18718                &editor,
18719                workspace,
18720                project_transaction,
18721                format!("Rename: {}{}", old_name, new_name),
18722                cx,
18723            )
18724            .await?;
18725
18726            editor.update(cx, |editor, cx| {
18727                editor.refresh_document_highlights(cx);
18728            })?;
18729            Ok(())
18730        }))
18731    }
18732
18733    fn take_rename(
18734        &mut self,
18735        moving_cursor: bool,
18736        window: &mut Window,
18737        cx: &mut Context<Self>,
18738    ) -> Option<RenameState> {
18739        let rename = self.pending_rename.take()?;
18740        if rename.editor.focus_handle(cx).is_focused(window) {
18741            window.focus(&self.focus_handle, cx);
18742        }
18743
18744        self.remove_blocks(
18745            [rename.block_id].into_iter().collect(),
18746            Some(Autoscroll::fit()),
18747            cx,
18748        );
18749        self.clear_highlights::<Rename>(cx);
18750        self.show_local_selections = true;
18751
18752        if moving_cursor {
18753            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18754                editor
18755                    .selections
18756                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18757                    .head()
18758            });
18759
18760            // Update the selection to match the position of the selection inside
18761            // the rename editor.
18762            let snapshot = self.buffer.read(cx).read(cx);
18763            let rename_range = rename.range.to_offset(&snapshot);
18764            let cursor_in_editor = snapshot
18765                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18766                .min(rename_range.end);
18767            drop(snapshot);
18768
18769            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18770                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18771            });
18772        } else {
18773            self.refresh_document_highlights(cx);
18774        }
18775
18776        Some(rename)
18777    }
18778
18779    pub fn pending_rename(&self) -> Option<&RenameState> {
18780        self.pending_rename.as_ref()
18781    }
18782
18783    fn format(
18784        &mut self,
18785        _: &Format,
18786        window: &mut Window,
18787        cx: &mut Context<Self>,
18788    ) -> Option<Task<Result<()>>> {
18789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18790
18791        let project = match &self.project {
18792            Some(project) => project.clone(),
18793            None => return None,
18794        };
18795
18796        Some(self.perform_format(
18797            project,
18798            FormatTrigger::Manual,
18799            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18800            window,
18801            cx,
18802        ))
18803    }
18804
18805    fn format_selections(
18806        &mut self,
18807        _: &FormatSelections,
18808        window: &mut Window,
18809        cx: &mut Context<Self>,
18810    ) -> Option<Task<Result<()>>> {
18811        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18812
18813        let project = match &self.project {
18814            Some(project) => project.clone(),
18815            None => return None,
18816        };
18817
18818        let ranges = self
18819            .selections
18820            .all_adjusted(&self.display_snapshot(cx))
18821            .into_iter()
18822            .map(|selection| selection.range())
18823            .collect_vec();
18824
18825        Some(self.perform_format(
18826            project,
18827            FormatTrigger::Manual,
18828            FormatTarget::Ranges(ranges),
18829            window,
18830            cx,
18831        ))
18832    }
18833
18834    fn perform_format(
18835        &mut self,
18836        project: Entity<Project>,
18837        trigger: FormatTrigger,
18838        target: FormatTarget,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) -> Task<Result<()>> {
18842        let buffer = self.buffer.clone();
18843        let (buffers, target) = match target {
18844            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18845            FormatTarget::Ranges(selection_ranges) => {
18846                let multi_buffer = buffer.read(cx);
18847                let snapshot = multi_buffer.read(cx);
18848                let mut buffers = HashSet::default();
18849                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18850                    BTreeMap::new();
18851                for selection_range in selection_ranges {
18852                    for (buffer, buffer_range, _) in
18853                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
18854                    {
18855                        let buffer_id = buffer.remote_id();
18856                        let start = buffer.anchor_before(buffer_range.start);
18857                        let end = buffer.anchor_after(buffer_range.end);
18858                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18859                        buffer_id_to_ranges
18860                            .entry(buffer_id)
18861                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18862                            .or_insert_with(|| vec![start..end]);
18863                    }
18864                }
18865                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18866            }
18867        };
18868
18869        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18870        let selections_prev = transaction_id_prev
18871            .and_then(|transaction_id_prev| {
18872                // default to selections as they were after the last edit, if we have them,
18873                // instead of how they are now.
18874                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18875                // will take you back to where you made the last edit, instead of staying where you scrolled
18876                self.selection_history
18877                    .transaction(transaction_id_prev)
18878                    .map(|t| t.0.clone())
18879            })
18880            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18881
18882        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18883        let format = project.update(cx, |project, cx| {
18884            project.format(buffers, target, true, trigger, cx)
18885        });
18886
18887        cx.spawn_in(window, async move |editor, cx| {
18888            let transaction = futures::select_biased! {
18889                transaction = format.log_err().fuse() => transaction,
18890                () = timeout => {
18891                    log::warn!("timed out waiting for formatting");
18892                    None
18893                }
18894            };
18895
18896            buffer.update(cx, |buffer, cx| {
18897                if let Some(transaction) = transaction
18898                    && !buffer.is_singleton()
18899                {
18900                    buffer.push_transaction(&transaction.0, cx);
18901                }
18902                cx.notify();
18903            });
18904
18905            if let Some(transaction_id_now) =
18906                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18907            {
18908                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18909                if has_new_transaction {
18910                    editor
18911                        .update(cx, |editor, _| {
18912                            editor
18913                                .selection_history
18914                                .insert_transaction(transaction_id_now, selections_prev);
18915                        })
18916                        .ok();
18917                }
18918            }
18919
18920            Ok(())
18921        })
18922    }
18923
18924    fn organize_imports(
18925        &mut self,
18926        _: &OrganizeImports,
18927        window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) -> Option<Task<Result<()>>> {
18930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18931        let project = match &self.project {
18932            Some(project) => project.clone(),
18933            None => return None,
18934        };
18935        Some(self.perform_code_action_kind(
18936            project,
18937            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18938            window,
18939            cx,
18940        ))
18941    }
18942
18943    fn perform_code_action_kind(
18944        &mut self,
18945        project: Entity<Project>,
18946        kind: CodeActionKind,
18947        window: &mut Window,
18948        cx: &mut Context<Self>,
18949    ) -> Task<Result<()>> {
18950        let buffer = self.buffer.clone();
18951        let buffers = buffer.read(cx).all_buffers();
18952        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18953        let apply_action = project.update(cx, |project, cx| {
18954            project.apply_code_action_kind(buffers, kind, true, cx)
18955        });
18956        cx.spawn_in(window, async move |_, cx| {
18957            let transaction = futures::select_biased! {
18958                () = timeout => {
18959                    log::warn!("timed out waiting for executing code action");
18960                    None
18961                }
18962                transaction = apply_action.log_err().fuse() => transaction,
18963            };
18964            buffer.update(cx, |buffer, cx| {
18965                // check if we need this
18966                if let Some(transaction) = transaction
18967                    && !buffer.is_singleton()
18968                {
18969                    buffer.push_transaction(&transaction.0, cx);
18970                }
18971                cx.notify();
18972            });
18973            Ok(())
18974        })
18975    }
18976
18977    pub fn restart_language_server(
18978        &mut self,
18979        _: &RestartLanguageServer,
18980        _: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        if let Some(project) = self.project.clone() {
18984            self.buffer.update(cx, |multi_buffer, cx| {
18985                project.update(cx, |project, cx| {
18986                    project.restart_language_servers_for_buffers(
18987                        multi_buffer.all_buffers().into_iter().collect(),
18988                        HashSet::default(),
18989                        cx,
18990                    );
18991                });
18992            })
18993        }
18994    }
18995
18996    pub fn stop_language_server(
18997        &mut self,
18998        _: &StopLanguageServer,
18999        _: &mut Window,
19000        cx: &mut Context<Self>,
19001    ) {
19002        if let Some(project) = self.project.clone() {
19003            self.buffer.update(cx, |multi_buffer, cx| {
19004                project.update(cx, |project, cx| {
19005                    project.stop_language_servers_for_buffers(
19006                        multi_buffer.all_buffers().into_iter().collect(),
19007                        HashSet::default(),
19008                        cx,
19009                    );
19010                });
19011            });
19012            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19013        }
19014    }
19015
19016    fn cancel_language_server_work(
19017        workspace: &mut Workspace,
19018        _: &actions::CancelLanguageServerWork,
19019        _: &mut Window,
19020        cx: &mut Context<Workspace>,
19021    ) {
19022        let project = workspace.project();
19023        let buffers = workspace
19024            .active_item(cx)
19025            .and_then(|item| item.act_as::<Editor>(cx))
19026            .map_or(HashSet::default(), |editor| {
19027                editor.read(cx).buffer.read(cx).all_buffers()
19028            });
19029        project.update(cx, |project, cx| {
19030            project.cancel_language_server_work_for_buffers(buffers, cx);
19031        });
19032    }
19033
19034    fn show_character_palette(
19035        &mut self,
19036        _: &ShowCharacterPalette,
19037        window: &mut Window,
19038        _: &mut Context<Self>,
19039    ) {
19040        window.show_character_palette();
19041    }
19042
19043    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19044        if !self.diagnostics_enabled() {
19045            return;
19046        }
19047
19048        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19049            let buffer = self.buffer.read(cx).snapshot(cx);
19050            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19051            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19052            let is_valid = buffer
19053                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19054                .any(|entry| {
19055                    entry.diagnostic.is_primary
19056                        && !entry.range.is_empty()
19057                        && entry.range.start == primary_range_start
19058                        && entry.diagnostic.message == active_diagnostics.active_message
19059                });
19060
19061            if !is_valid {
19062                self.dismiss_diagnostics(cx);
19063            }
19064        }
19065    }
19066
19067    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19068        match &self.active_diagnostics {
19069            ActiveDiagnostic::Group(group) => Some(group),
19070            _ => None,
19071        }
19072    }
19073
19074    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19075        if !self.diagnostics_enabled() {
19076            return;
19077        }
19078        self.dismiss_diagnostics(cx);
19079        self.active_diagnostics = ActiveDiagnostic::All;
19080    }
19081
19082    fn activate_diagnostics(
19083        &mut self,
19084        buffer_id: BufferId,
19085        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19086        window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19090            return;
19091        }
19092        self.dismiss_diagnostics(cx);
19093        let snapshot = self.snapshot(window, cx);
19094        let buffer = self.buffer.read(cx).snapshot(cx);
19095        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19096            return;
19097        };
19098
19099        let diagnostic_group = buffer
19100            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19101            .collect::<Vec<_>>();
19102
19103        let language_registry = self
19104            .project()
19105            .map(|project| project.read(cx).languages().clone());
19106
19107        let blocks = renderer.render_group(
19108            diagnostic_group,
19109            buffer_id,
19110            snapshot,
19111            cx.weak_entity(),
19112            language_registry,
19113            cx,
19114        );
19115
19116        let blocks = self.display_map.update(cx, |display_map, cx| {
19117            display_map.insert_blocks(blocks, cx).into_iter().collect()
19118        });
19119        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19120            active_range: buffer.anchor_before(diagnostic.range.start)
19121                ..buffer.anchor_after(diagnostic.range.end),
19122            active_message: diagnostic.diagnostic.message.clone(),
19123            group_id: diagnostic.diagnostic.group_id,
19124            blocks,
19125        });
19126        cx.notify();
19127    }
19128
19129    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19130        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19131            return;
19132        };
19133
19134        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19135        if let ActiveDiagnostic::Group(group) = prev {
19136            self.display_map.update(cx, |display_map, cx| {
19137                display_map.remove_blocks(group.blocks, cx);
19138            });
19139            cx.notify();
19140        }
19141    }
19142
19143    /// Disable inline diagnostics rendering for this editor.
19144    pub fn disable_inline_diagnostics(&mut self) {
19145        self.inline_diagnostics_enabled = false;
19146        self.inline_diagnostics_update = Task::ready(());
19147        self.inline_diagnostics.clear();
19148    }
19149
19150    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19151        self.diagnostics_enabled = false;
19152        self.dismiss_diagnostics(cx);
19153        self.inline_diagnostics_update = Task::ready(());
19154        self.inline_diagnostics.clear();
19155    }
19156
19157    pub fn disable_word_completions(&mut self) {
19158        self.word_completions_enabled = false;
19159    }
19160
19161    pub fn diagnostics_enabled(&self) -> bool {
19162        self.diagnostics_enabled && self.mode.is_full()
19163    }
19164
19165    pub fn inline_diagnostics_enabled(&self) -> bool {
19166        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19167    }
19168
19169    pub fn show_inline_diagnostics(&self) -> bool {
19170        self.show_inline_diagnostics
19171    }
19172
19173    pub fn toggle_inline_diagnostics(
19174        &mut self,
19175        _: &ToggleInlineDiagnostics,
19176        window: &mut Window,
19177        cx: &mut Context<Editor>,
19178    ) {
19179        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19180        self.refresh_inline_diagnostics(false, window, cx);
19181    }
19182
19183    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19184        self.diagnostics_max_severity = severity;
19185        self.display_map.update(cx, |display_map, _| {
19186            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19187        });
19188    }
19189
19190    pub fn toggle_diagnostics(
19191        &mut self,
19192        _: &ToggleDiagnostics,
19193        window: &mut Window,
19194        cx: &mut Context<Editor>,
19195    ) {
19196        if !self.diagnostics_enabled() {
19197            return;
19198        }
19199
19200        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19201            EditorSettings::get_global(cx)
19202                .diagnostics_max_severity
19203                .filter(|severity| severity != &DiagnosticSeverity::Off)
19204                .unwrap_or(DiagnosticSeverity::Hint)
19205        } else {
19206            DiagnosticSeverity::Off
19207        };
19208        self.set_max_diagnostics_severity(new_severity, cx);
19209        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19210            self.active_diagnostics = ActiveDiagnostic::None;
19211            self.inline_diagnostics_update = Task::ready(());
19212            self.inline_diagnostics.clear();
19213        } else {
19214            self.refresh_inline_diagnostics(false, window, cx);
19215        }
19216
19217        cx.notify();
19218    }
19219
19220    pub fn toggle_minimap(
19221        &mut self,
19222        _: &ToggleMinimap,
19223        window: &mut Window,
19224        cx: &mut Context<Editor>,
19225    ) {
19226        if self.supports_minimap(cx) {
19227            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19228        }
19229    }
19230
19231    fn refresh_inline_diagnostics(
19232        &mut self,
19233        debounce: bool,
19234        window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        let max_severity = ProjectSettings::get_global(cx)
19238            .diagnostics
19239            .inline
19240            .max_severity
19241            .unwrap_or(self.diagnostics_max_severity);
19242
19243        if !self.inline_diagnostics_enabled()
19244            || !self.diagnostics_enabled()
19245            || !self.show_inline_diagnostics
19246            || max_severity == DiagnosticSeverity::Off
19247        {
19248            self.inline_diagnostics_update = Task::ready(());
19249            self.inline_diagnostics.clear();
19250            return;
19251        }
19252
19253        let debounce_ms = ProjectSettings::get_global(cx)
19254            .diagnostics
19255            .inline
19256            .update_debounce_ms;
19257        let debounce = if debounce && debounce_ms > 0 {
19258            Some(Duration::from_millis(debounce_ms))
19259        } else {
19260            None
19261        };
19262        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19263            if let Some(debounce) = debounce {
19264                cx.background_executor().timer(debounce).await;
19265            }
19266            let Some(snapshot) = editor.upgrade().map(|editor| {
19267                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19268            }) else {
19269                return;
19270            };
19271
19272            let new_inline_diagnostics = cx
19273                .background_spawn(async move {
19274                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19275                    for diagnostic_entry in
19276                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19277                    {
19278                        let message = diagnostic_entry
19279                            .diagnostic
19280                            .message
19281                            .split_once('\n')
19282                            .map(|(line, _)| line)
19283                            .map(SharedString::new)
19284                            .unwrap_or_else(|| {
19285                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19286                            });
19287                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19288                        let (Ok(i) | Err(i)) = inline_diagnostics
19289                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19290                        inline_diagnostics.insert(
19291                            i,
19292                            (
19293                                start_anchor,
19294                                InlineDiagnostic {
19295                                    message,
19296                                    group_id: diagnostic_entry.diagnostic.group_id,
19297                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19298                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19299                                    severity: diagnostic_entry.diagnostic.severity,
19300                                },
19301                            ),
19302                        );
19303                    }
19304                    inline_diagnostics
19305                })
19306                .await;
19307
19308            editor
19309                .update(cx, |editor, cx| {
19310                    editor.inline_diagnostics = new_inline_diagnostics;
19311                    cx.notify();
19312                })
19313                .ok();
19314        });
19315    }
19316
19317    fn pull_diagnostics(
19318        &mut self,
19319        buffer_id: BufferId,
19320        _window: &Window,
19321        cx: &mut Context<Self>,
19322    ) -> Option<()> {
19323        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
19324            return None;
19325        }
19326        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19327            .diagnostics
19328            .lsp_pull_diagnostics;
19329        if !pull_diagnostics_settings.enabled {
19330            return None;
19331        }
19332        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19333        let project = self.project()?.downgrade();
19334        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19335
19336        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19337            cx.background_executor().timer(debounce).await;
19338            if let Ok(task) = project.update(cx, |project, cx| {
19339                project.lsp_store().update(cx, |lsp_store, cx| {
19340                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19341                })
19342            }) {
19343                task.await.log_err();
19344            }
19345            project
19346                .update(cx, |project, cx| {
19347                    project.lsp_store().update(cx, |lsp_store, cx| {
19348                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19349                    })
19350                })
19351                .log_err();
19352        });
19353
19354        Some(())
19355    }
19356
19357    pub fn set_selections_from_remote(
19358        &mut self,
19359        selections: Vec<Selection<Anchor>>,
19360        pending_selection: Option<Selection<Anchor>>,
19361        window: &mut Window,
19362        cx: &mut Context<Self>,
19363    ) {
19364        let old_cursor_position = self.selections.newest_anchor().head();
19365        self.selections
19366            .change_with(&self.display_snapshot(cx), |s| {
19367                s.select_anchors(selections);
19368                if let Some(pending_selection) = pending_selection {
19369                    s.set_pending(pending_selection, SelectMode::Character);
19370                } else {
19371                    s.clear_pending();
19372                }
19373            });
19374        self.selections_did_change(
19375            false,
19376            &old_cursor_position,
19377            SelectionEffects::default(),
19378            window,
19379            cx,
19380        );
19381    }
19382
19383    pub fn transact(
19384        &mut self,
19385        window: &mut Window,
19386        cx: &mut Context<Self>,
19387        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19388    ) -> Option<TransactionId> {
19389        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19390            this.start_transaction_at(Instant::now(), window, cx);
19391            update(this, window, cx);
19392            this.end_transaction_at(Instant::now(), cx)
19393        })
19394    }
19395
19396    pub fn start_transaction_at(
19397        &mut self,
19398        now: Instant,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) -> Option<TransactionId> {
19402        self.end_selection(window, cx);
19403        if let Some(tx_id) = self
19404            .buffer
19405            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19406        {
19407            self.selection_history
19408                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19409            cx.emit(EditorEvent::TransactionBegun {
19410                transaction_id: tx_id,
19411            });
19412            Some(tx_id)
19413        } else {
19414            None
19415        }
19416    }
19417
19418    pub fn end_transaction_at(
19419        &mut self,
19420        now: Instant,
19421        cx: &mut Context<Self>,
19422    ) -> Option<TransactionId> {
19423        if let Some(transaction_id) = self
19424            .buffer
19425            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19426        {
19427            if let Some((_, end_selections)) =
19428                self.selection_history.transaction_mut(transaction_id)
19429            {
19430                *end_selections = Some(self.selections.disjoint_anchors_arc());
19431            } else {
19432                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19433            }
19434
19435            cx.emit(EditorEvent::Edited { transaction_id });
19436            Some(transaction_id)
19437        } else {
19438            None
19439        }
19440    }
19441
19442    pub fn modify_transaction_selection_history(
19443        &mut self,
19444        transaction_id: TransactionId,
19445        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19446    ) -> bool {
19447        self.selection_history
19448            .transaction_mut(transaction_id)
19449            .map(modify)
19450            .is_some()
19451    }
19452
19453    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19454        if self.selection_mark_mode {
19455            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19456                s.move_with(|_, sel| {
19457                    sel.collapse_to(sel.head(), SelectionGoal::None);
19458                });
19459            })
19460        }
19461        self.selection_mark_mode = true;
19462        cx.notify();
19463    }
19464
19465    pub fn swap_selection_ends(
19466        &mut self,
19467        _: &actions::SwapSelectionEnds,
19468        window: &mut Window,
19469        cx: &mut Context<Self>,
19470    ) {
19471        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19472            s.move_with(|_, sel| {
19473                if sel.start != sel.end {
19474                    sel.reversed = !sel.reversed
19475                }
19476            });
19477        });
19478        self.request_autoscroll(Autoscroll::newest(), cx);
19479        cx.notify();
19480    }
19481
19482    pub fn toggle_focus(
19483        workspace: &mut Workspace,
19484        _: &actions::ToggleFocus,
19485        window: &mut Window,
19486        cx: &mut Context<Workspace>,
19487    ) {
19488        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19489            return;
19490        };
19491        workspace.activate_item(&item, true, true, window, cx);
19492    }
19493
19494    pub fn toggle_fold(
19495        &mut self,
19496        _: &actions::ToggleFold,
19497        window: &mut Window,
19498        cx: &mut Context<Self>,
19499    ) {
19500        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19501            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19502            let selection = self.selections.newest::<Point>(&display_map);
19503
19504            let range = if selection.is_empty() {
19505                let point = selection.head().to_display_point(&display_map);
19506                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19507                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19508                    .to_point(&display_map);
19509                start..end
19510            } else {
19511                selection.range()
19512            };
19513            if display_map.folds_in_range(range).next().is_some() {
19514                self.unfold_lines(&Default::default(), window, cx)
19515            } else {
19516                self.fold(&Default::default(), window, cx)
19517            }
19518        } else {
19519            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19520            let buffer_ids: HashSet<_> = self
19521                .selections
19522                .disjoint_anchor_ranges()
19523                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19524                .collect();
19525
19526            let should_unfold = buffer_ids
19527                .iter()
19528                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19529
19530            for buffer_id in buffer_ids {
19531                if should_unfold {
19532                    self.unfold_buffer(buffer_id, cx);
19533                } else {
19534                    self.fold_buffer(buffer_id, cx);
19535                }
19536            }
19537        }
19538    }
19539
19540    pub fn toggle_fold_recursive(
19541        &mut self,
19542        _: &actions::ToggleFoldRecursive,
19543        window: &mut Window,
19544        cx: &mut Context<Self>,
19545    ) {
19546        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19547
19548        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19549        let range = if selection.is_empty() {
19550            let point = selection.head().to_display_point(&display_map);
19551            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19552            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19553                .to_point(&display_map);
19554            start..end
19555        } else {
19556            selection.range()
19557        };
19558        if display_map.folds_in_range(range).next().is_some() {
19559            self.unfold_recursive(&Default::default(), window, cx)
19560        } else {
19561            self.fold_recursive(&Default::default(), window, cx)
19562        }
19563    }
19564
19565    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19566        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19567            let mut to_fold = Vec::new();
19568            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19569            let selections = self.selections.all_adjusted(&display_map);
19570
19571            for selection in selections {
19572                let range = selection.range().sorted();
19573                let buffer_start_row = range.start.row;
19574
19575                if range.start.row != range.end.row {
19576                    let mut found = false;
19577                    let mut row = range.start.row;
19578                    while row <= range.end.row {
19579                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19580                        {
19581                            found = true;
19582                            row = crease.range().end.row + 1;
19583                            to_fold.push(crease);
19584                        } else {
19585                            row += 1
19586                        }
19587                    }
19588                    if found {
19589                        continue;
19590                    }
19591                }
19592
19593                for row in (0..=range.start.row).rev() {
19594                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19595                        && crease.range().end.row >= buffer_start_row
19596                    {
19597                        to_fold.push(crease);
19598                        if row <= range.start.row {
19599                            break;
19600                        }
19601                    }
19602                }
19603            }
19604
19605            self.fold_creases(to_fold, true, window, cx);
19606        } else {
19607            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19608            let buffer_ids = self
19609                .selections
19610                .disjoint_anchor_ranges()
19611                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19612                .collect::<HashSet<_>>();
19613            for buffer_id in buffer_ids {
19614                self.fold_buffer(buffer_id, cx);
19615            }
19616        }
19617    }
19618
19619    pub fn toggle_fold_all(
19620        &mut self,
19621        _: &actions::ToggleFoldAll,
19622        window: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        let has_folds = if self.buffer.read(cx).is_singleton() {
19626            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19627            let has_folds = display_map
19628                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19629                .next()
19630                .is_some();
19631            has_folds
19632        } else {
19633            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19634            let has_folds = buffer_ids
19635                .iter()
19636                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19637            has_folds
19638        };
19639
19640        if has_folds {
19641            self.unfold_all(&actions::UnfoldAll, window, cx);
19642        } else {
19643            self.fold_all(&actions::FoldAll, window, cx);
19644        }
19645    }
19646
19647    fn fold_at_level(
19648        &mut self,
19649        fold_at: &FoldAtLevel,
19650        window: &mut Window,
19651        cx: &mut Context<Self>,
19652    ) {
19653        if !self.buffer.read(cx).is_singleton() {
19654            return;
19655        }
19656
19657        let fold_at_level = fold_at.0;
19658        let snapshot = self.buffer.read(cx).snapshot(cx);
19659        let mut to_fold = Vec::new();
19660        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19661
19662        let row_ranges_to_keep: Vec<Range<u32>> = self
19663            .selections
19664            .all::<Point>(&self.display_snapshot(cx))
19665            .into_iter()
19666            .map(|sel| sel.start.row..sel.end.row)
19667            .collect();
19668
19669        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19670            while start_row < end_row {
19671                match self
19672                    .snapshot(window, cx)
19673                    .crease_for_buffer_row(MultiBufferRow(start_row))
19674                {
19675                    Some(crease) => {
19676                        let nested_start_row = crease.range().start.row + 1;
19677                        let nested_end_row = crease.range().end.row;
19678
19679                        if current_level < fold_at_level {
19680                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19681                        } else if current_level == fold_at_level {
19682                            // Fold iff there is no selection completely contained within the fold region
19683                            if !row_ranges_to_keep.iter().any(|selection| {
19684                                selection.end >= nested_start_row
19685                                    && selection.start <= nested_end_row
19686                            }) {
19687                                to_fold.push(crease);
19688                            }
19689                        }
19690
19691                        start_row = nested_end_row + 1;
19692                    }
19693                    None => start_row += 1,
19694                }
19695            }
19696        }
19697
19698        self.fold_creases(to_fold, true, window, cx);
19699    }
19700
19701    pub fn fold_at_level_1(
19702        &mut self,
19703        _: &actions::FoldAtLevel1,
19704        window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) {
19707        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19708    }
19709
19710    pub fn fold_at_level_2(
19711        &mut self,
19712        _: &actions::FoldAtLevel2,
19713        window: &mut Window,
19714        cx: &mut Context<Self>,
19715    ) {
19716        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19717    }
19718
19719    pub fn fold_at_level_3(
19720        &mut self,
19721        _: &actions::FoldAtLevel3,
19722        window: &mut Window,
19723        cx: &mut Context<Self>,
19724    ) {
19725        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19726    }
19727
19728    pub fn fold_at_level_4(
19729        &mut self,
19730        _: &actions::FoldAtLevel4,
19731        window: &mut Window,
19732        cx: &mut Context<Self>,
19733    ) {
19734        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19735    }
19736
19737    pub fn fold_at_level_5(
19738        &mut self,
19739        _: &actions::FoldAtLevel5,
19740        window: &mut Window,
19741        cx: &mut Context<Self>,
19742    ) {
19743        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19744    }
19745
19746    pub fn fold_at_level_6(
19747        &mut self,
19748        _: &actions::FoldAtLevel6,
19749        window: &mut Window,
19750        cx: &mut Context<Self>,
19751    ) {
19752        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19753    }
19754
19755    pub fn fold_at_level_7(
19756        &mut self,
19757        _: &actions::FoldAtLevel7,
19758        window: &mut Window,
19759        cx: &mut Context<Self>,
19760    ) {
19761        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19762    }
19763
19764    pub fn fold_at_level_8(
19765        &mut self,
19766        _: &actions::FoldAtLevel8,
19767        window: &mut Window,
19768        cx: &mut Context<Self>,
19769    ) {
19770        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19771    }
19772
19773    pub fn fold_at_level_9(
19774        &mut self,
19775        _: &actions::FoldAtLevel9,
19776        window: &mut Window,
19777        cx: &mut Context<Self>,
19778    ) {
19779        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19780    }
19781
19782    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19783        if self.buffer.read(cx).is_singleton() {
19784            let mut fold_ranges = Vec::new();
19785            let snapshot = self.buffer.read(cx).snapshot(cx);
19786
19787            for row in 0..snapshot.max_row().0 {
19788                if let Some(foldable_range) = self
19789                    .snapshot(window, cx)
19790                    .crease_for_buffer_row(MultiBufferRow(row))
19791                {
19792                    fold_ranges.push(foldable_range);
19793                }
19794            }
19795
19796            self.fold_creases(fold_ranges, true, window, cx);
19797        } else {
19798            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19799                editor
19800                    .update_in(cx, |editor, _, cx| {
19801                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19802                            editor.fold_buffer(buffer_id, cx);
19803                        }
19804                    })
19805                    .ok();
19806            });
19807        }
19808        cx.emit(SearchEvent::ResultsCollapsedChanged(
19809            CollapseDirection::Collapsed,
19810        ));
19811    }
19812
19813    pub fn fold_function_bodies(
19814        &mut self,
19815        _: &actions::FoldFunctionBodies,
19816        window: &mut Window,
19817        cx: &mut Context<Self>,
19818    ) {
19819        let snapshot = self.buffer.read(cx).snapshot(cx);
19820
19821        let ranges = snapshot
19822            .text_object_ranges(
19823                MultiBufferOffset(0)..snapshot.len(),
19824                TreeSitterOptions::default(),
19825            )
19826            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19827            .collect::<Vec<_>>();
19828
19829        let creases = ranges
19830            .into_iter()
19831            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19832            .collect();
19833
19834        self.fold_creases(creases, true, window, cx);
19835    }
19836
19837    pub fn fold_recursive(
19838        &mut self,
19839        _: &actions::FoldRecursive,
19840        window: &mut Window,
19841        cx: &mut Context<Self>,
19842    ) {
19843        let mut to_fold = Vec::new();
19844        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19845        let selections = self.selections.all_adjusted(&display_map);
19846
19847        for selection in selections {
19848            let range = selection.range().sorted();
19849            let buffer_start_row = range.start.row;
19850
19851            if range.start.row != range.end.row {
19852                let mut found = false;
19853                for row in range.start.row..=range.end.row {
19854                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19855                        found = true;
19856                        to_fold.push(crease);
19857                    }
19858                }
19859                if found {
19860                    continue;
19861                }
19862            }
19863
19864            for row in (0..=range.start.row).rev() {
19865                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19866                    if crease.range().end.row >= buffer_start_row {
19867                        to_fold.push(crease);
19868                    } else {
19869                        break;
19870                    }
19871                }
19872            }
19873        }
19874
19875        self.fold_creases(to_fold, true, window, cx);
19876    }
19877
19878    pub fn fold_at(
19879        &mut self,
19880        buffer_row: MultiBufferRow,
19881        window: &mut Window,
19882        cx: &mut Context<Self>,
19883    ) {
19884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19885
19886        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19887            let autoscroll = self
19888                .selections
19889                .all::<Point>(&display_map)
19890                .iter()
19891                .any(|selection| crease.range().overlaps(&selection.range()));
19892
19893            self.fold_creases(vec![crease], autoscroll, window, cx);
19894        }
19895    }
19896
19897    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19898        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19899            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19900            let buffer = display_map.buffer_snapshot();
19901            let selections = self.selections.all::<Point>(&display_map);
19902            let ranges = selections
19903                .iter()
19904                .map(|s| {
19905                    let range = s.display_range(&display_map).sorted();
19906                    let mut start = range.start.to_point(&display_map);
19907                    let mut end = range.end.to_point(&display_map);
19908                    start.column = 0;
19909                    end.column = buffer.line_len(MultiBufferRow(end.row));
19910                    start..end
19911                })
19912                .collect::<Vec<_>>();
19913
19914            self.unfold_ranges(&ranges, true, true, cx);
19915        } else {
19916            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19917            let buffer_ids = self
19918                .selections
19919                .disjoint_anchor_ranges()
19920                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19921                .collect::<HashSet<_>>();
19922            for buffer_id in buffer_ids {
19923                self.unfold_buffer(buffer_id, cx);
19924            }
19925        }
19926    }
19927
19928    pub fn unfold_recursive(
19929        &mut self,
19930        _: &UnfoldRecursive,
19931        _window: &mut Window,
19932        cx: &mut Context<Self>,
19933    ) {
19934        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19935        let selections = self.selections.all::<Point>(&display_map);
19936        let ranges = selections
19937            .iter()
19938            .map(|s| {
19939                let mut range = s.display_range(&display_map).sorted();
19940                *range.start.column_mut() = 0;
19941                *range.end.column_mut() = display_map.line_len(range.end.row());
19942                let start = range.start.to_point(&display_map);
19943                let end = range.end.to_point(&display_map);
19944                start..end
19945            })
19946            .collect::<Vec<_>>();
19947
19948        self.unfold_ranges(&ranges, true, true, cx);
19949    }
19950
19951    pub fn unfold_at(
19952        &mut self,
19953        buffer_row: MultiBufferRow,
19954        _window: &mut Window,
19955        cx: &mut Context<Self>,
19956    ) {
19957        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19958
19959        let intersection_range = Point::new(buffer_row.0, 0)
19960            ..Point::new(
19961                buffer_row.0,
19962                display_map.buffer_snapshot().line_len(buffer_row),
19963            );
19964
19965        let autoscroll = self
19966            .selections
19967            .all::<Point>(&display_map)
19968            .iter()
19969            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19970
19971        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19972    }
19973
19974    pub fn unfold_all(
19975        &mut self,
19976        _: &actions::UnfoldAll,
19977        _window: &mut Window,
19978        cx: &mut Context<Self>,
19979    ) {
19980        if self.buffer.read(cx).is_singleton() {
19981            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19982            self.unfold_ranges(
19983                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19984                true,
19985                true,
19986                cx,
19987            );
19988        } else {
19989            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19990                editor
19991                    .update(cx, |editor, cx| {
19992                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19993                            editor.unfold_buffer(buffer_id, cx);
19994                        }
19995                    })
19996                    .ok();
19997            });
19998        }
19999        cx.emit(SearchEvent::ResultsCollapsedChanged(
20000            CollapseDirection::Expanded,
20001        ));
20002    }
20003
20004    pub fn fold_selected_ranges(
20005        &mut self,
20006        _: &FoldSelectedRanges,
20007        window: &mut Window,
20008        cx: &mut Context<Self>,
20009    ) {
20010        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20011        let selections = self.selections.all_adjusted(&display_map);
20012        let ranges = selections
20013            .into_iter()
20014            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20015            .collect::<Vec<_>>();
20016        self.fold_creases(ranges, true, window, cx);
20017    }
20018
20019    pub fn fold_ranges<T: ToOffset + Clone>(
20020        &mut self,
20021        ranges: Vec<Range<T>>,
20022        auto_scroll: bool,
20023        window: &mut Window,
20024        cx: &mut Context<Self>,
20025    ) {
20026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20027        let ranges = ranges
20028            .into_iter()
20029            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20030            .collect::<Vec<_>>();
20031        self.fold_creases(ranges, auto_scroll, window, cx);
20032    }
20033
20034    pub fn fold_creases<T: ToOffset + Clone>(
20035        &mut self,
20036        creases: Vec<Crease<T>>,
20037        auto_scroll: bool,
20038        _window: &mut Window,
20039        cx: &mut Context<Self>,
20040    ) {
20041        if creases.is_empty() {
20042            return;
20043        }
20044
20045        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20046
20047        if auto_scroll {
20048            self.request_autoscroll(Autoscroll::fit(), cx);
20049        }
20050
20051        cx.notify();
20052
20053        self.scrollbar_marker_state.dirty = true;
20054        self.folds_did_change(cx);
20055    }
20056
20057    /// Removes any folds whose ranges intersect any of the given ranges.
20058    pub fn unfold_ranges<T: ToOffset + Clone>(
20059        &mut self,
20060        ranges: &[Range<T>],
20061        inclusive: bool,
20062        auto_scroll: bool,
20063        cx: &mut Context<Self>,
20064    ) {
20065        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20066            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
20067        });
20068        self.folds_did_change(cx);
20069    }
20070
20071    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20072        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
20073            return;
20074        }
20075
20076        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20077        self.display_map.update(cx, |display_map, cx| {
20078            display_map.fold_buffers([buffer_id], cx)
20079        });
20080
20081        let snapshot = self.display_snapshot(cx);
20082        self.selections.change_with(&snapshot, |selections| {
20083            selections.remove_selections_from_buffer(buffer_id);
20084        });
20085
20086        cx.emit(EditorEvent::BufferFoldToggled {
20087            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
20088            folded: true,
20089        });
20090        cx.notify();
20091    }
20092
20093    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20094        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20095            return;
20096        }
20097        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20098        self.display_map.update(cx, |display_map, cx| {
20099            display_map.unfold_buffers([buffer_id], cx);
20100        });
20101        cx.emit(EditorEvent::BufferFoldToggled {
20102            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
20103            folded: false,
20104        });
20105        cx.notify();
20106    }
20107
20108    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20109        self.display_map.read(cx).is_buffer_folded(buffer)
20110    }
20111
20112    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20113        self.display_map.read(cx).folded_buffers()
20114    }
20115
20116    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20117        self.display_map.update(cx, |display_map, cx| {
20118            display_map.disable_header_for_buffer(buffer_id, cx);
20119        });
20120        cx.notify();
20121    }
20122
20123    /// Removes any folds with the given ranges.
20124    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20125        &mut self,
20126        ranges: &[Range<T>],
20127        type_id: TypeId,
20128        auto_scroll: bool,
20129        cx: &mut Context<Self>,
20130    ) {
20131        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20132            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20133        });
20134        self.folds_did_change(cx);
20135    }
20136
20137    fn remove_folds_with<T: ToOffset + Clone>(
20138        &mut self,
20139        ranges: &[Range<T>],
20140        auto_scroll: bool,
20141        cx: &mut Context<Self>,
20142        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20143    ) {
20144        if ranges.is_empty() {
20145            return;
20146        }
20147
20148        let mut buffers_affected = HashSet::default();
20149        let multi_buffer = self.buffer().read(cx);
20150        for range in ranges {
20151            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20152                buffers_affected.insert(buffer.read(cx).remote_id());
20153            };
20154        }
20155
20156        self.display_map.update(cx, update);
20157
20158        if auto_scroll {
20159            self.request_autoscroll(Autoscroll::fit(), cx);
20160        }
20161
20162        cx.notify();
20163        self.scrollbar_marker_state.dirty = true;
20164        self.active_indent_guides_state.dirty = true;
20165    }
20166
20167    pub fn update_renderer_widths(
20168        &mut self,
20169        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20170        cx: &mut Context<Self>,
20171    ) -> bool {
20172        self.display_map
20173            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20174    }
20175
20176    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20177        self.display_map.read(cx).fold_placeholder.clone()
20178    }
20179
20180    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20181        self.buffer.update(cx, |buffer, cx| {
20182            buffer.set_all_diff_hunks_expanded(cx);
20183        });
20184    }
20185
20186    pub fn expand_all_diff_hunks(
20187        &mut self,
20188        _: &ExpandAllDiffHunks,
20189        _window: &mut Window,
20190        cx: &mut Context<Self>,
20191    ) {
20192        self.buffer.update(cx, |buffer, cx| {
20193            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20194        });
20195    }
20196
20197    pub fn collapse_all_diff_hunks(
20198        &mut self,
20199        _: &CollapseAllDiffHunks,
20200        _window: &mut Window,
20201        cx: &mut Context<Self>,
20202    ) {
20203        self.buffer.update(cx, |buffer, cx| {
20204            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20205        });
20206    }
20207
20208    pub fn toggle_selected_diff_hunks(
20209        &mut self,
20210        _: &ToggleSelectedDiffHunks,
20211        _window: &mut Window,
20212        cx: &mut Context<Self>,
20213    ) {
20214        let ranges: Vec<_> = self
20215            .selections
20216            .disjoint_anchors()
20217            .iter()
20218            .map(|s| s.range())
20219            .collect();
20220        self.toggle_diff_hunks_in_ranges(ranges, cx);
20221    }
20222
20223    pub fn diff_hunks_in_ranges<'a>(
20224        &'a self,
20225        ranges: &'a [Range<Anchor>],
20226        buffer: &'a MultiBufferSnapshot,
20227    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20228        ranges.iter().flat_map(move |range| {
20229            let end_excerpt_id = range.end.excerpt_id;
20230            let range = range.to_point(buffer);
20231            let mut peek_end = range.end;
20232            if range.end.row < buffer.max_row().0 {
20233                peek_end = Point::new(range.end.row + 1, 0);
20234            }
20235            buffer
20236                .diff_hunks_in_range(range.start..peek_end)
20237                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20238        })
20239    }
20240
20241    pub fn has_stageable_diff_hunks_in_ranges(
20242        &self,
20243        ranges: &[Range<Anchor>],
20244        snapshot: &MultiBufferSnapshot,
20245    ) -> bool {
20246        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20247        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20248    }
20249
20250    pub fn toggle_staged_selected_diff_hunks(
20251        &mut self,
20252        _: &::git::ToggleStaged,
20253        _: &mut Window,
20254        cx: &mut Context<Self>,
20255    ) {
20256        let snapshot = self.buffer.read(cx).snapshot(cx);
20257        let ranges: Vec<_> = self
20258            .selections
20259            .disjoint_anchors()
20260            .iter()
20261            .map(|s| s.range())
20262            .collect();
20263        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20264        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20265    }
20266
20267    pub fn set_render_diff_hunk_controls(
20268        &mut self,
20269        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20270        cx: &mut Context<Self>,
20271    ) {
20272        self.render_diff_hunk_controls = render_diff_hunk_controls;
20273        cx.notify();
20274    }
20275
20276    pub fn stage_and_next(
20277        &mut self,
20278        _: &::git::StageAndNext,
20279        window: &mut Window,
20280        cx: &mut Context<Self>,
20281    ) {
20282        self.do_stage_or_unstage_and_next(true, window, cx);
20283    }
20284
20285    pub fn unstage_and_next(
20286        &mut self,
20287        _: &::git::UnstageAndNext,
20288        window: &mut Window,
20289        cx: &mut Context<Self>,
20290    ) {
20291        self.do_stage_or_unstage_and_next(false, window, cx);
20292    }
20293
20294    pub fn stage_or_unstage_diff_hunks(
20295        &mut self,
20296        stage: bool,
20297        ranges: Vec<Range<Anchor>>,
20298        cx: &mut Context<Self>,
20299    ) {
20300        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20301        cx.spawn(async move |this, cx| {
20302            task.await?;
20303            this.update(cx, |this, cx| {
20304                let snapshot = this.buffer.read(cx).snapshot(cx);
20305                let chunk_by = this
20306                    .diff_hunks_in_ranges(&ranges, &snapshot)
20307                    .chunk_by(|hunk| hunk.buffer_id);
20308                for (buffer_id, hunks) in &chunk_by {
20309                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20310                }
20311            })
20312        })
20313        .detach_and_log_err(cx);
20314    }
20315
20316    fn save_buffers_for_ranges_if_needed(
20317        &mut self,
20318        ranges: &[Range<Anchor>],
20319        cx: &mut Context<Editor>,
20320    ) -> Task<Result<()>> {
20321        let multibuffer = self.buffer.read(cx);
20322        let snapshot = multibuffer.read(cx);
20323        let buffer_ids: HashSet<_> = ranges
20324            .iter()
20325            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20326            .collect();
20327        drop(snapshot);
20328
20329        let mut buffers = HashSet::default();
20330        for buffer_id in buffer_ids {
20331            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20332                let buffer = buffer_entity.read(cx);
20333                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20334                {
20335                    buffers.insert(buffer_entity);
20336                }
20337            }
20338        }
20339
20340        if let Some(project) = &self.project {
20341            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20342        } else {
20343            Task::ready(Ok(()))
20344        }
20345    }
20346
20347    fn do_stage_or_unstage_and_next(
20348        &mut self,
20349        stage: bool,
20350        window: &mut Window,
20351        cx: &mut Context<Self>,
20352    ) {
20353        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20354
20355        if ranges.iter().any(|range| range.start != range.end) {
20356            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20357            return;
20358        }
20359
20360        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20361        let snapshot = self.snapshot(window, cx);
20362        let position = self
20363            .selections
20364            .newest::<Point>(&snapshot.display_snapshot)
20365            .head();
20366        let mut row = snapshot
20367            .buffer_snapshot()
20368            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20369            .find(|hunk| hunk.row_range.start.0 > position.row)
20370            .map(|hunk| hunk.row_range.start);
20371
20372        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20373        // Outside of the project diff editor, wrap around to the beginning.
20374        if !all_diff_hunks_expanded {
20375            row = row.or_else(|| {
20376                snapshot
20377                    .buffer_snapshot()
20378                    .diff_hunks_in_range(Point::zero()..position)
20379                    .find(|hunk| hunk.row_range.end.0 < position.row)
20380                    .map(|hunk| hunk.row_range.start)
20381            });
20382        }
20383
20384        if let Some(row) = row {
20385            let destination = Point::new(row.0, 0);
20386            let autoscroll = Autoscroll::center();
20387
20388            self.unfold_ranges(&[destination..destination], false, false, cx);
20389            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20390                s.select_ranges([destination..destination]);
20391            });
20392        }
20393    }
20394
20395    fn do_stage_or_unstage(
20396        &self,
20397        stage: bool,
20398        buffer_id: BufferId,
20399        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20400        cx: &mut App,
20401    ) -> Option<()> {
20402        let project = self.project()?;
20403        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20404        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20405        let buffer_snapshot = buffer.read(cx).snapshot();
20406        let file_exists = buffer_snapshot
20407            .file()
20408            .is_some_and(|file| file.disk_state().exists());
20409        diff.update(cx, |diff, cx| {
20410            diff.stage_or_unstage_hunks(
20411                stage,
20412                &hunks
20413                    .map(|hunk| buffer_diff::DiffHunk {
20414                        buffer_range: hunk.buffer_range,
20415                        // We don't need to pass in word diffs here because they're only used for rendering and
20416                        // this function changes internal state
20417                        base_word_diffs: Vec::default(),
20418                        buffer_word_diffs: Vec::default(),
20419                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20420                            ..hunk.diff_base_byte_range.end.0,
20421                        secondary_status: hunk.status.secondary,
20422                        range: Point::zero()..Point::zero(), // unused
20423                    })
20424                    .collect::<Vec<_>>(),
20425                &buffer_snapshot,
20426                file_exists,
20427                cx,
20428            )
20429        });
20430        None
20431    }
20432
20433    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20434        let ranges: Vec<_> = self
20435            .selections
20436            .disjoint_anchors()
20437            .iter()
20438            .map(|s| s.range())
20439            .collect();
20440        self.buffer
20441            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20442    }
20443
20444    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20445        self.buffer.update(cx, |buffer, cx| {
20446            let ranges = vec![Anchor::min()..Anchor::max()];
20447            if !buffer.all_diff_hunks_expanded()
20448                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20449            {
20450                buffer.collapse_diff_hunks(ranges, cx);
20451                true
20452            } else {
20453                false
20454            }
20455        })
20456    }
20457
20458    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20459        if self.buffer.read(cx).all_diff_hunks_expanded() {
20460            return true;
20461        }
20462        let ranges = vec![Anchor::min()..Anchor::max()];
20463        self.buffer
20464            .read(cx)
20465            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20466    }
20467
20468    fn toggle_diff_hunks_in_ranges(
20469        &mut self,
20470        ranges: Vec<Range<Anchor>>,
20471        cx: &mut Context<Editor>,
20472    ) {
20473        self.buffer.update(cx, |buffer, cx| {
20474            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20475            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20476        })
20477    }
20478
20479    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20480        self.buffer.update(cx, |buffer, cx| {
20481            let snapshot = buffer.snapshot(cx);
20482            let excerpt_id = range.end.excerpt_id;
20483            let point_range = range.to_point(&snapshot);
20484            let expand = !buffer.single_hunk_is_expanded(range, cx);
20485            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20486        })
20487    }
20488
20489    pub(crate) fn apply_all_diff_hunks(
20490        &mut self,
20491        _: &ApplyAllDiffHunks,
20492        window: &mut Window,
20493        cx: &mut Context<Self>,
20494    ) {
20495        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20496
20497        let buffers = self.buffer.read(cx).all_buffers();
20498        for branch_buffer in buffers {
20499            branch_buffer.update(cx, |branch_buffer, cx| {
20500                branch_buffer.merge_into_base(Vec::new(), cx);
20501            });
20502        }
20503
20504        if let Some(project) = self.project.clone() {
20505            self.save(
20506                SaveOptions {
20507                    format: true,
20508                    autosave: false,
20509                },
20510                project,
20511                window,
20512                cx,
20513            )
20514            .detach_and_log_err(cx);
20515        }
20516    }
20517
20518    pub(crate) fn apply_selected_diff_hunks(
20519        &mut self,
20520        _: &ApplyDiffHunk,
20521        window: &mut Window,
20522        cx: &mut Context<Self>,
20523    ) {
20524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20525        let snapshot = self.snapshot(window, cx);
20526        let hunks = snapshot.hunks_for_ranges(
20527            self.selections
20528                .all(&snapshot.display_snapshot)
20529                .into_iter()
20530                .map(|selection| selection.range()),
20531        );
20532        let mut ranges_by_buffer = HashMap::default();
20533        self.transact(window, cx, |editor, _window, cx| {
20534            for hunk in hunks {
20535                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20536                    ranges_by_buffer
20537                        .entry(buffer.clone())
20538                        .or_insert_with(Vec::new)
20539                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20540                }
20541            }
20542
20543            for (buffer, ranges) in ranges_by_buffer {
20544                buffer.update(cx, |buffer, cx| {
20545                    buffer.merge_into_base(ranges, cx);
20546                });
20547            }
20548        });
20549
20550        if let Some(project) = self.project.clone() {
20551            self.save(
20552                SaveOptions {
20553                    format: true,
20554                    autosave: false,
20555                },
20556                project,
20557                window,
20558                cx,
20559            )
20560            .detach_and_log_err(cx);
20561        }
20562    }
20563
20564    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20565        if hovered != self.gutter_hovered {
20566            self.gutter_hovered = hovered;
20567            cx.notify();
20568        }
20569    }
20570
20571    pub fn insert_blocks(
20572        &mut self,
20573        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20574        autoscroll: Option<Autoscroll>,
20575        cx: &mut Context<Self>,
20576    ) -> Vec<CustomBlockId> {
20577        let blocks = self
20578            .display_map
20579            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20580        if let Some(autoscroll) = autoscroll {
20581            self.request_autoscroll(autoscroll, cx);
20582        }
20583        cx.notify();
20584        blocks
20585    }
20586
20587    pub fn resize_blocks(
20588        &mut self,
20589        heights: HashMap<CustomBlockId, u32>,
20590        autoscroll: Option<Autoscroll>,
20591        cx: &mut Context<Self>,
20592    ) {
20593        self.display_map
20594            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20595        if let Some(autoscroll) = autoscroll {
20596            self.request_autoscroll(autoscroll, cx);
20597        }
20598        cx.notify();
20599    }
20600
20601    pub fn replace_blocks(
20602        &mut self,
20603        renderers: HashMap<CustomBlockId, RenderBlock>,
20604        autoscroll: Option<Autoscroll>,
20605        cx: &mut Context<Self>,
20606    ) {
20607        self.display_map
20608            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20609        if let Some(autoscroll) = autoscroll {
20610            self.request_autoscroll(autoscroll, cx);
20611        }
20612        cx.notify();
20613    }
20614
20615    pub fn remove_blocks(
20616        &mut self,
20617        block_ids: HashSet<CustomBlockId>,
20618        autoscroll: Option<Autoscroll>,
20619        cx: &mut Context<Self>,
20620    ) {
20621        self.display_map.update(cx, |display_map, cx| {
20622            display_map.remove_blocks(block_ids, cx)
20623        });
20624        if let Some(autoscroll) = autoscroll {
20625            self.request_autoscroll(autoscroll, cx);
20626        }
20627        cx.notify();
20628    }
20629
20630    pub fn row_for_block(
20631        &self,
20632        block_id: CustomBlockId,
20633        cx: &mut Context<Self>,
20634    ) -> Option<DisplayRow> {
20635        self.display_map
20636            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20637    }
20638
20639    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20640        self.focused_block = Some(focused_block);
20641    }
20642
20643    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20644        self.focused_block.take()
20645    }
20646
20647    pub fn insert_creases(
20648        &mut self,
20649        creases: impl IntoIterator<Item = Crease<Anchor>>,
20650        cx: &mut Context<Self>,
20651    ) -> Vec<CreaseId> {
20652        self.display_map
20653            .update(cx, |map, cx| map.insert_creases(creases, cx))
20654    }
20655
20656    pub fn remove_creases(
20657        &mut self,
20658        ids: impl IntoIterator<Item = CreaseId>,
20659        cx: &mut Context<Self>,
20660    ) -> Vec<(CreaseId, Range<Anchor>)> {
20661        self.display_map
20662            .update(cx, |map, cx| map.remove_creases(ids, cx))
20663    }
20664
20665    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20666        self.display_map
20667            .update(cx, |map, cx| map.snapshot(cx))
20668            .longest_row()
20669    }
20670
20671    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20672        self.display_map
20673            .update(cx, |map, cx| map.snapshot(cx))
20674            .max_point()
20675    }
20676
20677    pub fn text(&self, cx: &App) -> String {
20678        self.buffer.read(cx).read(cx).text()
20679    }
20680
20681    pub fn is_empty(&self, cx: &App) -> bool {
20682        self.buffer.read(cx).read(cx).is_empty()
20683    }
20684
20685    pub fn text_option(&self, cx: &App) -> Option<String> {
20686        let text = self.text(cx);
20687        let text = text.trim();
20688
20689        if text.is_empty() {
20690            return None;
20691        }
20692
20693        Some(text.to_string())
20694    }
20695
20696    pub fn set_text(
20697        &mut self,
20698        text: impl Into<Arc<str>>,
20699        window: &mut Window,
20700        cx: &mut Context<Self>,
20701    ) {
20702        self.transact(window, cx, |this, _, cx| {
20703            this.buffer
20704                .read(cx)
20705                .as_singleton()
20706                .expect("you can only call set_text on editors for singleton buffers")
20707                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20708        });
20709    }
20710
20711    pub fn display_text(&self, cx: &mut App) -> String {
20712        self.display_map
20713            .update(cx, |map, cx| map.snapshot(cx))
20714            .text()
20715    }
20716
20717    fn create_minimap(
20718        &self,
20719        minimap_settings: MinimapSettings,
20720        window: &mut Window,
20721        cx: &mut Context<Self>,
20722    ) -> Option<Entity<Self>> {
20723        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20724            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20725    }
20726
20727    fn initialize_new_minimap(
20728        &self,
20729        minimap_settings: MinimapSettings,
20730        window: &mut Window,
20731        cx: &mut Context<Self>,
20732    ) -> Entity<Self> {
20733        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20734        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20735
20736        let mut minimap = Editor::new_internal(
20737            EditorMode::Minimap {
20738                parent: cx.weak_entity(),
20739            },
20740            self.buffer.clone(),
20741            None,
20742            Some(self.display_map.clone()),
20743            window,
20744            cx,
20745        );
20746        minimap.scroll_manager.clone_state(&self.scroll_manager);
20747        minimap.set_text_style_refinement(TextStyleRefinement {
20748            font_size: Some(MINIMAP_FONT_SIZE),
20749            font_weight: Some(MINIMAP_FONT_WEIGHT),
20750            font_family: Some(MINIMAP_FONT_FAMILY),
20751            ..Default::default()
20752        });
20753        minimap.update_minimap_configuration(minimap_settings, cx);
20754        cx.new(|_| minimap)
20755    }
20756
20757    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20758        let current_line_highlight = minimap_settings
20759            .current_line_highlight
20760            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20761        self.set_current_line_highlight(Some(current_line_highlight));
20762    }
20763
20764    pub fn minimap(&self) -> Option<&Entity<Self>> {
20765        self.minimap
20766            .as_ref()
20767            .filter(|_| self.minimap_visibility.visible())
20768    }
20769
20770    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20771        let mut wrap_guides = smallvec![];
20772
20773        if self.show_wrap_guides == Some(false) {
20774            return wrap_guides;
20775        }
20776
20777        let settings = self.buffer.read(cx).language_settings(cx);
20778        if settings.show_wrap_guides {
20779            match self.soft_wrap_mode(cx) {
20780                SoftWrap::Column(soft_wrap) => {
20781                    wrap_guides.push((soft_wrap as usize, true));
20782                }
20783                SoftWrap::Bounded(soft_wrap) => {
20784                    wrap_guides.push((soft_wrap as usize, true));
20785                }
20786                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20787            }
20788            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20789        }
20790
20791        wrap_guides
20792    }
20793
20794    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20795        let settings = self.buffer.read(cx).language_settings(cx);
20796        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20797        match mode {
20798            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20799                SoftWrap::None
20800            }
20801            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20802            language_settings::SoftWrap::PreferredLineLength => {
20803                SoftWrap::Column(settings.preferred_line_length)
20804            }
20805            language_settings::SoftWrap::Bounded => {
20806                SoftWrap::Bounded(settings.preferred_line_length)
20807            }
20808        }
20809    }
20810
20811    pub fn set_soft_wrap_mode(
20812        &mut self,
20813        mode: language_settings::SoftWrap,
20814        cx: &mut Context<Self>,
20815    ) {
20816        self.soft_wrap_mode_override = Some(mode);
20817        cx.notify();
20818    }
20819
20820    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20821        self.hard_wrap = hard_wrap;
20822        cx.notify();
20823    }
20824
20825    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20826        self.text_style_refinement = Some(style);
20827    }
20828
20829    /// called by the Element so we know what style we were most recently rendered with.
20830    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20831        // We intentionally do not inform the display map about the minimap style
20832        // so that wrapping is not recalculated and stays consistent for the editor
20833        // and its linked minimap.
20834        if !self.mode.is_minimap() {
20835            let font = style.text.font();
20836            let font_size = style.text.font_size.to_pixels(window.rem_size());
20837            let display_map = self
20838                .placeholder_display_map
20839                .as_ref()
20840                .filter(|_| self.is_empty(cx))
20841                .unwrap_or(&self.display_map);
20842
20843            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20844        }
20845        self.style = Some(style);
20846    }
20847
20848    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20849        if self.style.is_none() {
20850            self.style = Some(self.create_style(cx));
20851        }
20852        self.style.as_ref().unwrap()
20853    }
20854
20855    // Called by the element. This method is not designed to be called outside of the editor
20856    // element's layout code because it does not notify when rewrapping is computed synchronously.
20857    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20858        if self.is_empty(cx) {
20859            self.placeholder_display_map
20860                .as_ref()
20861                .map_or(false, |display_map| {
20862                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20863                })
20864        } else {
20865            self.display_map
20866                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20867        }
20868    }
20869
20870    pub fn set_soft_wrap(&mut self) {
20871        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20872    }
20873
20874    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20875        if self.soft_wrap_mode_override.is_some() {
20876            self.soft_wrap_mode_override.take();
20877        } else {
20878            let soft_wrap = match self.soft_wrap_mode(cx) {
20879                SoftWrap::GitDiff => return,
20880                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20881                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20882                    language_settings::SoftWrap::None
20883                }
20884            };
20885            self.soft_wrap_mode_override = Some(soft_wrap);
20886        }
20887        cx.notify();
20888    }
20889
20890    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20891        let Some(workspace) = self.workspace() else {
20892            return;
20893        };
20894        let fs = workspace.read(cx).app_state().fs.clone();
20895        let current_show = TabBarSettings::get_global(cx).show;
20896        update_settings_file(fs, cx, move |setting, _| {
20897            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20898        });
20899    }
20900
20901    pub fn toggle_indent_guides(
20902        &mut self,
20903        _: &ToggleIndentGuides,
20904        _: &mut Window,
20905        cx: &mut Context<Self>,
20906    ) {
20907        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20908            self.buffer
20909                .read(cx)
20910                .language_settings(cx)
20911                .indent_guides
20912                .enabled
20913        });
20914        self.show_indent_guides = Some(!currently_enabled);
20915        cx.notify();
20916    }
20917
20918    fn should_show_indent_guides(&self) -> Option<bool> {
20919        self.show_indent_guides
20920    }
20921
20922    pub fn disable_indent_guides_for_buffer(
20923        &mut self,
20924        buffer_id: BufferId,
20925        cx: &mut Context<Self>,
20926    ) {
20927        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20928        cx.notify();
20929    }
20930
20931    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20932        self.buffers_with_disabled_indent_guides
20933            .contains(&buffer_id)
20934    }
20935
20936    pub fn toggle_line_numbers(
20937        &mut self,
20938        _: &ToggleLineNumbers,
20939        _: &mut Window,
20940        cx: &mut Context<Self>,
20941    ) {
20942        let mut editor_settings = EditorSettings::get_global(cx).clone();
20943        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20944        EditorSettings::override_global(editor_settings, cx);
20945    }
20946
20947    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20948        if let Some(show_line_numbers) = self.show_line_numbers {
20949            return show_line_numbers;
20950        }
20951        EditorSettings::get_global(cx).gutter.line_numbers
20952    }
20953
20954    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20955        match (
20956            self.use_relative_line_numbers,
20957            EditorSettings::get_global(cx).relative_line_numbers,
20958        ) {
20959            (None, setting) => setting,
20960            (Some(false), _) => RelativeLineNumbers::Disabled,
20961            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20962            (Some(true), _) => RelativeLineNumbers::Enabled,
20963        }
20964    }
20965
20966    pub fn toggle_relative_line_numbers(
20967        &mut self,
20968        _: &ToggleRelativeLineNumbers,
20969        _: &mut Window,
20970        cx: &mut Context<Self>,
20971    ) {
20972        let is_relative = self.relative_line_numbers(cx);
20973        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20974    }
20975
20976    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20977        self.use_relative_line_numbers = is_relative;
20978        cx.notify();
20979    }
20980
20981    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20982        self.show_gutter = show_gutter;
20983        cx.notify();
20984    }
20985
20986    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20987        self.show_scrollbars = ScrollbarAxes {
20988            horizontal: show,
20989            vertical: show,
20990        };
20991        cx.notify();
20992    }
20993
20994    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20995        self.show_scrollbars.vertical = show;
20996        cx.notify();
20997    }
20998
20999    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21000        self.show_scrollbars.horizontal = show;
21001        cx.notify();
21002    }
21003
21004    pub fn set_minimap_visibility(
21005        &mut self,
21006        minimap_visibility: MinimapVisibility,
21007        window: &mut Window,
21008        cx: &mut Context<Self>,
21009    ) {
21010        if self.minimap_visibility != minimap_visibility {
21011            if minimap_visibility.visible() && self.minimap.is_none() {
21012                let minimap_settings = EditorSettings::get_global(cx).minimap;
21013                self.minimap =
21014                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21015            }
21016            self.minimap_visibility = minimap_visibility;
21017            cx.notify();
21018        }
21019    }
21020
21021    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21022        self.set_show_scrollbars(false, cx);
21023        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21024    }
21025
21026    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21027        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21028    }
21029
21030    /// Normally the text in full mode and auto height editors is padded on the
21031    /// left side by roughly half a character width for improved hit testing.
21032    ///
21033    /// Use this method to disable this for cases where this is not wanted (e.g.
21034    /// if you want to align the editor text with some other text above or below)
21035    /// or if you want to add this padding to single-line editors.
21036    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21037        self.offset_content = offset_content;
21038        cx.notify();
21039    }
21040
21041    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21042        self.show_line_numbers = Some(show_line_numbers);
21043        cx.notify();
21044    }
21045
21046    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21047        self.disable_expand_excerpt_buttons = true;
21048        cx.notify();
21049    }
21050
21051    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21052        self.delegate_expand_excerpts = delegate;
21053    }
21054
21055    pub fn set_scroll_companion(&mut self, companion: Option<WeakEntity<Editor>>) {
21056        self.scroll_companion = companion;
21057    }
21058
21059    pub fn scroll_companion(&self) -> Option<&WeakEntity<Editor>> {
21060        self.scroll_companion.as_ref()
21061    }
21062
21063    pub fn set_on_local_selections_changed(
21064        &mut self,
21065        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21066    ) {
21067        self.on_local_selections_changed = callback;
21068    }
21069
21070    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21071        self.suppress_selection_callback = suppress;
21072    }
21073
21074    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21075        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21076        cx.notify();
21077    }
21078
21079    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21080        self.show_code_actions = Some(show_code_actions);
21081        cx.notify();
21082    }
21083
21084    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21085        self.show_runnables = Some(show_runnables);
21086        cx.notify();
21087    }
21088
21089    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21090        self.show_breakpoints = Some(show_breakpoints);
21091        cx.notify();
21092    }
21093
21094    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21095        self.show_diff_review_button = show;
21096        cx.notify();
21097    }
21098
21099    pub fn show_diff_review_button(&self) -> bool {
21100        self.show_diff_review_button
21101    }
21102
21103    pub fn render_diff_review_button(
21104        &self,
21105        display_row: DisplayRow,
21106        width: Pixels,
21107        cx: &mut Context<Self>,
21108    ) -> impl IntoElement {
21109        let text_color = cx.theme().colors().text;
21110        let icon_color = cx.theme().colors().icon_accent;
21111
21112        h_flex()
21113            .id("diff_review_button")
21114            .cursor_pointer()
21115            .w(width - px(1.))
21116            .h(relative(0.9))
21117            .justify_center()
21118            .rounded_sm()
21119            .border_1()
21120            .border_color(text_color.opacity(0.1))
21121            .bg(text_color.opacity(0.15))
21122            .hover(|s| {
21123                s.bg(icon_color.opacity(0.4))
21124                    .border_color(icon_color.opacity(0.5))
21125            })
21126            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21127            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21128            .on_mouse_down(
21129                gpui::MouseButton::Left,
21130                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21131                    editor.start_diff_review_drag(display_row, window, cx);
21132                }),
21133            )
21134    }
21135
21136    pub fn start_diff_review_drag(
21137        &mut self,
21138        display_row: DisplayRow,
21139        window: &mut Window,
21140        cx: &mut Context<Self>,
21141    ) {
21142        let snapshot = self.snapshot(window, cx);
21143        let point = snapshot
21144            .display_snapshot
21145            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21146        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21147        self.diff_review_drag_state = Some(DiffReviewDragState {
21148            start_anchor: anchor,
21149            current_anchor: anchor,
21150        });
21151        cx.notify();
21152    }
21153
21154    pub fn update_diff_review_drag(
21155        &mut self,
21156        display_row: DisplayRow,
21157        window: &mut Window,
21158        cx: &mut Context<Self>,
21159    ) {
21160        if self.diff_review_drag_state.is_none() {
21161            return;
21162        }
21163        let snapshot = self.snapshot(window, cx);
21164        let point = snapshot
21165            .display_snapshot
21166            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21167        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21168        if let Some(drag_state) = &mut self.diff_review_drag_state {
21169            drag_state.current_anchor = anchor;
21170            cx.notify();
21171        }
21172    }
21173
21174    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21175        if let Some(drag_state) = self.diff_review_drag_state.take() {
21176            let snapshot = self.snapshot(window, cx);
21177            let range = drag_state.row_range(&snapshot.display_snapshot);
21178            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21179        }
21180        cx.notify();
21181    }
21182
21183    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21184        self.diff_review_drag_state = None;
21185        cx.notify();
21186    }
21187
21188    /// Calculates the appropriate block height for the diff review overlay.
21189    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21190    /// and 2 lines per comment when expanded.
21191    fn calculate_overlay_height(
21192        &self,
21193        hunk_key: &DiffHunkKey,
21194        comments_expanded: bool,
21195        snapshot: &MultiBufferSnapshot,
21196    ) -> u32 {
21197        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21198        let base_height: u32 = 2; // Input row with avatar and buttons
21199
21200        if comment_count == 0 {
21201            base_height
21202        } else if comments_expanded {
21203            // Header (1 line) + 2 lines per comment
21204            base_height + 1 + (comment_count as u32 * 2)
21205        } else {
21206            // Just header when collapsed
21207            base_height + 1
21208        }
21209    }
21210
21211    pub fn show_diff_review_overlay(
21212        &mut self,
21213        display_range: Range<DisplayRow>,
21214        window: &mut Window,
21215        cx: &mut Context<Self>,
21216    ) {
21217        let Range { start, end } = display_range.sorted();
21218
21219        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21220        let editor_snapshot = self.snapshot(window, cx);
21221
21222        // Convert display rows to multibuffer points
21223        let start_point = editor_snapshot
21224            .display_snapshot
21225            .display_point_to_point(start.as_display_point(), Bias::Left);
21226        let end_point = editor_snapshot
21227            .display_snapshot
21228            .display_point_to_point(end.as_display_point(), Bias::Left);
21229        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21230
21231        // Create anchor range for the selected lines (start of first line to end of last line)
21232        let line_end = Point::new(
21233            end_point.row,
21234            buffer_snapshot.line_len(end_multi_buffer_row),
21235        );
21236        let anchor_range =
21237            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21238
21239        // Compute the hunk key for this display row
21240        let file_path = buffer_snapshot
21241            .file_at(start_point)
21242            .map(|file: &Arc<dyn language::File>| file.path().clone())
21243            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21244        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21245        let new_hunk_key = DiffHunkKey {
21246            file_path,
21247            hunk_start_anchor,
21248        };
21249
21250        // Check if we already have an overlay for this hunk
21251        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21252            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21253        }) {
21254            // Just focus the existing overlay's prompt editor
21255            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21256            window.focus(&focus_handle, cx);
21257            return;
21258        }
21259
21260        // Dismiss overlays that have no comments for their hunks
21261        self.dismiss_overlays_without_comments(cx);
21262
21263        // Get the current user's avatar URI from the project's user_store
21264        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21265            let user_store = project.read(cx).user_store();
21266            user_store
21267                .read(cx)
21268                .current_user()
21269                .map(|user| user.avatar_uri.clone())
21270        });
21271
21272        // Create anchor at the end of the last row so the block appears immediately below it
21273        // Use multibuffer coordinates for anchor creation
21274        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21275        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21276
21277        // Use the hunk key we already computed
21278        let hunk_key = new_hunk_key;
21279
21280        // Create the prompt editor for the review input
21281        let prompt_editor = cx.new(|cx| {
21282            let mut editor = Editor::single_line(window, cx);
21283            editor.set_placeholder_text("Add a review comment...", window, cx);
21284            editor
21285        });
21286
21287        // Register the Newline action on the prompt editor to submit the review
21288        let parent_editor = cx.entity().downgrade();
21289        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21290            prompt_editor.register_action({
21291                let parent_editor = parent_editor.clone();
21292                move |_: &crate::actions::Newline, window, cx| {
21293                    if let Some(editor) = parent_editor.upgrade() {
21294                        editor.update(cx, |editor, cx| {
21295                            editor.submit_diff_review_comment(window, cx);
21296                        });
21297                    }
21298                }
21299            })
21300        });
21301
21302        // Calculate initial height based on existing comments for this hunk
21303        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21304
21305        // Create the overlay block
21306        let prompt_editor_for_render = prompt_editor.clone();
21307        let hunk_key_for_render = hunk_key.clone();
21308        let editor_handle = cx.entity().downgrade();
21309        let block = BlockProperties {
21310            style: BlockStyle::Sticky,
21311            placement: BlockPlacement::Below(anchor),
21312            height: Some(initial_height),
21313            render: Arc::new(move |cx| {
21314                Self::render_diff_review_overlay(
21315                    &prompt_editor_for_render,
21316                    &hunk_key_for_render,
21317                    &editor_handle,
21318                    cx,
21319                )
21320            }),
21321            priority: 0,
21322        };
21323
21324        let block_ids = self.insert_blocks([block], None, cx);
21325        let Some(block_id) = block_ids.into_iter().next() else {
21326            log::error!("Failed to insert diff review overlay block");
21327            return;
21328        };
21329
21330        self.diff_review_overlays.push(DiffReviewOverlay {
21331            anchor_range,
21332            block_id,
21333            prompt_editor: prompt_editor.clone(),
21334            hunk_key,
21335            comments_expanded: true,
21336            inline_edit_editors: HashMap::default(),
21337            inline_edit_subscriptions: HashMap::default(),
21338            user_avatar_uri,
21339            _subscription: subscription,
21340        });
21341
21342        // Focus the prompt editor
21343        let focus_handle = prompt_editor.focus_handle(cx);
21344        window.focus(&focus_handle, cx);
21345
21346        cx.notify();
21347    }
21348
21349    /// Dismisses all diff review overlays.
21350    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21351        if self.diff_review_overlays.is_empty() {
21352            return;
21353        }
21354        let block_ids: HashSet<_> = self
21355            .diff_review_overlays
21356            .drain(..)
21357            .map(|overlay| overlay.block_id)
21358            .collect();
21359        self.remove_blocks(block_ids, None, cx);
21360        cx.notify();
21361    }
21362
21363    /// Dismisses overlays that have no comments stored for their hunks.
21364    /// Keeps overlays that have at least one comment.
21365    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21366        let snapshot = self.buffer.read(cx).snapshot(cx);
21367
21368        // First, compute which overlays have comments (to avoid borrow issues with retain)
21369        let overlays_with_comments: Vec<bool> = self
21370            .diff_review_overlays
21371            .iter()
21372            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21373            .collect();
21374
21375        // Now collect block IDs to remove and retain overlays
21376        let mut block_ids_to_remove = HashSet::default();
21377        let mut index = 0;
21378        self.diff_review_overlays.retain(|overlay| {
21379            let has_comments = overlays_with_comments[index];
21380            index += 1;
21381            if !has_comments {
21382                block_ids_to_remove.insert(overlay.block_id);
21383            }
21384            has_comments
21385        });
21386
21387        if !block_ids_to_remove.is_empty() {
21388            self.remove_blocks(block_ids_to_remove, None, cx);
21389            cx.notify();
21390        }
21391    }
21392
21393    /// Refreshes the diff review overlay block to update its height and render function.
21394    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21395    fn refresh_diff_review_overlay_height(
21396        &mut self,
21397        hunk_key: &DiffHunkKey,
21398        _window: &mut Window,
21399        cx: &mut Context<Self>,
21400    ) {
21401        // Extract all needed data from overlay first to avoid borrow conflicts
21402        let snapshot = self.buffer.read(cx).snapshot(cx);
21403        let (comments_expanded, block_id, prompt_editor) = {
21404            let Some(overlay) = self
21405                .diff_review_overlays
21406                .iter()
21407                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21408            else {
21409                return;
21410            };
21411
21412            (
21413                overlay.comments_expanded,
21414                overlay.block_id,
21415                overlay.prompt_editor.clone(),
21416            )
21417        };
21418
21419        // Calculate new height
21420        let snapshot = self.buffer.read(cx).snapshot(cx);
21421        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21422
21423        // Update the block height using resize_blocks (avoids flicker)
21424        let mut heights = HashMap::default();
21425        heights.insert(block_id, new_height);
21426        self.resize_blocks(heights, None, cx);
21427
21428        // Update the render function using replace_blocks (avoids flicker)
21429        let hunk_key_for_render = hunk_key.clone();
21430        let editor_handle = cx.entity().downgrade();
21431        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21432            Arc::new(move |cx| {
21433                Self::render_diff_review_overlay(
21434                    &prompt_editor,
21435                    &hunk_key_for_render,
21436                    &editor_handle,
21437                    cx,
21438                )
21439            });
21440
21441        let mut renderers = HashMap::default();
21442        renderers.insert(block_id, render);
21443        self.replace_blocks(renderers, None, cx);
21444    }
21445
21446    /// Action handler for SubmitDiffReviewComment.
21447    pub fn submit_diff_review_comment_action(
21448        &mut self,
21449        _: &SubmitDiffReviewComment,
21450        window: &mut Window,
21451        cx: &mut Context<Self>,
21452    ) {
21453        self.submit_diff_review_comment(window, cx);
21454    }
21455
21456    /// Stores the diff review comment locally.
21457    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21458    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21459        // Find the overlay that currently has focus
21460        let overlay_index = self
21461            .diff_review_overlays
21462            .iter()
21463            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
21464        let Some(overlay_index) = overlay_index else {
21465            return;
21466        };
21467        let overlay = &self.diff_review_overlays[overlay_index];
21468
21469        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
21470        if comment_text.is_empty() {
21471            return;
21472        }
21473
21474        let anchor_range = overlay.anchor_range.clone();
21475        let hunk_key = overlay.hunk_key.clone();
21476
21477        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
21478
21479        // Clear the prompt editor but keep the overlay open
21480        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
21481            overlay.prompt_editor.update(cx, |editor, cx| {
21482                editor.clear(window, cx);
21483            });
21484        }
21485
21486        // Refresh the overlay to update the block height for the new comment
21487        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21488
21489        cx.notify();
21490    }
21491
21492    /// Returns the prompt editor for the diff review overlay, if one is active.
21493    /// This is primarily used for testing.
21494    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
21495        self.diff_review_overlays
21496            .first()
21497            .map(|overlay| &overlay.prompt_editor)
21498    }
21499
21500    /// Returns the line range for the first diff review overlay, if one is active.
21501    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
21502    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
21503        let overlay = self.diff_review_overlays.first()?;
21504        let snapshot = self.buffer.read(cx).snapshot(cx);
21505        let start_point = overlay.anchor_range.start.to_point(&snapshot);
21506        let end_point = overlay.anchor_range.end.to_point(&snapshot);
21507        let start_row = snapshot
21508            .point_to_buffer_point(start_point)
21509            .map(|(_, p, _)| p.row)
21510            .unwrap_or(start_point.row);
21511        let end_row = snapshot
21512            .point_to_buffer_point(end_point)
21513            .map(|(_, p, _)| p.row)
21514            .unwrap_or(end_point.row);
21515        Some((start_row, end_row))
21516    }
21517
21518    /// Sets whether the comments section is expanded in the diff review overlay.
21519    /// This is primarily used for testing.
21520    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
21521        for overlay in &mut self.diff_review_overlays {
21522            overlay.comments_expanded = expanded;
21523        }
21524        cx.notify();
21525    }
21526
21527    /// Compares two DiffHunkKeys for equality by resolving their anchors.
21528    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
21529        a.file_path == b.file_path
21530            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
21531    }
21532
21533    /// Returns comments for a specific hunk, ordered by creation time.
21534    pub fn comments_for_hunk<'a>(
21535        &'a self,
21536        key: &DiffHunkKey,
21537        snapshot: &MultiBufferSnapshot,
21538    ) -> &'a [StoredReviewComment] {
21539        let key_point = key.hunk_start_anchor.to_point(snapshot);
21540        self.stored_review_comments
21541            .iter()
21542            .find(|(k, _)| {
21543                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21544            })
21545            .map(|(_, comments)| comments.as_slice())
21546            .unwrap_or(&[])
21547    }
21548
21549    /// Returns the total count of stored review comments across all hunks.
21550    pub fn total_review_comment_count(&self) -> usize {
21551        self.stored_review_comments
21552            .iter()
21553            .map(|(_, v)| v.len())
21554            .sum()
21555    }
21556
21557    /// Returns the count of comments for a specific hunk.
21558    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
21559        let key_point = key.hunk_start_anchor.to_point(snapshot);
21560        self.stored_review_comments
21561            .iter()
21562            .find(|(k, _)| {
21563                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21564            })
21565            .map(|(_, v)| v.len())
21566            .unwrap_or(0)
21567    }
21568
21569    /// Adds a new review comment to a specific hunk.
21570    pub fn add_review_comment(
21571        &mut self,
21572        hunk_key: DiffHunkKey,
21573        comment: String,
21574        anchor_range: Range<Anchor>,
21575        cx: &mut Context<Self>,
21576    ) -> usize {
21577        let id = self.next_review_comment_id;
21578        self.next_review_comment_id += 1;
21579
21580        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
21581
21582        let snapshot = self.buffer.read(cx).snapshot(cx);
21583        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
21584
21585        // Find existing entry for this hunk or add a new one
21586        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
21587            k.file_path == hunk_key.file_path
21588                && k.hunk_start_anchor.to_point(&snapshot) == key_point
21589        }) {
21590            comments.push(stored_comment);
21591        } else {
21592            self.stored_review_comments
21593                .push((hunk_key, vec![stored_comment]));
21594        }
21595
21596        cx.emit(EditorEvent::ReviewCommentsChanged {
21597            total_count: self.total_review_comment_count(),
21598        });
21599        cx.notify();
21600        id
21601    }
21602
21603    /// Removes a review comment by ID from any hunk.
21604    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
21605        for (_, comments) in self.stored_review_comments.iter_mut() {
21606            if let Some(index) = comments.iter().position(|c| c.id == id) {
21607                comments.remove(index);
21608                cx.emit(EditorEvent::ReviewCommentsChanged {
21609                    total_count: self.total_review_comment_count(),
21610                });
21611                cx.notify();
21612                return true;
21613            }
21614        }
21615        false
21616    }
21617
21618    /// Updates a review comment's text by ID.
21619    pub fn update_review_comment(
21620        &mut self,
21621        id: usize,
21622        new_comment: String,
21623        cx: &mut Context<Self>,
21624    ) -> bool {
21625        for (_, comments) in self.stored_review_comments.iter_mut() {
21626            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21627                comment.comment = new_comment;
21628                comment.is_editing = false;
21629                cx.emit(EditorEvent::ReviewCommentsChanged {
21630                    total_count: self.total_review_comment_count(),
21631                });
21632                cx.notify();
21633                return true;
21634            }
21635        }
21636        false
21637    }
21638
21639    /// Sets a comment's editing state.
21640    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
21641        for (_, comments) in self.stored_review_comments.iter_mut() {
21642            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21643                comment.is_editing = is_editing;
21644                cx.notify();
21645                return;
21646            }
21647        }
21648    }
21649
21650    /// Takes all stored comments from all hunks, clearing the storage.
21651    /// Returns a Vec of (hunk_key, comments) pairs.
21652    pub fn take_all_review_comments(
21653        &mut self,
21654        cx: &mut Context<Self>,
21655    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
21656        // Dismiss all overlays when taking comments (e.g., when sending to agent)
21657        self.dismiss_all_diff_review_overlays(cx);
21658        let comments = std::mem::take(&mut self.stored_review_comments);
21659        // Reset the ID counter since all comments have been taken
21660        self.next_review_comment_id = 0;
21661        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
21662        cx.notify();
21663        comments
21664    }
21665
21666    /// Removes review comments whose anchors are no longer valid or whose
21667    /// associated diff hunks no longer exist.
21668    ///
21669    /// This should be called when the buffer changes to prevent orphaned comments
21670    /// from accumulating.
21671    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
21672        let snapshot = self.buffer.read(cx).snapshot(cx);
21673        let original_count = self.total_review_comment_count();
21674
21675        // Remove comments with invalid hunk anchors
21676        self.stored_review_comments
21677            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
21678
21679        // Also clean up individual comments with invalid anchor ranges
21680        for (_, comments) in &mut self.stored_review_comments {
21681            comments.retain(|comment| {
21682                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
21683            });
21684        }
21685
21686        // Remove empty hunk entries
21687        self.stored_review_comments
21688            .retain(|(_, comments)| !comments.is_empty());
21689
21690        let new_count = self.total_review_comment_count();
21691        if new_count != original_count {
21692            cx.emit(EditorEvent::ReviewCommentsChanged {
21693                total_count: new_count,
21694            });
21695            cx.notify();
21696        }
21697    }
21698
21699    /// Toggles the expanded state of the comments section in the overlay.
21700    pub fn toggle_review_comments_expanded(
21701        &mut self,
21702        _: &ToggleReviewCommentsExpanded,
21703        window: &mut Window,
21704        cx: &mut Context<Self>,
21705    ) {
21706        // Find the overlay that currently has focus, or use the first one
21707        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
21708            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
21709                overlay.comments_expanded = !overlay.comments_expanded;
21710                Some(overlay.hunk_key.clone())
21711            } else {
21712                None
21713            }
21714        });
21715
21716        // If no focused overlay found, toggle the first one
21717        let hunk_key = overlay_info.or_else(|| {
21718            self.diff_review_overlays.first_mut().map(|overlay| {
21719                overlay.comments_expanded = !overlay.comments_expanded;
21720                overlay.hunk_key.clone()
21721            })
21722        });
21723
21724        if let Some(hunk_key) = hunk_key {
21725            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21726            cx.notify();
21727        }
21728    }
21729
21730    /// Handles the EditReviewComment action - sets a comment into editing mode.
21731    pub fn edit_review_comment(
21732        &mut self,
21733        action: &EditReviewComment,
21734        window: &mut Window,
21735        cx: &mut Context<Self>,
21736    ) {
21737        let comment_id = action.id;
21738
21739        // Set the comment to editing mode
21740        self.set_comment_editing(comment_id, true, cx);
21741
21742        // Find the overlay that contains this comment and create an inline editor if needed
21743        // First, find which hunk this comment belongs to
21744        let hunk_key = self
21745            .stored_review_comments
21746            .iter()
21747            .find_map(|(key, comments)| {
21748                if comments.iter().any(|c| c.id == comment_id) {
21749                    Some(key.clone())
21750                } else {
21751                    None
21752                }
21753            });
21754
21755        let snapshot = self.buffer.read(cx).snapshot(cx);
21756        if let Some(hunk_key) = hunk_key {
21757            if let Some(overlay) = self
21758                .diff_review_overlays
21759                .iter_mut()
21760                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21761            {
21762                if let std::collections::hash_map::Entry::Vacant(entry) =
21763                    overlay.inline_edit_editors.entry(comment_id)
21764                {
21765                    // Find the comment text
21766                    let comment_text = self
21767                        .stored_review_comments
21768                        .iter()
21769                        .flat_map(|(_, comments)| comments)
21770                        .find(|c| c.id == comment_id)
21771                        .map(|c| c.comment.clone())
21772                        .unwrap_or_default();
21773
21774                    // Create inline editor
21775                    let parent_editor = cx.entity().downgrade();
21776                    let inline_editor = cx.new(|cx| {
21777                        let mut editor = Editor::single_line(window, cx);
21778                        editor.set_text(&*comment_text, window, cx);
21779                        // Select all text for easy replacement
21780                        editor.select_all(&crate::actions::SelectAll, window, cx);
21781                        editor
21782                    });
21783
21784                    // Register the Newline action to confirm the edit
21785                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
21786                        inline_editor.register_action({
21787                            let parent_editor = parent_editor.clone();
21788                            move |_: &crate::actions::Newline, window, cx| {
21789                                if let Some(editor) = parent_editor.upgrade() {
21790                                    editor.update(cx, |editor, cx| {
21791                                        editor.confirm_edit_review_comment(comment_id, window, cx);
21792                                    });
21793                                }
21794                            }
21795                        })
21796                    });
21797
21798                    // Store the subscription to keep the action handler alive
21799                    overlay
21800                        .inline_edit_subscriptions
21801                        .insert(comment_id, subscription);
21802
21803                    // Focus the inline editor
21804                    let focus_handle = inline_editor.focus_handle(cx);
21805                    window.focus(&focus_handle, cx);
21806
21807                    entry.insert(inline_editor);
21808                }
21809            }
21810        }
21811
21812        cx.notify();
21813    }
21814
21815    /// Confirms an inline edit of a review comment.
21816    pub fn confirm_edit_review_comment(
21817        &mut self,
21818        comment_id: usize,
21819        _window: &mut Window,
21820        cx: &mut Context<Self>,
21821    ) {
21822        // Get the new text from the inline editor
21823        // Find the overlay containing this comment's inline editor
21824        let snapshot = self.buffer.read(cx).snapshot(cx);
21825        let hunk_key = self
21826            .stored_review_comments
21827            .iter()
21828            .find_map(|(key, comments)| {
21829                if comments.iter().any(|c| c.id == comment_id) {
21830                    Some(key.clone())
21831                } else {
21832                    None
21833                }
21834            });
21835
21836        let new_text = hunk_key
21837            .as_ref()
21838            .and_then(|hunk_key| {
21839                self.diff_review_overlays
21840                    .iter()
21841                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21842            })
21843            .as_ref()
21844            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
21845            .map(|editor| editor.read(cx).text(cx).trim().to_string());
21846
21847        if let Some(new_text) = new_text {
21848            if !new_text.is_empty() {
21849                self.update_review_comment(comment_id, new_text, cx);
21850            }
21851        }
21852
21853        // Remove the inline editor and its subscription
21854        if let Some(hunk_key) = hunk_key {
21855            if let Some(overlay) = self
21856                .diff_review_overlays
21857                .iter_mut()
21858                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21859            {
21860                overlay.inline_edit_editors.remove(&comment_id);
21861                overlay.inline_edit_subscriptions.remove(&comment_id);
21862            }
21863        }
21864
21865        // Clear editing state
21866        self.set_comment_editing(comment_id, false, cx);
21867    }
21868
21869    /// Cancels an inline edit of a review comment.
21870    pub fn cancel_edit_review_comment(
21871        &mut self,
21872        comment_id: usize,
21873        _window: &mut Window,
21874        cx: &mut Context<Self>,
21875    ) {
21876        // Find which hunk this comment belongs to
21877        let hunk_key = self
21878            .stored_review_comments
21879            .iter()
21880            .find_map(|(key, comments)| {
21881                if comments.iter().any(|c| c.id == comment_id) {
21882                    Some(key.clone())
21883                } else {
21884                    None
21885                }
21886            });
21887
21888        // Remove the inline editor and its subscription
21889        if let Some(hunk_key) = hunk_key {
21890            let snapshot = self.buffer.read(cx).snapshot(cx);
21891            if let Some(overlay) = self
21892                .diff_review_overlays
21893                .iter_mut()
21894                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21895            {
21896                overlay.inline_edit_editors.remove(&comment_id);
21897                overlay.inline_edit_subscriptions.remove(&comment_id);
21898            }
21899        }
21900
21901        // Clear editing state
21902        self.set_comment_editing(comment_id, false, cx);
21903    }
21904
21905    /// Action handler for ConfirmEditReviewComment.
21906    pub fn confirm_edit_review_comment_action(
21907        &mut self,
21908        action: &ConfirmEditReviewComment,
21909        window: &mut Window,
21910        cx: &mut Context<Self>,
21911    ) {
21912        self.confirm_edit_review_comment(action.id, window, cx);
21913    }
21914
21915    /// Action handler for CancelEditReviewComment.
21916    pub fn cancel_edit_review_comment_action(
21917        &mut self,
21918        action: &CancelEditReviewComment,
21919        window: &mut Window,
21920        cx: &mut Context<Self>,
21921    ) {
21922        self.cancel_edit_review_comment(action.id, window, cx);
21923    }
21924
21925    /// Handles the DeleteReviewComment action - removes a comment.
21926    pub fn delete_review_comment(
21927        &mut self,
21928        action: &DeleteReviewComment,
21929        window: &mut Window,
21930        cx: &mut Context<Self>,
21931    ) {
21932        // Get the hunk key before removing the comment
21933        // Find the hunk key from the comment itself
21934        let comment_id = action.id;
21935        let hunk_key = self
21936            .stored_review_comments
21937            .iter()
21938            .find_map(|(key, comments)| {
21939                if comments.iter().any(|c| c.id == comment_id) {
21940                    Some(key.clone())
21941                } else {
21942                    None
21943                }
21944            });
21945
21946        // Also get it from the overlay for refresh purposes
21947        let overlay_hunk_key = self
21948            .diff_review_overlays
21949            .first()
21950            .map(|o| o.hunk_key.clone());
21951
21952        self.remove_review_comment(action.id, cx);
21953
21954        // Refresh the overlay height after removing a comment
21955        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
21956            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21957        }
21958    }
21959
21960    fn render_diff_review_overlay(
21961        prompt_editor: &Entity<Editor>,
21962        hunk_key: &DiffHunkKey,
21963        editor_handle: &WeakEntity<Editor>,
21964        cx: &mut BlockContext,
21965    ) -> AnyElement {
21966        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
21967            if ranges.is_empty() {
21968                return None;
21969            }
21970            let formatted: Vec<String> = ranges
21971                .iter()
21972                .map(|(start, end)| {
21973                    let start_line = start + 1;
21974                    let end_line = end + 1;
21975                    if start_line == end_line {
21976                        format!("Line {start_line}")
21977                    } else {
21978                        format!("Lines {start_line}-{end_line}")
21979                    }
21980                })
21981                .collect();
21982            // Don't show label for single line in single excerpt
21983            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
21984                return None;
21985            }
21986            Some(formatted.join(""))
21987        }
21988
21989        let theme = cx.theme();
21990        let colors = theme.colors();
21991
21992        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
21993            editor_handle
21994                .upgrade()
21995                .map(|editor| {
21996                    let editor = editor.read(cx);
21997                    let snapshot = editor.buffer().read(cx).snapshot(cx);
21998                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
21999                    let (expanded, editors, avatar_uri, line_ranges) = editor
22000                        .diff_review_overlays
22001                        .iter()
22002                        .find(|overlay| {
22003                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22004                        })
22005                        .map(|o| {
22006                            let start_point = o.anchor_range.start.to_point(&snapshot);
22007                            let end_point = o.anchor_range.end.to_point(&snapshot);
22008                            // Get line ranges per excerpt to detect discontinuities
22009                            let buffer_ranges =
22010                                snapshot.range_to_buffer_ranges(start_point..end_point);
22011                            let ranges: Vec<(u32, u32)> = buffer_ranges
22012                                .iter()
22013                                .map(|(buffer, range, _)| {
22014                                    let start = buffer.offset_to_point(range.start.0).row;
22015                                    let end = buffer.offset_to_point(range.end.0).row;
22016                                    (start, end)
22017                                })
22018                                .collect();
22019                            (
22020                                o.comments_expanded,
22021                                o.inline_edit_editors.clone(),
22022                                o.user_avatar_uri.clone(),
22023                                if ranges.is_empty() {
22024                                    None
22025                                } else {
22026                                    Some(ranges)
22027                                },
22028                            )
22029                        })
22030                        .unwrap_or((true, HashMap::default(), None, None));
22031                    (comments, expanded, editors, avatar_uri, line_ranges)
22032                })
22033                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22034
22035        let comment_count = comments.len();
22036        let avatar_size = px(20.);
22037        let action_icon_size = IconSize::XSmall;
22038
22039        v_flex()
22040            .w_full()
22041            .bg(colors.editor_background)
22042            .border_b_1()
22043            .border_color(colors.border)
22044            .px_2()
22045            .pb_2()
22046            .gap_2()
22047            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22048            .when_some(line_ranges, |el, ranges| {
22049                let label = format_line_ranges(&ranges);
22050                if let Some(label) = label {
22051                    el.child(
22052                        h_flex()
22053                            .w_full()
22054                            .px_2()
22055                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22056                    )
22057                } else {
22058                    el
22059                }
22060            })
22061            // Top row: editable input with user's avatar
22062            .child(
22063                h_flex()
22064                    .w_full()
22065                    .items_center()
22066                    .gap_2()
22067                    .px_2()
22068                    .py_1p5()
22069                    .rounded_md()
22070                    .bg(colors.surface_background)
22071                    .child(
22072                        div()
22073                            .size(avatar_size)
22074                            .flex_shrink_0()
22075                            .rounded_full()
22076                            .overflow_hidden()
22077                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22078                                Avatar::new(avatar_uri.clone())
22079                                    .size(avatar_size)
22080                                    .into_any_element()
22081                            } else {
22082                                Icon::new(IconName::Person)
22083                                    .size(IconSize::Small)
22084                                    .color(ui::Color::Muted)
22085                                    .into_any_element()
22086                            }),
22087                    )
22088                    .child(
22089                        div()
22090                            .flex_1()
22091                            .border_1()
22092                            .border_color(colors.border)
22093                            .rounded_md()
22094                            .bg(colors.editor_background)
22095                            .px_2()
22096                            .py_1()
22097                            .child(prompt_editor.clone()),
22098                    )
22099                    .child(
22100                        h_flex()
22101                            .flex_shrink_0()
22102                            .gap_1()
22103                            .child(
22104                                IconButton::new("diff-review-close", IconName::Close)
22105                                    .icon_color(ui::Color::Muted)
22106                                    .icon_size(action_icon_size)
22107                                    .tooltip(Tooltip::text("Close"))
22108                                    .on_click(|_, window, cx| {
22109                                        window
22110                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22111                                    }),
22112                            )
22113                            .child(
22114                                IconButton::new("diff-review-add", IconName::Return)
22115                                    .icon_color(ui::Color::Muted)
22116                                    .icon_size(action_icon_size)
22117                                    .tooltip(Tooltip::text("Add comment"))
22118                                    .on_click(|_, window, cx| {
22119                                        window.dispatch_action(
22120                                            Box::new(crate::actions::SubmitDiffReviewComment),
22121                                            cx,
22122                                        );
22123                                    }),
22124                            ),
22125                    ),
22126            )
22127            // Expandable comments section (only shown when there are comments)
22128            .when(comment_count > 0, |el| {
22129                el.child(Self::render_comments_section(
22130                    comments,
22131                    comments_expanded,
22132                    inline_editors,
22133                    user_avatar_uri,
22134                    avatar_size,
22135                    action_icon_size,
22136                    colors,
22137                ))
22138            })
22139            .into_any_element()
22140    }
22141
22142    fn render_comments_section(
22143        comments: Vec<StoredReviewComment>,
22144        expanded: bool,
22145        inline_editors: HashMap<usize, Entity<Editor>>,
22146        user_avatar_uri: Option<SharedUri>,
22147        avatar_size: Pixels,
22148        action_icon_size: IconSize,
22149        colors: &theme::ThemeColors,
22150    ) -> impl IntoElement {
22151        let comment_count = comments.len();
22152
22153        v_flex()
22154            .w_full()
22155            .gap_1()
22156            // Header with expand/collapse toggle
22157            .child(
22158                h_flex()
22159                    .id("review-comments-header")
22160                    .w_full()
22161                    .items_center()
22162                    .gap_1()
22163                    .px_2()
22164                    .py_1()
22165                    .cursor_pointer()
22166                    .rounded_md()
22167                    .hover(|style| style.bg(colors.ghost_element_hover))
22168                    .on_click(|_, window: &mut Window, cx| {
22169                        window.dispatch_action(
22170                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22171                            cx,
22172                        );
22173                    })
22174                    .child(
22175                        Icon::new(if expanded {
22176                            IconName::ChevronDown
22177                        } else {
22178                            IconName::ChevronRight
22179                        })
22180                        .size(IconSize::Small)
22181                        .color(ui::Color::Muted),
22182                    )
22183                    .child(
22184                        Label::new(format!(
22185                            "{} Comment{}",
22186                            comment_count,
22187                            if comment_count == 1 { "" } else { "s" }
22188                        ))
22189                        .size(LabelSize::Small)
22190                        .color(Color::Muted),
22191                    ),
22192            )
22193            // Comments list (when expanded)
22194            .when(expanded, |el| {
22195                el.children(comments.into_iter().map(|comment| {
22196                    let inline_editor = inline_editors.get(&comment.id).cloned();
22197                    Self::render_comment_row(
22198                        comment,
22199                        inline_editor,
22200                        user_avatar_uri.clone(),
22201                        avatar_size,
22202                        action_icon_size,
22203                        colors,
22204                    )
22205                }))
22206            })
22207    }
22208
22209    fn render_comment_row(
22210        comment: StoredReviewComment,
22211        inline_editor: Option<Entity<Editor>>,
22212        user_avatar_uri: Option<SharedUri>,
22213        avatar_size: Pixels,
22214        action_icon_size: IconSize,
22215        colors: &theme::ThemeColors,
22216    ) -> impl IntoElement {
22217        let comment_id = comment.id;
22218        let is_editing = inline_editor.is_some();
22219
22220        h_flex()
22221            .w_full()
22222            .items_center()
22223            .gap_2()
22224            .px_2()
22225            .py_1p5()
22226            .rounded_md()
22227            .bg(colors.surface_background)
22228            .child(
22229                div()
22230                    .size(avatar_size)
22231                    .flex_shrink_0()
22232                    .rounded_full()
22233                    .overflow_hidden()
22234                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22235                        Avatar::new(avatar_uri.clone())
22236                            .size(avatar_size)
22237                            .into_any_element()
22238                    } else {
22239                        Icon::new(IconName::Person)
22240                            .size(IconSize::Small)
22241                            .color(ui::Color::Muted)
22242                            .into_any_element()
22243                    }),
22244            )
22245            .child(if let Some(editor) = inline_editor {
22246                // Inline edit mode: show an editable text field
22247                div()
22248                    .flex_1()
22249                    .border_1()
22250                    .border_color(colors.border)
22251                    .rounded_md()
22252                    .bg(colors.editor_background)
22253                    .px_2()
22254                    .py_1()
22255                    .child(editor)
22256                    .into_any_element()
22257            } else {
22258                // Display mode: show the comment text
22259                div()
22260                    .flex_1()
22261                    .text_sm()
22262                    .text_color(colors.text)
22263                    .child(comment.comment)
22264                    .into_any_element()
22265            })
22266            .child(if is_editing {
22267                // Editing mode: show close and confirm buttons
22268                h_flex()
22269                    .gap_1()
22270                    .child(
22271                        IconButton::new(
22272                            format!("diff-review-cancel-edit-{comment_id}"),
22273                            IconName::Close,
22274                        )
22275                        .icon_color(ui::Color::Muted)
22276                        .icon_size(action_icon_size)
22277                        .tooltip(Tooltip::text("Cancel"))
22278                        .on_click(move |_, window, cx| {
22279                            window.dispatch_action(
22280                                Box::new(crate::actions::CancelEditReviewComment {
22281                                    id: comment_id,
22282                                }),
22283                                cx,
22284                            );
22285                        }),
22286                    )
22287                    .child(
22288                        IconButton::new(
22289                            format!("diff-review-confirm-edit-{comment_id}"),
22290                            IconName::Return,
22291                        )
22292                        .icon_color(ui::Color::Muted)
22293                        .icon_size(action_icon_size)
22294                        .tooltip(Tooltip::text("Confirm"))
22295                        .on_click(move |_, window, cx| {
22296                            window.dispatch_action(
22297                                Box::new(crate::actions::ConfirmEditReviewComment {
22298                                    id: comment_id,
22299                                }),
22300                                cx,
22301                            );
22302                        }),
22303                    )
22304                    .into_any_element()
22305            } else {
22306                // Display mode: no action buttons for now (edit/delete not yet implemented)
22307                gpui::Empty.into_any_element()
22308            })
22309    }
22310
22311    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22312        if self.display_map.read(cx).masked != masked {
22313            self.display_map.update(cx, |map, _| map.masked = masked);
22314        }
22315        cx.notify()
22316    }
22317
22318    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22319        self.show_wrap_guides = Some(show_wrap_guides);
22320        cx.notify();
22321    }
22322
22323    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22324        self.show_indent_guides = Some(show_indent_guides);
22325        cx.notify();
22326    }
22327
22328    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22329        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22330            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22331                && let Some(dir) = file.abs_path(cx).parent()
22332            {
22333                return Some(dir.to_owned());
22334            }
22335        }
22336
22337        None
22338    }
22339
22340    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22341        self.active_excerpt(cx)?
22342            .1
22343            .read(cx)
22344            .file()
22345            .and_then(|f| f.as_local())
22346    }
22347
22348    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22349        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22350            let buffer = buffer.read(cx);
22351            if let Some(project_path) = buffer.project_path(cx) {
22352                let project = self.project()?.read(cx);
22353                project.absolute_path(&project_path, cx)
22354            } else {
22355                buffer
22356                    .file()
22357                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22358            }
22359        })
22360    }
22361
22362    pub fn reveal_in_finder(
22363        &mut self,
22364        _: &RevealInFileManager,
22365        _window: &mut Window,
22366        cx: &mut Context<Self>,
22367    ) {
22368        if let Some(path) = self.target_file_abs_path(cx) {
22369            if let Some(project) = self.project() {
22370                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22371            } else {
22372                cx.reveal_path(&path);
22373            }
22374        }
22375    }
22376
22377    pub fn copy_path(
22378        &mut self,
22379        _: &zed_actions::workspace::CopyPath,
22380        _window: &mut Window,
22381        cx: &mut Context<Self>,
22382    ) {
22383        if let Some(path) = self.target_file_abs_path(cx)
22384            && let Some(path) = path.to_str()
22385        {
22386            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22387        } else {
22388            cx.propagate();
22389        }
22390    }
22391
22392    pub fn copy_relative_path(
22393        &mut self,
22394        _: &zed_actions::workspace::CopyRelativePath,
22395        _window: &mut Window,
22396        cx: &mut Context<Self>,
22397    ) {
22398        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22399            let project = self.project()?.read(cx);
22400            let path = buffer.read(cx).file()?.path();
22401            let path = path.display(project.path_style(cx));
22402            Some(path)
22403        }) {
22404            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22405        } else {
22406            cx.propagate();
22407        }
22408    }
22409
22410    /// Returns the project path for the editor's buffer, if any buffer is
22411    /// opened in the editor.
22412    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22413        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22414            buffer.read(cx).project_path(cx)
22415        } else {
22416            None
22417        }
22418    }
22419
22420    // Returns true if the editor handled a go-to-line request
22421    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22422        maybe!({
22423            let breakpoint_store = self.breakpoint_store.as_ref()?;
22424
22425            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
22426            else {
22427                self.clear_row_highlights::<ActiveDebugLine>();
22428                return None;
22429            };
22430
22431            let position = active_stack_frame.position;
22432            let buffer_id = position.buffer_id?;
22433            let snapshot = self
22434                .project
22435                .as_ref()?
22436                .read(cx)
22437                .buffer_for_id(buffer_id, cx)?
22438                .read(cx)
22439                .snapshot();
22440
22441            let mut handled = false;
22442            for (id, ExcerptRange { context, .. }) in
22443                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
22444            {
22445                if context.start.cmp(&position, &snapshot).is_ge()
22446                    || context.end.cmp(&position, &snapshot).is_lt()
22447                {
22448                    continue;
22449                }
22450                let snapshot = self.buffer.read(cx).snapshot(cx);
22451                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
22452
22453                handled = true;
22454                self.clear_row_highlights::<ActiveDebugLine>();
22455
22456                self.go_to_line::<ActiveDebugLine>(
22457                    multibuffer_anchor,
22458                    Some(cx.theme().colors().editor_debugger_active_line_background),
22459                    window,
22460                    cx,
22461                );
22462
22463                cx.notify();
22464            }
22465
22466            handled.then_some(())
22467        })
22468        .is_some()
22469    }
22470
22471    pub fn copy_file_name_without_extension(
22472        &mut self,
22473        _: &CopyFileNameWithoutExtension,
22474        _: &mut Window,
22475        cx: &mut Context<Self>,
22476    ) {
22477        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22478            let file = buffer.read(cx).file()?;
22479            file.path().file_stem()
22480        }) {
22481            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
22482        }
22483    }
22484
22485    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
22486        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22487            let file = buffer.read(cx).file()?;
22488            Some(file.file_name(cx))
22489        }) {
22490            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
22491        }
22492    }
22493
22494    pub fn toggle_git_blame(
22495        &mut self,
22496        _: &::git::Blame,
22497        window: &mut Window,
22498        cx: &mut Context<Self>,
22499    ) {
22500        self.show_git_blame_gutter = !self.show_git_blame_gutter;
22501
22502        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
22503            self.start_git_blame(true, window, cx);
22504        }
22505
22506        cx.notify();
22507    }
22508
22509    pub fn toggle_git_blame_inline(
22510        &mut self,
22511        _: &ToggleGitBlameInline,
22512        window: &mut Window,
22513        cx: &mut Context<Self>,
22514    ) {
22515        self.toggle_git_blame_inline_internal(true, window, cx);
22516        cx.notify();
22517    }
22518
22519    pub fn open_git_blame_commit(
22520        &mut self,
22521        _: &OpenGitBlameCommit,
22522        window: &mut Window,
22523        cx: &mut Context<Self>,
22524    ) {
22525        self.open_git_blame_commit_internal(window, cx);
22526    }
22527
22528    fn open_git_blame_commit_internal(
22529        &mut self,
22530        window: &mut Window,
22531        cx: &mut Context<Self>,
22532    ) -> Option<()> {
22533        let blame = self.blame.as_ref()?;
22534        let snapshot = self.snapshot(window, cx);
22535        let cursor = self
22536            .selections
22537            .newest::<Point>(&snapshot.display_snapshot)
22538            .head();
22539        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
22540        let (_, blame_entry) = blame
22541            .update(cx, |blame, cx| {
22542                blame
22543                    .blame_for_rows(
22544                        &[RowInfo {
22545                            buffer_id: Some(buffer.remote_id()),
22546                            buffer_row: Some(point.row),
22547                            ..Default::default()
22548                        }],
22549                        cx,
22550                    )
22551                    .next()
22552            })
22553            .flatten()?;
22554        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22555        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
22556        let workspace = self.workspace()?.downgrade();
22557        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
22558        None
22559    }
22560
22561    pub fn git_blame_inline_enabled(&self) -> bool {
22562        self.git_blame_inline_enabled
22563    }
22564
22565    pub fn toggle_selection_menu(
22566        &mut self,
22567        _: &ToggleSelectionMenu,
22568        _: &mut Window,
22569        cx: &mut Context<Self>,
22570    ) {
22571        self.show_selection_menu = self
22572            .show_selection_menu
22573            .map(|show_selections_menu| !show_selections_menu)
22574            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
22575
22576        cx.notify();
22577    }
22578
22579    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
22580        self.show_selection_menu
22581            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
22582    }
22583
22584    fn start_git_blame(
22585        &mut self,
22586        user_triggered: bool,
22587        window: &mut Window,
22588        cx: &mut Context<Self>,
22589    ) {
22590        if let Some(project) = self.project() {
22591            if let Some(buffer) = self.buffer().read(cx).as_singleton()
22592                && buffer.read(cx).file().is_none()
22593            {
22594                return;
22595            }
22596
22597            let focused = self.focus_handle(cx).contains_focused(window, cx);
22598
22599            let project = project.clone();
22600            let blame = cx
22601                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
22602            self.blame_subscription =
22603                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
22604            self.blame = Some(blame);
22605        }
22606    }
22607
22608    fn toggle_git_blame_inline_internal(
22609        &mut self,
22610        user_triggered: bool,
22611        window: &mut Window,
22612        cx: &mut Context<Self>,
22613    ) {
22614        if self.git_blame_inline_enabled {
22615            self.git_blame_inline_enabled = false;
22616            self.show_git_blame_inline = false;
22617            self.show_git_blame_inline_delay_task.take();
22618        } else {
22619            self.git_blame_inline_enabled = true;
22620            self.start_git_blame_inline(user_triggered, window, cx);
22621        }
22622
22623        cx.notify();
22624    }
22625
22626    fn start_git_blame_inline(
22627        &mut self,
22628        user_triggered: bool,
22629        window: &mut Window,
22630        cx: &mut Context<Self>,
22631    ) {
22632        self.start_git_blame(user_triggered, window, cx);
22633
22634        if ProjectSettings::get_global(cx)
22635            .git
22636            .inline_blame_delay()
22637            .is_some()
22638        {
22639            self.start_inline_blame_timer(window, cx);
22640        } else {
22641            self.show_git_blame_inline = true
22642        }
22643    }
22644
22645    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
22646        self.blame.as_ref()
22647    }
22648
22649    pub fn show_git_blame_gutter(&self) -> bool {
22650        self.show_git_blame_gutter
22651    }
22652
22653    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
22654        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
22655    }
22656
22657    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
22658        self.show_git_blame_inline
22659            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
22660            && !self.newest_selection_head_on_empty_line(cx)
22661            && self.has_blame_entries(cx)
22662    }
22663
22664    fn has_blame_entries(&self, cx: &App) -> bool {
22665        self.blame()
22666            .is_some_and(|blame| blame.read(cx).has_generated_entries())
22667    }
22668
22669    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
22670        let cursor_anchor = self.selections.newest_anchor().head();
22671
22672        let snapshot = self.buffer.read(cx).snapshot(cx);
22673        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
22674
22675        snapshot.line_len(buffer_row) == 0
22676    }
22677
22678    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
22679        let buffer_and_selection = maybe!({
22680            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22681            let selection_range = selection.range();
22682
22683            let multi_buffer = self.buffer().read(cx);
22684            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
22685            let buffer_ranges = multi_buffer_snapshot
22686                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
22687
22688            let (buffer, range, _) = if selection.reversed {
22689                buffer_ranges.first()
22690            } else {
22691                buffer_ranges.last()
22692            }?;
22693
22694            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
22695            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
22696
22697            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
22698                let selection = start_row_in_buffer..end_row_in_buffer;
22699
22700                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
22701            };
22702
22703            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
22704            let (mut translated, _, _) = buffer_diff_snapshot.points_to_base_text_points(
22705                [
22706                    Point::new(start_row_in_buffer, 0),
22707                    Point::new(end_row_in_buffer, 0),
22708                ],
22709                buffer,
22710            );
22711            let start_row = translated.next().unwrap().start.row;
22712            let end_row = translated.next().unwrap().end.row;
22713
22714            Some((
22715                multi_buffer.buffer(buffer.remote_id()).unwrap(),
22716                start_row..end_row,
22717            ))
22718        });
22719
22720        let Some((buffer, selection)) = buffer_and_selection else {
22721            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
22722        };
22723
22724        let Some(project) = self.project() else {
22725            return Task::ready(Err(anyhow!("editor does not have project")));
22726        };
22727
22728        project.update(cx, |project, cx| {
22729            project.get_permalink_to_line(&buffer, selection, cx)
22730        })
22731    }
22732
22733    pub fn copy_permalink_to_line(
22734        &mut self,
22735        _: &CopyPermalinkToLine,
22736        window: &mut Window,
22737        cx: &mut Context<Self>,
22738    ) {
22739        let permalink_task = self.get_permalink_to_line(cx);
22740        let workspace = self.workspace();
22741
22742        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22743            Ok(permalink) => {
22744                cx.update(|_, cx| {
22745                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
22746                })
22747                .ok();
22748            }
22749            Err(err) => {
22750                let message = format!("Failed to copy permalink: {err}");
22751
22752                anyhow::Result::<()>::Err(err).log_err();
22753
22754                if let Some(workspace) = workspace {
22755                    workspace
22756                        .update_in(cx, |workspace, _, cx| {
22757                            struct CopyPermalinkToLine;
22758
22759                            workspace.show_toast(
22760                                Toast::new(
22761                                    NotificationId::unique::<CopyPermalinkToLine>(),
22762                                    message,
22763                                ),
22764                                cx,
22765                            )
22766                        })
22767                        .ok();
22768                }
22769            }
22770        })
22771        .detach();
22772    }
22773
22774    pub fn copy_file_location(
22775        &mut self,
22776        _: &CopyFileLocation,
22777        _: &mut Window,
22778        cx: &mut Context<Self>,
22779    ) {
22780        let selection = self
22781            .selections
22782            .newest::<Point>(&self.display_snapshot(cx))
22783            .start
22784            .row
22785            + 1;
22786        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22787            let project = self.project()?.read(cx);
22788            let file = buffer.read(cx).file()?;
22789            let path = file.path().display(project.path_style(cx));
22790
22791            Some(format!("{path}:{selection}"))
22792        }) {
22793            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
22794        }
22795    }
22796
22797    pub fn open_permalink_to_line(
22798        &mut self,
22799        _: &OpenPermalinkToLine,
22800        window: &mut Window,
22801        cx: &mut Context<Self>,
22802    ) {
22803        let permalink_task = self.get_permalink_to_line(cx);
22804        let workspace = self.workspace();
22805
22806        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22807            Ok(permalink) => {
22808                cx.update(|_, cx| {
22809                    cx.open_url(permalink.as_ref());
22810                })
22811                .ok();
22812            }
22813            Err(err) => {
22814                let message = format!("Failed to open permalink: {err}");
22815
22816                anyhow::Result::<()>::Err(err).log_err();
22817
22818                if let Some(workspace) = workspace {
22819                    workspace.update(cx, |workspace, cx| {
22820                        struct OpenPermalinkToLine;
22821
22822                        workspace.show_toast(
22823                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
22824                            cx,
22825                        )
22826                    });
22827                }
22828            }
22829        })
22830        .detach();
22831    }
22832
22833    pub fn insert_uuid_v4(
22834        &mut self,
22835        _: &InsertUuidV4,
22836        window: &mut Window,
22837        cx: &mut Context<Self>,
22838    ) {
22839        self.insert_uuid(UuidVersion::V4, window, cx);
22840    }
22841
22842    pub fn insert_uuid_v7(
22843        &mut self,
22844        _: &InsertUuidV7,
22845        window: &mut Window,
22846        cx: &mut Context<Self>,
22847    ) {
22848        self.insert_uuid(UuidVersion::V7, window, cx);
22849    }
22850
22851    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
22852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
22853        self.transact(window, cx, |this, window, cx| {
22854            let edits = this
22855                .selections
22856                .all::<Point>(&this.display_snapshot(cx))
22857                .into_iter()
22858                .map(|selection| {
22859                    let uuid = match version {
22860                        UuidVersion::V4 => uuid::Uuid::new_v4(),
22861                        UuidVersion::V7 => uuid::Uuid::now_v7(),
22862                    };
22863
22864                    (selection.range(), uuid.to_string())
22865                });
22866            this.edit(edits, cx);
22867            this.refresh_edit_prediction(true, false, window, cx);
22868        });
22869    }
22870
22871    pub fn open_selections_in_multibuffer(
22872        &mut self,
22873        _: &OpenSelectionsInMultibuffer,
22874        window: &mut Window,
22875        cx: &mut Context<Self>,
22876    ) {
22877        let multibuffer = self.buffer.read(cx);
22878
22879        let Some(buffer) = multibuffer.as_singleton() else {
22880            return;
22881        };
22882
22883        let Some(workspace) = self.workspace() else {
22884            return;
22885        };
22886
22887        let title = multibuffer.title(cx).to_string();
22888
22889        let locations = self
22890            .selections
22891            .all_anchors(&self.display_snapshot(cx))
22892            .iter()
22893            .map(|selection| {
22894                (
22895                    buffer.clone(),
22896                    (selection.start.text_anchor..selection.end.text_anchor)
22897                        .to_point(buffer.read(cx)),
22898                )
22899            })
22900            .into_group_map();
22901
22902        cx.spawn_in(window, async move |_, cx| {
22903            workspace.update_in(cx, |workspace, window, cx| {
22904                Self::open_locations_in_multibuffer(
22905                    workspace,
22906                    locations,
22907                    format!("Selections for '{title}'"),
22908                    false,
22909                    false,
22910                    MultibufferSelectionMode::All,
22911                    window,
22912                    cx,
22913                );
22914            })
22915        })
22916        .detach();
22917    }
22918
22919    /// Adds a row highlight for the given range. If a row has multiple highlights, the
22920    /// last highlight added will be used.
22921    ///
22922    /// If the range ends at the beginning of a line, then that line will not be highlighted.
22923    pub fn highlight_rows<T: 'static>(
22924        &mut self,
22925        range: Range<Anchor>,
22926        color: Hsla,
22927        options: RowHighlightOptions,
22928        cx: &mut Context<Self>,
22929    ) {
22930        let snapshot = self.buffer().read(cx).snapshot(cx);
22931        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
22932        let ix = row_highlights.binary_search_by(|highlight| {
22933            Ordering::Equal
22934                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
22935                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
22936        });
22937
22938        if let Err(mut ix) = ix {
22939            let index = post_inc(&mut self.highlight_order);
22940
22941            // If this range intersects with the preceding highlight, then merge it with
22942            // the preceding highlight. Otherwise insert a new highlight.
22943            let mut merged = false;
22944            if ix > 0 {
22945                let prev_highlight = &mut row_highlights[ix - 1];
22946                if prev_highlight
22947                    .range
22948                    .end
22949                    .cmp(&range.start, &snapshot)
22950                    .is_ge()
22951                {
22952                    ix -= 1;
22953                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
22954                        prev_highlight.range.end = range.end;
22955                    }
22956                    merged = true;
22957                    prev_highlight.index = index;
22958                    prev_highlight.color = color;
22959                    prev_highlight.options = options;
22960                }
22961            }
22962
22963            if !merged {
22964                row_highlights.insert(
22965                    ix,
22966                    RowHighlight {
22967                        range,
22968                        index,
22969                        color,
22970                        options,
22971                        type_id: TypeId::of::<T>(),
22972                    },
22973                );
22974            }
22975
22976            // If any of the following highlights intersect with this one, merge them.
22977            while let Some(next_highlight) = row_highlights.get(ix + 1) {
22978                let highlight = &row_highlights[ix];
22979                if next_highlight
22980                    .range
22981                    .start
22982                    .cmp(&highlight.range.end, &snapshot)
22983                    .is_le()
22984                {
22985                    if next_highlight
22986                        .range
22987                        .end
22988                        .cmp(&highlight.range.end, &snapshot)
22989                        .is_gt()
22990                    {
22991                        row_highlights[ix].range.end = next_highlight.range.end;
22992                    }
22993                    row_highlights.remove(ix + 1);
22994                } else {
22995                    break;
22996                }
22997            }
22998        }
22999    }
23000
23001    /// Remove any highlighted row ranges of the given type that intersect the
23002    /// given ranges.
23003    pub fn remove_highlighted_rows<T: 'static>(
23004        &mut self,
23005        ranges_to_remove: Vec<Range<Anchor>>,
23006        cx: &mut Context<Self>,
23007    ) {
23008        let snapshot = self.buffer().read(cx).snapshot(cx);
23009        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23010        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23011        row_highlights.retain(|highlight| {
23012            while let Some(range_to_remove) = ranges_to_remove.peek() {
23013                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23014                    Ordering::Less | Ordering::Equal => {
23015                        ranges_to_remove.next();
23016                    }
23017                    Ordering::Greater => {
23018                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23019                            Ordering::Less | Ordering::Equal => {
23020                                return false;
23021                            }
23022                            Ordering::Greater => break,
23023                        }
23024                    }
23025                }
23026            }
23027
23028            true
23029        })
23030    }
23031
23032    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23033    pub fn clear_row_highlights<T: 'static>(&mut self) {
23034        self.highlighted_rows.remove(&TypeId::of::<T>());
23035    }
23036
23037    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23038    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23039        self.highlighted_rows
23040            .get(&TypeId::of::<T>())
23041            .map_or(&[] as &[_], |vec| vec.as_slice())
23042            .iter()
23043            .map(|highlight| (highlight.range.clone(), highlight.color))
23044    }
23045
23046    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23047    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23048    /// Allows to ignore certain kinds of highlights.
23049    pub fn highlighted_display_rows(
23050        &self,
23051        window: &mut Window,
23052        cx: &mut App,
23053    ) -> BTreeMap<DisplayRow, LineHighlight> {
23054        let snapshot = self.snapshot(window, cx);
23055        let mut used_highlight_orders = HashMap::default();
23056        self.highlighted_rows
23057            .iter()
23058            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23059            .fold(
23060                BTreeMap::<DisplayRow, LineHighlight>::new(),
23061                |mut unique_rows, highlight| {
23062                    let start = highlight.range.start.to_display_point(&snapshot);
23063                    let end = highlight.range.end.to_display_point(&snapshot);
23064                    let start_row = start.row().0;
23065                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
23066                    {
23067                        end.row().0.saturating_sub(1)
23068                    } else {
23069                        end.row().0
23070                    };
23071                    for row in start_row..=end_row {
23072                        let used_index =
23073                            used_highlight_orders.entry(row).or_insert(highlight.index);
23074                        if highlight.index >= *used_index {
23075                            *used_index = highlight.index;
23076                            unique_rows.insert(
23077                                DisplayRow(row),
23078                                LineHighlight {
23079                                    include_gutter: highlight.options.include_gutter,
23080                                    border: None,
23081                                    background: highlight.color.into(),
23082                                    type_id: Some(highlight.type_id),
23083                                },
23084                            );
23085                        }
23086                    }
23087                    unique_rows
23088                },
23089            )
23090    }
23091
23092    pub fn highlighted_display_row_for_autoscroll(
23093        &self,
23094        snapshot: &DisplaySnapshot,
23095    ) -> Option<DisplayRow> {
23096        self.highlighted_rows
23097            .values()
23098            .flat_map(|highlighted_rows| highlighted_rows.iter())
23099            .filter_map(|highlight| {
23100                if highlight.options.autoscroll {
23101                    Some(highlight.range.start.to_display_point(snapshot).row())
23102                } else {
23103                    None
23104                }
23105            })
23106            .min()
23107    }
23108
23109    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23110        self.highlight_background::<SearchWithinRange>(
23111            ranges,
23112            |_, colors| colors.colors().editor_document_highlight_read_background,
23113            cx,
23114        )
23115    }
23116
23117    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23118        self.breadcrumb_header = Some(new_header);
23119    }
23120
23121    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23122        self.clear_background_highlights::<SearchWithinRange>(cx);
23123    }
23124
23125    pub fn highlight_background<T: 'static>(
23126        &mut self,
23127        ranges: &[Range<Anchor>],
23128        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23129        cx: &mut Context<Self>,
23130    ) {
23131        self.background_highlights.insert(
23132            HighlightKey::Type(TypeId::of::<T>()),
23133            (Arc::new(color_fetcher), Arc::from(ranges)),
23134        );
23135        self.scrollbar_marker_state.dirty = true;
23136        cx.notify();
23137    }
23138
23139    pub fn highlight_background_key<T: 'static>(
23140        &mut self,
23141        key: usize,
23142        ranges: &[Range<Anchor>],
23143        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23144        cx: &mut Context<Self>,
23145    ) {
23146        self.background_highlights.insert(
23147            HighlightKey::TypePlus(TypeId::of::<T>(), key),
23148            (Arc::new(color_fetcher), Arc::from(ranges)),
23149        );
23150        self.scrollbar_marker_state.dirty = true;
23151        cx.notify();
23152    }
23153
23154    pub fn clear_background_highlights<T: 'static>(
23155        &mut self,
23156        cx: &mut Context<Self>,
23157    ) -> Option<BackgroundHighlight> {
23158        let text_highlights = self
23159            .background_highlights
23160            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
23161        if !text_highlights.1.is_empty() {
23162            self.scrollbar_marker_state.dirty = true;
23163            cx.notify();
23164        }
23165        Some(text_highlights)
23166    }
23167
23168    pub fn clear_background_highlights_key<T: 'static>(
23169        &mut self,
23170        key: usize,
23171        cx: &mut Context<Self>,
23172    ) -> Option<BackgroundHighlight> {
23173        let text_highlights = self
23174            .background_highlights
23175            .remove(&HighlightKey::TypePlus(TypeId::of::<T>(), key))?;
23176        if !text_highlights.1.is_empty() {
23177            self.scrollbar_marker_state.dirty = true;
23178            cx.notify();
23179        }
23180        Some(text_highlights)
23181    }
23182
23183    pub fn highlight_gutter<T: 'static>(
23184        &mut self,
23185        ranges: impl Into<Vec<Range<Anchor>>>,
23186        color_fetcher: fn(&App) -> Hsla,
23187        cx: &mut Context<Self>,
23188    ) {
23189        self.gutter_highlights
23190            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23191        cx.notify();
23192    }
23193
23194    pub fn clear_gutter_highlights<T: 'static>(
23195        &mut self,
23196        cx: &mut Context<Self>,
23197    ) -> Option<GutterHighlight> {
23198        cx.notify();
23199        self.gutter_highlights.remove(&TypeId::of::<T>())
23200    }
23201
23202    pub fn insert_gutter_highlight<T: 'static>(
23203        &mut self,
23204        range: Range<Anchor>,
23205        color_fetcher: fn(&App) -> Hsla,
23206        cx: &mut Context<Self>,
23207    ) {
23208        let snapshot = self.buffer().read(cx).snapshot(cx);
23209        let mut highlights = self
23210            .gutter_highlights
23211            .remove(&TypeId::of::<T>())
23212            .map(|(_, highlights)| highlights)
23213            .unwrap_or_default();
23214        let ix = highlights.binary_search_by(|highlight| {
23215            Ordering::Equal
23216                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23217                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23218        });
23219        if let Err(ix) = ix {
23220            highlights.insert(ix, range);
23221        }
23222        self.gutter_highlights
23223            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23224    }
23225
23226    pub fn remove_gutter_highlights<T: 'static>(
23227        &mut self,
23228        ranges_to_remove: Vec<Range<Anchor>>,
23229        cx: &mut Context<Self>,
23230    ) {
23231        let snapshot = self.buffer().read(cx).snapshot(cx);
23232        let Some((color_fetcher, mut gutter_highlights)) =
23233            self.gutter_highlights.remove(&TypeId::of::<T>())
23234        else {
23235            return;
23236        };
23237        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23238        gutter_highlights.retain(|highlight| {
23239            while let Some(range_to_remove) = ranges_to_remove.peek() {
23240                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23241                    Ordering::Less | Ordering::Equal => {
23242                        ranges_to_remove.next();
23243                    }
23244                    Ordering::Greater => {
23245                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23246                            Ordering::Less | Ordering::Equal => {
23247                                return false;
23248                            }
23249                            Ordering::Greater => break,
23250                        }
23251                    }
23252                }
23253            }
23254
23255            true
23256        });
23257        self.gutter_highlights
23258            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23259    }
23260
23261    #[cfg(feature = "test-support")]
23262    pub fn all_text_highlights(
23263        &self,
23264        window: &mut Window,
23265        cx: &mut Context<Self>,
23266    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23267        let snapshot = self.snapshot(window, cx);
23268        self.display_map.update(cx, |display_map, _| {
23269            display_map
23270                .all_text_highlights()
23271                .map(|highlight| {
23272                    let (style, ranges) = highlight.as_ref();
23273                    (
23274                        *style,
23275                        ranges
23276                            .iter()
23277                            .map(|range| range.clone().to_display_points(&snapshot))
23278                            .collect(),
23279                    )
23280                })
23281                .collect()
23282        })
23283    }
23284
23285    #[cfg(feature = "test-support")]
23286    pub fn all_text_background_highlights(
23287        &self,
23288        window: &mut Window,
23289        cx: &mut Context<Self>,
23290    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23291        let snapshot = self.snapshot(window, cx);
23292        let buffer = &snapshot.buffer_snapshot();
23293        let start = buffer.anchor_before(MultiBufferOffset(0));
23294        let end = buffer.anchor_after(buffer.len());
23295        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23296    }
23297
23298    #[cfg(any(test, feature = "test-support"))]
23299    pub fn sorted_background_highlights_in_range(
23300        &self,
23301        search_range: Range<Anchor>,
23302        display_snapshot: &DisplaySnapshot,
23303        theme: &Theme,
23304    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23305        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23306        res.sort_by(|a, b| {
23307            a.0.start
23308                .cmp(&b.0.start)
23309                .then_with(|| a.0.end.cmp(&b.0.end))
23310                .then_with(|| a.1.cmp(&b.1))
23311        });
23312        res
23313    }
23314
23315    #[cfg(feature = "test-support")]
23316    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23317        let snapshot = self.buffer().read(cx).snapshot(cx);
23318
23319        let highlights = self
23320            .background_highlights
23321            .get(&HighlightKey::Type(TypeId::of::<
23322                items::BufferSearchHighlights,
23323            >()));
23324
23325        if let Some((_color, ranges)) = highlights {
23326            ranges
23327                .iter()
23328                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23329                .collect_vec()
23330        } else {
23331            vec![]
23332        }
23333    }
23334
23335    fn document_highlights_for_position<'a>(
23336        &'a self,
23337        position: Anchor,
23338        buffer: &'a MultiBufferSnapshot,
23339    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23340        let read_highlights = self
23341            .background_highlights
23342            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
23343            .map(|h| &h.1);
23344        let write_highlights = self
23345            .background_highlights
23346            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
23347            .map(|h| &h.1);
23348        let left_position = position.bias_left(buffer);
23349        let right_position = position.bias_right(buffer);
23350        read_highlights
23351            .into_iter()
23352            .chain(write_highlights)
23353            .flat_map(move |ranges| {
23354                let start_ix = match ranges.binary_search_by(|probe| {
23355                    let cmp = probe.end.cmp(&left_position, buffer);
23356                    if cmp.is_ge() {
23357                        Ordering::Greater
23358                    } else {
23359                        Ordering::Less
23360                    }
23361                }) {
23362                    Ok(i) | Err(i) => i,
23363                };
23364
23365                ranges[start_ix..]
23366                    .iter()
23367                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23368            })
23369    }
23370
23371    pub fn has_background_highlights<T: 'static>(&self) -> bool {
23372        self.background_highlights
23373            .get(&HighlightKey::Type(TypeId::of::<T>()))
23374            .is_some_and(|(_, highlights)| !highlights.is_empty())
23375    }
23376
23377    /// Returns all background highlights for a given range.
23378    ///
23379    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23380    pub fn background_highlights_in_range(
23381        &self,
23382        search_range: Range<Anchor>,
23383        display_snapshot: &DisplaySnapshot,
23384        theme: &Theme,
23385    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23386        let mut results = Vec::new();
23387        for (color_fetcher, ranges) in self.background_highlights.values() {
23388            let start_ix = match ranges.binary_search_by(|probe| {
23389                let cmp = probe
23390                    .end
23391                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23392                if cmp.is_gt() {
23393                    Ordering::Greater
23394                } else {
23395                    Ordering::Less
23396                }
23397            }) {
23398                Ok(i) | Err(i) => i,
23399            };
23400            for (index, range) in ranges[start_ix..].iter().enumerate() {
23401                if range
23402                    .start
23403                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23404                    .is_ge()
23405                {
23406                    break;
23407                }
23408
23409                let color = color_fetcher(&(start_ix + index), theme);
23410                let start = range.start.to_display_point(display_snapshot);
23411                let end = range.end.to_display_point(display_snapshot);
23412                results.push((start..end, color))
23413            }
23414        }
23415        results
23416    }
23417
23418    pub fn gutter_highlights_in_range(
23419        &self,
23420        search_range: Range<Anchor>,
23421        display_snapshot: &DisplaySnapshot,
23422        cx: &App,
23423    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23424        let mut results = Vec::new();
23425        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23426            let color = color_fetcher(cx);
23427            let start_ix = match ranges.binary_search_by(|probe| {
23428                let cmp = probe
23429                    .end
23430                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23431                if cmp.is_gt() {
23432                    Ordering::Greater
23433                } else {
23434                    Ordering::Less
23435                }
23436            }) {
23437                Ok(i) | Err(i) => i,
23438            };
23439            for range in &ranges[start_ix..] {
23440                if range
23441                    .start
23442                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23443                    .is_ge()
23444                {
23445                    break;
23446                }
23447
23448                let start = range.start.to_display_point(display_snapshot);
23449                let end = range.end.to_display_point(display_snapshot);
23450                results.push((start..end, color))
23451            }
23452        }
23453        results
23454    }
23455
23456    /// Get the text ranges corresponding to the redaction query
23457    pub fn redacted_ranges(
23458        &self,
23459        search_range: Range<Anchor>,
23460        display_snapshot: &DisplaySnapshot,
23461        cx: &App,
23462    ) -> Vec<Range<DisplayPoint>> {
23463        display_snapshot
23464            .buffer_snapshot()
23465            .redacted_ranges(search_range, |file| {
23466                if let Some(file) = file {
23467                    file.is_private()
23468                        && EditorSettings::get(
23469                            Some(SettingsLocation {
23470                                worktree_id: file.worktree_id(cx),
23471                                path: file.path().as_ref(),
23472                            }),
23473                            cx,
23474                        )
23475                        .redact_private_values
23476                } else {
23477                    false
23478                }
23479            })
23480            .map(|range| {
23481                range.start.to_display_point(display_snapshot)
23482                    ..range.end.to_display_point(display_snapshot)
23483            })
23484            .collect()
23485    }
23486
23487    pub fn highlight_text_key<T: 'static>(
23488        &mut self,
23489        key: usize,
23490        ranges: Vec<Range<Anchor>>,
23491        style: HighlightStyle,
23492        merge: bool,
23493        cx: &mut Context<Self>,
23494    ) {
23495        self.display_map.update(cx, |map, cx| {
23496            map.highlight_text(
23497                HighlightKey::TypePlus(TypeId::of::<T>(), key),
23498                ranges,
23499                style,
23500                merge,
23501                cx,
23502            );
23503        });
23504        cx.notify();
23505    }
23506
23507    pub fn highlight_text<T: 'static>(
23508        &mut self,
23509        ranges: Vec<Range<Anchor>>,
23510        style: HighlightStyle,
23511        cx: &mut Context<Self>,
23512    ) {
23513        self.display_map.update(cx, |map, cx| {
23514            map.highlight_text(
23515                HighlightKey::Type(TypeId::of::<T>()),
23516                ranges,
23517                style,
23518                false,
23519                cx,
23520            )
23521        });
23522        cx.notify();
23523    }
23524
23525    pub fn text_highlights<'a, T: 'static>(
23526        &'a self,
23527        cx: &'a App,
23528    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
23529        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
23530    }
23531
23532    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
23533        let cleared = self
23534            .display_map
23535            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
23536        if cleared {
23537            cx.notify();
23538        }
23539    }
23540
23541    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
23542        (self.read_only(cx) || self.blink_manager.read(cx).visible())
23543            && self.focus_handle.is_focused(window)
23544    }
23545
23546    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
23547        self.show_cursor_when_unfocused = is_enabled;
23548        cx.notify();
23549    }
23550
23551    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
23552        cx.notify();
23553    }
23554
23555    fn on_debug_session_event(
23556        &mut self,
23557        _session: Entity<Session>,
23558        event: &SessionEvent,
23559        cx: &mut Context<Self>,
23560    ) {
23561        if let SessionEvent::InvalidateInlineValue = event {
23562            self.refresh_inline_values(cx);
23563        }
23564    }
23565
23566    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
23567        let Some(project) = self.project.clone() else {
23568            return;
23569        };
23570
23571        if !self.inline_value_cache.enabled {
23572            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
23573            self.splice_inlays(&inlays, Vec::new(), cx);
23574            return;
23575        }
23576
23577        let current_execution_position = self
23578            .highlighted_rows
23579            .get(&TypeId::of::<ActiveDebugLine>())
23580            .and_then(|lines| lines.last().map(|line| line.range.end));
23581
23582        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
23583            let inline_values = editor
23584                .update(cx, |editor, cx| {
23585                    let Some(current_execution_position) = current_execution_position else {
23586                        return Some(Task::ready(Ok(Vec::new())));
23587                    };
23588
23589                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
23590                        let snapshot = buffer.snapshot(cx);
23591
23592                        let excerpt = snapshot.excerpt_containing(
23593                            current_execution_position..current_execution_position,
23594                        )?;
23595
23596                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
23597                    })?;
23598
23599                    let range =
23600                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
23601
23602                    project.inline_values(buffer, range, cx)
23603                })
23604                .ok()
23605                .flatten()?
23606                .await
23607                .context("refreshing debugger inlays")
23608                .log_err()?;
23609
23610            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
23611
23612            for (buffer_id, inline_value) in inline_values
23613                .into_iter()
23614                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
23615            {
23616                buffer_inline_values
23617                    .entry(buffer_id)
23618                    .or_default()
23619                    .push(inline_value);
23620            }
23621
23622            editor
23623                .update(cx, |editor, cx| {
23624                    let snapshot = editor.buffer.read(cx).snapshot(cx);
23625                    let mut new_inlays = Vec::default();
23626
23627                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
23628                        let buffer_id = buffer_snapshot.remote_id();
23629                        buffer_inline_values
23630                            .get(&buffer_id)
23631                            .into_iter()
23632                            .flatten()
23633                            .for_each(|hint| {
23634                                let inlay = Inlay::debugger(
23635                                    post_inc(&mut editor.next_inlay_id),
23636                                    Anchor::in_buffer(excerpt_id, hint.position),
23637                                    hint.text(),
23638                                );
23639                                if !inlay.text().chars().contains(&'\n') {
23640                                    new_inlays.push(inlay);
23641                                }
23642                            });
23643                    }
23644
23645                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
23646                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
23647
23648                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
23649                })
23650                .ok()?;
23651            Some(())
23652        });
23653    }
23654
23655    fn on_buffer_event(
23656        &mut self,
23657        multibuffer: &Entity<MultiBuffer>,
23658        event: &multi_buffer::Event,
23659        window: &mut Window,
23660        cx: &mut Context<Self>,
23661    ) {
23662        match event {
23663            multi_buffer::Event::Edited { edited_buffer } => {
23664                self.scrollbar_marker_state.dirty = true;
23665                self.active_indent_guides_state.dirty = true;
23666                self.refresh_active_diagnostics(cx);
23667                self.refresh_code_actions(window, cx);
23668                self.refresh_single_line_folds(window, cx);
23669                self.refresh_matching_bracket_highlights(window, cx);
23670                if self.has_active_edit_prediction() {
23671                    self.update_visible_edit_prediction(window, cx);
23672                }
23673
23674                // Clean up orphaned review comments after edits
23675                self.cleanup_orphaned_review_comments(cx);
23676
23677                if let Some(buffer) = edited_buffer {
23678                    if buffer.read(cx).file().is_none() {
23679                        cx.emit(EditorEvent::TitleChanged);
23680                    }
23681
23682                    if self.project.is_some() {
23683                        let buffer_id = buffer.read(cx).remote_id();
23684                        self.register_buffer(buffer_id, cx);
23685                        self.update_lsp_data(Some(buffer_id), window, cx);
23686                        self.refresh_inlay_hints(
23687                            InlayHintRefreshReason::BufferEdited(buffer_id),
23688                            cx,
23689                        );
23690                    }
23691                }
23692
23693                cx.emit(EditorEvent::BufferEdited);
23694                cx.emit(SearchEvent::MatchesInvalidated);
23695
23696                let Some(project) = &self.project else { return };
23697                let (telemetry, is_via_ssh) = {
23698                    let project = project.read(cx);
23699                    let telemetry = project.client().telemetry().clone();
23700                    let is_via_ssh = project.is_via_remote_server();
23701                    (telemetry, is_via_ssh)
23702                };
23703                telemetry.log_edit_event("editor", is_via_ssh);
23704            }
23705            multi_buffer::Event::ExcerptsAdded {
23706                buffer,
23707                predecessor,
23708                excerpts,
23709            } => {
23710                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23711                let buffer_id = buffer.read(cx).remote_id();
23712                if self.buffer.read(cx).diff_for(buffer_id).is_none()
23713                    && let Some(project) = &self.project
23714                {
23715                    update_uncommitted_diff_for_buffer(
23716                        cx.entity(),
23717                        project,
23718                        [buffer.clone()],
23719                        self.buffer.clone(),
23720                        cx,
23721                    )
23722                    .detach();
23723                }
23724                self.update_lsp_data(Some(buffer_id), window, cx);
23725                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23726                self.colorize_brackets(false, cx);
23727                self.refresh_selected_text_highlights(true, window, cx);
23728                cx.emit(EditorEvent::ExcerptsAdded {
23729                    buffer: buffer.clone(),
23730                    predecessor: *predecessor,
23731                    excerpts: excerpts.clone(),
23732                });
23733            }
23734            multi_buffer::Event::ExcerptsRemoved {
23735                ids,
23736                removed_buffer_ids,
23737            } => {
23738                if let Some(inlay_hints) = &mut self.inlay_hints {
23739                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
23740                }
23741                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
23742                for buffer_id in removed_buffer_ids {
23743                    self.registered_buffers.remove(buffer_id);
23744                }
23745                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23746                cx.emit(EditorEvent::ExcerptsRemoved {
23747                    ids: ids.clone(),
23748                    removed_buffer_ids: removed_buffer_ids.clone(),
23749                });
23750            }
23751            multi_buffer::Event::ExcerptsEdited {
23752                excerpt_ids,
23753                buffer_ids,
23754            } => {
23755                self.display_map.update(cx, |map, cx| {
23756                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
23757                });
23758                cx.emit(EditorEvent::ExcerptsEdited {
23759                    ids: excerpt_ids.clone(),
23760                });
23761            }
23762            multi_buffer::Event::ExcerptsExpanded { ids } => {
23763                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23764                self.refresh_document_highlights(cx);
23765                for id in ids {
23766                    self.fetched_tree_sitter_chunks.remove(id);
23767                }
23768                self.colorize_brackets(false, cx);
23769                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
23770            }
23771            multi_buffer::Event::Reparsed(buffer_id) => {
23772                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23773                self.refresh_selected_text_highlights(true, window, cx);
23774                self.colorize_brackets(true, cx);
23775                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23776
23777                cx.emit(EditorEvent::Reparsed(*buffer_id));
23778            }
23779            multi_buffer::Event::DiffHunksToggled => {
23780                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23781            }
23782            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
23783                if !is_fresh_language {
23784                    self.registered_buffers.remove(&buffer_id);
23785                }
23786                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23787                cx.emit(EditorEvent::Reparsed(*buffer_id));
23788                cx.notify();
23789            }
23790            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
23791            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
23792            multi_buffer::Event::FileHandleChanged
23793            | multi_buffer::Event::Reloaded
23794            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
23795            multi_buffer::Event::DiagnosticsUpdated => {
23796                self.update_diagnostics_state(window, cx);
23797            }
23798            _ => {}
23799        };
23800    }
23801
23802    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
23803        if !self.diagnostics_enabled() {
23804            return;
23805        }
23806        self.refresh_active_diagnostics(cx);
23807        self.refresh_inline_diagnostics(true, window, cx);
23808        self.scrollbar_marker_state.dirty = true;
23809        cx.notify();
23810    }
23811
23812    pub fn start_temporary_diff_override(&mut self) {
23813        self.load_diff_task.take();
23814        self.temporary_diff_override = true;
23815    }
23816
23817    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
23818        self.temporary_diff_override = false;
23819        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
23820        self.buffer.update(cx, |buffer, cx| {
23821            buffer.set_all_diff_hunks_collapsed(cx);
23822        });
23823
23824        if let Some(project) = self.project.clone() {
23825            self.load_diff_task = Some(
23826                update_uncommitted_diff_for_buffer(
23827                    cx.entity(),
23828                    &project,
23829                    self.buffer.read(cx).all_buffers(),
23830                    self.buffer.clone(),
23831                    cx,
23832                )
23833                .shared(),
23834            );
23835        }
23836    }
23837
23838    fn on_display_map_changed(
23839        &mut self,
23840        _: Entity<DisplayMap>,
23841        _: &mut Window,
23842        cx: &mut Context<Self>,
23843    ) {
23844        cx.notify();
23845    }
23846
23847    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
23848        if !self.mode.is_full() {
23849            return None;
23850        }
23851
23852        let theme_settings = theme::ThemeSettings::get_global(cx);
23853        let theme = cx.theme();
23854        let accent_colors = theme.accents().clone();
23855
23856        let accent_overrides = theme_settings
23857            .theme_overrides
23858            .get(theme.name.as_ref())
23859            .map(|theme_style| &theme_style.accents)
23860            .into_iter()
23861            .flatten()
23862            .chain(
23863                theme_settings
23864                    .experimental_theme_overrides
23865                    .as_ref()
23866                    .map(|overrides| &overrides.accents)
23867                    .into_iter()
23868                    .flatten(),
23869            )
23870            .flat_map(|accent| accent.0.clone().map(SharedString::from))
23871            .collect();
23872
23873        Some(AccentData {
23874            colors: accent_colors,
23875            overrides: accent_overrides,
23876        })
23877    }
23878
23879    fn fetch_applicable_language_settings(
23880        &self,
23881        cx: &App,
23882    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
23883        if !self.mode.is_full() {
23884            return HashMap::default();
23885        }
23886
23887        self.buffer().read(cx).all_buffers().into_iter().fold(
23888            HashMap::default(),
23889            |mut acc, buffer| {
23890                let buffer = buffer.read(cx);
23891                let language = buffer.language().map(|language| language.name());
23892                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
23893                    let file = buffer.file();
23894                    v.insert(language_settings(language, file, cx).into_owned());
23895                }
23896                acc
23897            },
23898        )
23899    }
23900
23901    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23902        let new_language_settings = self.fetch_applicable_language_settings(cx);
23903        let language_settings_changed = new_language_settings != self.applicable_language_settings;
23904        self.applicable_language_settings = new_language_settings;
23905
23906        let new_accents = self.fetch_accent_data(cx);
23907        let accents_changed = new_accents != self.accent_data;
23908        self.accent_data = new_accents;
23909
23910        if self.diagnostics_enabled() {
23911            let new_severity = EditorSettings::get_global(cx)
23912                .diagnostics_max_severity
23913                .unwrap_or(DiagnosticSeverity::Hint);
23914            self.set_max_diagnostics_severity(new_severity, cx);
23915        }
23916        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
23917        self.update_edit_prediction_settings(cx);
23918        self.refresh_edit_prediction(true, false, window, cx);
23919        self.refresh_inline_values(cx);
23920        self.refresh_inlay_hints(
23921            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
23922                self.selections.newest_anchor().head(),
23923                &self.buffer.read(cx).snapshot(cx),
23924                cx,
23925            )),
23926            cx,
23927        );
23928
23929        let old_cursor_shape = self.cursor_shape;
23930        let old_show_breadcrumbs = self.show_breadcrumbs;
23931
23932        {
23933            let editor_settings = EditorSettings::get_global(cx);
23934            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
23935            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
23936            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
23937            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
23938        }
23939
23940        if old_cursor_shape != self.cursor_shape {
23941            cx.emit(EditorEvent::CursorShapeChanged);
23942        }
23943
23944        if old_show_breadcrumbs != self.show_breadcrumbs {
23945            cx.emit(EditorEvent::BreadcrumbsChanged);
23946        }
23947
23948        let project_settings = ProjectSettings::get_global(cx);
23949        self.buffer_serialization = self
23950            .should_serialize_buffer()
23951            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
23952
23953        if self.mode.is_full() {
23954            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
23955            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
23956            if self.show_inline_diagnostics != show_inline_diagnostics {
23957                self.show_inline_diagnostics = show_inline_diagnostics;
23958                self.refresh_inline_diagnostics(false, window, cx);
23959            }
23960
23961            if self.git_blame_inline_enabled != inline_blame_enabled {
23962                self.toggle_git_blame_inline_internal(false, window, cx);
23963            }
23964
23965            let minimap_settings = EditorSettings::get_global(cx).minimap;
23966            if self.minimap_visibility != MinimapVisibility::Disabled {
23967                if self.minimap_visibility.settings_visibility()
23968                    != minimap_settings.minimap_enabled()
23969                {
23970                    self.set_minimap_visibility(
23971                        MinimapVisibility::for_mode(self.mode(), cx),
23972                        window,
23973                        cx,
23974                    );
23975                } else if let Some(minimap_entity) = self.minimap.as_ref() {
23976                    minimap_entity.update(cx, |minimap_editor, cx| {
23977                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
23978                    })
23979                }
23980            }
23981
23982            if language_settings_changed || accents_changed {
23983                self.colorize_brackets(true, cx);
23984            }
23985
23986            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
23987                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
23988            }) {
23989                if !inlay_splice.is_empty() {
23990                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
23991                }
23992                self.refresh_colors_for_visible_range(None, window, cx);
23993            }
23994        }
23995
23996        cx.notify();
23997    }
23998
23999    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24000        if !self.mode.is_full() {
24001            return;
24002        }
24003
24004        let new_accents = self.fetch_accent_data(cx);
24005        if new_accents != self.accent_data {
24006            self.accent_data = new_accents;
24007            self.colorize_brackets(true, cx);
24008        }
24009    }
24010
24011    pub fn set_searchable(&mut self, searchable: bool) {
24012        self.searchable = searchable;
24013    }
24014
24015    pub fn searchable(&self) -> bool {
24016        self.searchable
24017    }
24018
24019    pub fn open_excerpts_in_split(
24020        &mut self,
24021        _: &OpenExcerptsSplit,
24022        window: &mut Window,
24023        cx: &mut Context<Self>,
24024    ) {
24025        self.open_excerpts_common(None, true, window, cx)
24026    }
24027
24028    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24029        self.open_excerpts_common(None, false, window, cx)
24030    }
24031
24032    pub(crate) fn open_excerpts_common(
24033        &mut self,
24034        jump_data: Option<JumpData>,
24035        split: bool,
24036        window: &mut Window,
24037        cx: &mut Context<Self>,
24038    ) {
24039        let Some(workspace) = self.workspace() else {
24040            cx.propagate();
24041            return;
24042        };
24043
24044        if self.buffer.read(cx).is_singleton() {
24045            cx.propagate();
24046            return;
24047        }
24048
24049        let mut new_selections_by_buffer = HashMap::default();
24050        match &jump_data {
24051            Some(JumpData::MultiBufferPoint {
24052                excerpt_id,
24053                position,
24054                anchor,
24055                line_offset_from_top,
24056            }) => {
24057                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
24058                if let Some(buffer) = multi_buffer_snapshot
24059                    .buffer_id_for_excerpt(*excerpt_id)
24060                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
24061                {
24062                    let buffer_snapshot = buffer.read(cx).snapshot();
24063                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
24064                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24065                    } else {
24066                        buffer_snapshot.clip_point(*position, Bias::Left)
24067                    };
24068                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24069                    new_selections_by_buffer.insert(
24070                        buffer,
24071                        (
24072                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24073                            Some(*line_offset_from_top),
24074                        ),
24075                    );
24076                }
24077            }
24078            Some(JumpData::MultiBufferRow {
24079                row,
24080                line_offset_from_top,
24081            }) => {
24082                let point = MultiBufferPoint::new(row.0, 0);
24083                if let Some((buffer, buffer_point, _)) =
24084                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24085                {
24086                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24087                    new_selections_by_buffer
24088                        .entry(buffer)
24089                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24090                        .0
24091                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24092                }
24093            }
24094            None => {
24095                let selections = self
24096                    .selections
24097                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24098                let multi_buffer = self.buffer.read(cx);
24099                for selection in selections {
24100                    for (snapshot, range, _, anchor) in multi_buffer
24101                        .snapshot(cx)
24102                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24103                    {
24104                        if let Some(anchor) = anchor {
24105                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24106                            else {
24107                                continue;
24108                            };
24109                            let offset = text::ToOffset::to_offset(
24110                                &anchor.text_anchor,
24111                                &buffer_handle.read(cx).snapshot(),
24112                            );
24113                            let range = BufferOffset(offset)..BufferOffset(offset);
24114                            new_selections_by_buffer
24115                                .entry(buffer_handle)
24116                                .or_insert((Vec::new(), None))
24117                                .0
24118                                .push(range)
24119                        } else {
24120                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24121                            else {
24122                                continue;
24123                            };
24124                            new_selections_by_buffer
24125                                .entry(buffer_handle)
24126                                .or_insert((Vec::new(), None))
24127                                .0
24128                                .push(range)
24129                        }
24130                    }
24131                }
24132            }
24133        }
24134
24135        new_selections_by_buffer
24136            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24137
24138        if new_selections_by_buffer.is_empty() {
24139            return;
24140        }
24141
24142        // We defer the pane interaction because we ourselves are a workspace item
24143        // and activating a new item causes the pane to call a method on us reentrantly,
24144        // which panics if we're on the stack.
24145        window.defer(cx, move |window, cx| {
24146            workspace.update(cx, |workspace, cx| {
24147                let pane = if split {
24148                    workspace.adjacent_pane(window, cx)
24149                } else {
24150                    workspace.active_pane().clone()
24151                };
24152
24153                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24154                    let buffer_read = buffer.read(cx);
24155                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24156                        (true, project::File::from_dyn(Some(file)).is_some())
24157                    } else {
24158                        (false, false)
24159                    };
24160
24161                    // If project file is none workspace.open_project_item will fail to open the excerpt
24162                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24163                    // so we check if there's a tab match in that case first
24164                    let editor = (!has_file || !is_project_file)
24165                        .then(|| {
24166                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24167                            // so `workspace.open_project_item` will never find them, always opening a new editor.
24168                            // Instead, we try to activate the existing editor in the pane first.
24169                            let (editor, pane_item_index, pane_item_id) =
24170                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
24171                                    let editor = item.downcast::<Editor>()?;
24172                                    let singleton_buffer =
24173                                        editor.read(cx).buffer().read(cx).as_singleton()?;
24174                                    if singleton_buffer == buffer {
24175                                        Some((editor, i, item.item_id()))
24176                                    } else {
24177                                        None
24178                                    }
24179                                })?;
24180                            pane.update(cx, |pane, cx| {
24181                                pane.activate_item(pane_item_index, true, true, window, cx);
24182                                if !PreviewTabsSettings::get_global(cx)
24183                                    .enable_preview_from_multibuffer
24184                                {
24185                                    pane.unpreview_item_if_preview(pane_item_id);
24186                                }
24187                            });
24188                            Some(editor)
24189                        })
24190                        .flatten()
24191                        .unwrap_or_else(|| {
24192                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
24193                                .enable_keep_preview_on_code_navigation;
24194                            let allow_new_preview =
24195                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
24196                            workspace.open_project_item::<Self>(
24197                                pane.clone(),
24198                                buffer,
24199                                true,
24200                                true,
24201                                keep_old_preview,
24202                                allow_new_preview,
24203                                window,
24204                                cx,
24205                            )
24206                        });
24207
24208                    editor.update(cx, |editor, cx| {
24209                        if has_file && !is_project_file {
24210                            editor.set_read_only(true);
24211                        }
24212                        let autoscroll = match scroll_offset {
24213                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
24214                            None => Autoscroll::newest(),
24215                        };
24216                        let nav_history = editor.nav_history.take();
24217                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24218                        let Some((&excerpt_id, _, buffer_snapshot)) =
24219                            multibuffer_snapshot.as_singleton()
24220                        else {
24221                            return;
24222                        };
24223                        editor.change_selections(
24224                            SelectionEffects::scroll(autoscroll),
24225                            window,
24226                            cx,
24227                            |s| {
24228                                s.select_ranges(ranges.into_iter().map(|range| {
24229                                    let range = buffer_snapshot.anchor_before(range.start)
24230                                        ..buffer_snapshot.anchor_after(range.end);
24231                                    multibuffer_snapshot
24232                                        .anchor_range_in_excerpt(excerpt_id, range)
24233                                        .unwrap()
24234                                }));
24235                            },
24236                        );
24237                        editor.nav_history = nav_history;
24238                    });
24239                }
24240            })
24241        });
24242    }
24243
24244    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24245        let snapshot = self.buffer.read(cx).read(cx);
24246        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
24247        Some(
24248            ranges
24249                .iter()
24250                .map(move |range| {
24251                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24252                })
24253                .collect(),
24254        )
24255    }
24256
24257    fn selection_replacement_ranges(
24258        &self,
24259        range: Range<MultiBufferOffsetUtf16>,
24260        cx: &mut App,
24261    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24262        let selections = self
24263            .selections
24264            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24265        let newest_selection = selections
24266            .iter()
24267            .max_by_key(|selection| selection.id)
24268            .unwrap();
24269        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24270        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24271        let snapshot = self.buffer.read(cx).read(cx);
24272        selections
24273            .into_iter()
24274            .map(|mut selection| {
24275                selection.start.0.0 =
24276                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24277                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24278                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24279                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24280            })
24281            .collect()
24282    }
24283
24284    fn report_editor_event(
24285        &self,
24286        reported_event: ReportEditorEvent,
24287        file_extension: Option<String>,
24288        cx: &App,
24289    ) {
24290        if cfg!(any(test, feature = "test-support")) {
24291            return;
24292        }
24293
24294        let Some(project) = &self.project else { return };
24295
24296        // If None, we are in a file without an extension
24297        let file = self
24298            .buffer
24299            .read(cx)
24300            .as_singleton()
24301            .and_then(|b| b.read(cx).file());
24302        let file_extension = file_extension.or(file
24303            .as_ref()
24304            .and_then(|file| Path::new(file.file_name(cx)).extension())
24305            .and_then(|e| e.to_str())
24306            .map(|a| a.to_string()));
24307
24308        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24309            .map(|vim_mode| vim_mode.0)
24310            .unwrap_or(false);
24311
24312        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24313        let copilot_enabled = edit_predictions_provider
24314            == language::language_settings::EditPredictionProvider::Copilot;
24315        let copilot_enabled_for_language = self
24316            .buffer
24317            .read(cx)
24318            .language_settings(cx)
24319            .show_edit_predictions;
24320
24321        let project = project.read(cx);
24322        let event_type = reported_event.event_type();
24323
24324        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24325            telemetry::event!(
24326                event_type,
24327                type = if auto_saved {"autosave"} else {"manual"},
24328                file_extension,
24329                vim_mode,
24330                copilot_enabled,
24331                copilot_enabled_for_language,
24332                edit_predictions_provider,
24333                is_via_ssh = project.is_via_remote_server(),
24334            );
24335        } else {
24336            telemetry::event!(
24337                event_type,
24338                file_extension,
24339                vim_mode,
24340                copilot_enabled,
24341                copilot_enabled_for_language,
24342                edit_predictions_provider,
24343                is_via_ssh = project.is_via_remote_server(),
24344            );
24345        };
24346    }
24347
24348    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24349    /// with each line being an array of {text, highlight} objects.
24350    fn copy_highlight_json(
24351        &mut self,
24352        _: &CopyHighlightJson,
24353        window: &mut Window,
24354        cx: &mut Context<Self>,
24355    ) {
24356        #[derive(Serialize)]
24357        struct Chunk<'a> {
24358            text: String,
24359            highlight: Option<&'a str>,
24360        }
24361
24362        let snapshot = self.buffer.read(cx).snapshot(cx);
24363        let range = self
24364            .selected_text_range(false, window, cx)
24365            .and_then(|selection| {
24366                if selection.range.is_empty() {
24367                    None
24368                } else {
24369                    Some(
24370                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24371                            selection.range.start,
24372                        )))
24373                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24374                                selection.range.end,
24375                            ))),
24376                    )
24377                }
24378            })
24379            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
24380
24381        let chunks = snapshot.chunks(range, true);
24382        let mut lines = Vec::new();
24383        let mut line: VecDeque<Chunk> = VecDeque::new();
24384
24385        let Some(style) = self.style.as_ref() else {
24386            return;
24387        };
24388
24389        for chunk in chunks {
24390            let highlight = chunk
24391                .syntax_highlight_id
24392                .and_then(|id| id.name(&style.syntax));
24393            let mut chunk_lines = chunk.text.split('\n').peekable();
24394            while let Some(text) = chunk_lines.next() {
24395                let mut merged_with_last_token = false;
24396                if let Some(last_token) = line.back_mut()
24397                    && last_token.highlight == highlight
24398                {
24399                    last_token.text.push_str(text);
24400                    merged_with_last_token = true;
24401                }
24402
24403                if !merged_with_last_token {
24404                    line.push_back(Chunk {
24405                        text: text.into(),
24406                        highlight,
24407                    });
24408                }
24409
24410                if chunk_lines.peek().is_some() {
24411                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
24412                        line.pop_front();
24413                    }
24414                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
24415                        line.pop_back();
24416                    }
24417
24418                    lines.push(mem::take(&mut line));
24419                }
24420            }
24421        }
24422
24423        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
24424            return;
24425        };
24426        cx.write_to_clipboard(ClipboardItem::new_string(lines));
24427    }
24428
24429    pub fn open_context_menu(
24430        &mut self,
24431        _: &OpenContextMenu,
24432        window: &mut Window,
24433        cx: &mut Context<Self>,
24434    ) {
24435        self.request_autoscroll(Autoscroll::newest(), cx);
24436        let position = self
24437            .selections
24438            .newest_display(&self.display_snapshot(cx))
24439            .start;
24440        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
24441    }
24442
24443    pub fn replay_insert_event(
24444        &mut self,
24445        text: &str,
24446        relative_utf16_range: Option<Range<isize>>,
24447        window: &mut Window,
24448        cx: &mut Context<Self>,
24449    ) {
24450        if !self.input_enabled {
24451            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24452            return;
24453        }
24454        if let Some(relative_utf16_range) = relative_utf16_range {
24455            let selections = self
24456                .selections
24457                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24458            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24459                let new_ranges = selections.into_iter().map(|range| {
24460                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
24461                        range
24462                            .head()
24463                            .0
24464                            .0
24465                            .saturating_add_signed(relative_utf16_range.start),
24466                    ));
24467                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
24468                        range
24469                            .head()
24470                            .0
24471                            .0
24472                            .saturating_add_signed(relative_utf16_range.end),
24473                    ));
24474                    start..end
24475                });
24476                s.select_ranges(new_ranges);
24477            });
24478        }
24479
24480        self.handle_input(text, window, cx);
24481    }
24482
24483    pub fn is_focused(&self, window: &Window) -> bool {
24484        self.focus_handle.is_focused(window)
24485    }
24486
24487    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24488        cx.emit(EditorEvent::Focused);
24489
24490        if let Some(descendant) = self
24491            .last_focused_descendant
24492            .take()
24493            .and_then(|descendant| descendant.upgrade())
24494        {
24495            window.focus(&descendant, cx);
24496        } else {
24497            if let Some(blame) = self.blame.as_ref() {
24498                blame.update(cx, GitBlame::focus)
24499            }
24500
24501            self.blink_manager.update(cx, BlinkManager::enable);
24502            self.show_cursor_names(window, cx);
24503            self.buffer.update(cx, |buffer, cx| {
24504                buffer.finalize_last_transaction(cx);
24505                if self.leader_id.is_none() {
24506                    buffer.set_active_selections(
24507                        &self.selections.disjoint_anchors_arc(),
24508                        self.selections.line_mode(),
24509                        self.cursor_shape,
24510                        cx,
24511                    );
24512                }
24513            });
24514
24515            if let Some(position_map) = self.last_position_map.clone() {
24516                EditorElement::mouse_moved(
24517                    self,
24518                    &MouseMoveEvent {
24519                        position: window.mouse_position(),
24520                        pressed_button: None,
24521                        modifiers: window.modifiers(),
24522                    },
24523                    &position_map,
24524                    None,
24525                    window,
24526                    cx,
24527                );
24528            }
24529        }
24530    }
24531
24532    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24533        cx.emit(EditorEvent::FocusedIn)
24534    }
24535
24536    fn handle_focus_out(
24537        &mut self,
24538        event: FocusOutEvent,
24539        _window: &mut Window,
24540        cx: &mut Context<Self>,
24541    ) {
24542        if event.blurred != self.focus_handle {
24543            self.last_focused_descendant = Some(event.blurred);
24544        }
24545        self.selection_drag_state = SelectionDragState::None;
24546        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
24547    }
24548
24549    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24550        self.blink_manager.update(cx, BlinkManager::disable);
24551        self.buffer
24552            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
24553
24554        if let Some(blame) = self.blame.as_ref() {
24555            blame.update(cx, GitBlame::blur)
24556        }
24557        if !self.hover_state.focused(window, cx) {
24558            hide_hover(self, cx);
24559        }
24560        if !self
24561            .context_menu
24562            .borrow()
24563            .as_ref()
24564            .is_some_and(|context_menu| context_menu.focused(window, cx))
24565        {
24566            self.hide_context_menu(window, cx);
24567        }
24568        self.take_active_edit_prediction(cx);
24569        cx.emit(EditorEvent::Blurred);
24570        cx.notify();
24571    }
24572
24573    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24574        let mut pending: String = window
24575            .pending_input_keystrokes()
24576            .into_iter()
24577            .flatten()
24578            .filter_map(|keystroke| keystroke.key_char.clone())
24579            .collect();
24580
24581        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
24582            pending = "".to_string();
24583        }
24584
24585        let existing_pending = self
24586            .text_highlights::<PendingInput>(cx)
24587            .map(|(_, ranges)| ranges.to_vec());
24588        if existing_pending.is_none() && pending.is_empty() {
24589            return;
24590        }
24591        let transaction =
24592            self.transact(window, cx, |this, window, cx| {
24593                let selections = this
24594                    .selections
24595                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
24596                let edits = selections
24597                    .iter()
24598                    .map(|selection| (selection.end..selection.end, pending.clone()));
24599                this.edit(edits, cx);
24600                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24601                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
24602                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
24603                    }));
24604                });
24605                if let Some(existing_ranges) = existing_pending {
24606                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
24607                    this.edit(edits, cx);
24608                }
24609            });
24610
24611        let snapshot = self.snapshot(window, cx);
24612        let ranges = self
24613            .selections
24614            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
24615            .into_iter()
24616            .map(|selection| {
24617                snapshot.buffer_snapshot().anchor_after(selection.end)
24618                    ..snapshot
24619                        .buffer_snapshot()
24620                        .anchor_before(selection.end + pending.len())
24621            })
24622            .collect();
24623
24624        if pending.is_empty() {
24625            self.clear_highlights::<PendingInput>(cx);
24626        } else {
24627            self.highlight_text::<PendingInput>(
24628                ranges,
24629                HighlightStyle {
24630                    underline: Some(UnderlineStyle {
24631                        thickness: px(1.),
24632                        color: None,
24633                        wavy: false,
24634                    }),
24635                    ..Default::default()
24636                },
24637                cx,
24638            );
24639        }
24640
24641        self.ime_transaction = self.ime_transaction.or(transaction);
24642        if let Some(transaction) = self.ime_transaction {
24643            self.buffer.update(cx, |buffer, cx| {
24644                buffer.group_until_transaction(transaction, cx);
24645            });
24646        }
24647
24648        if self.text_highlights::<PendingInput>(cx).is_none() {
24649            self.ime_transaction.take();
24650        }
24651    }
24652
24653    pub fn register_action_renderer(
24654        &mut self,
24655        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
24656    ) -> Subscription {
24657        let id = self.next_editor_action_id.post_inc();
24658        self.editor_actions
24659            .borrow_mut()
24660            .insert(id, Box::new(listener));
24661
24662        let editor_actions = self.editor_actions.clone();
24663        Subscription::new(move || {
24664            editor_actions.borrow_mut().remove(&id);
24665        })
24666    }
24667
24668    pub fn register_action<A: Action>(
24669        &mut self,
24670        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
24671    ) -> Subscription {
24672        let id = self.next_editor_action_id.post_inc();
24673        let listener = Arc::new(listener);
24674        self.editor_actions.borrow_mut().insert(
24675            id,
24676            Box::new(move |_, window, _| {
24677                let listener = listener.clone();
24678                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
24679                    let action = action.downcast_ref().unwrap();
24680                    if phase == DispatchPhase::Bubble {
24681                        listener(action, window, cx)
24682                    }
24683                })
24684            }),
24685        );
24686
24687        let editor_actions = self.editor_actions.clone();
24688        Subscription::new(move || {
24689            editor_actions.borrow_mut().remove(&id);
24690        })
24691    }
24692
24693    pub fn file_header_size(&self) -> u32 {
24694        FILE_HEADER_HEIGHT
24695    }
24696
24697    pub fn restore(
24698        &mut self,
24699        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
24700        window: &mut Window,
24701        cx: &mut Context<Self>,
24702    ) {
24703        self.buffer().update(cx, |multi_buffer, cx| {
24704            for (buffer_id, changes) in revert_changes {
24705                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
24706                    buffer.update(cx, |buffer, cx| {
24707                        buffer.edit(
24708                            changes
24709                                .into_iter()
24710                                .map(|(range, text)| (range, text.to_string())),
24711                            None,
24712                            cx,
24713                        );
24714                    });
24715                }
24716            }
24717        });
24718        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24719            selections.refresh()
24720        });
24721    }
24722
24723    pub fn to_pixel_point(
24724        &mut self,
24725        source: multi_buffer::Anchor,
24726        editor_snapshot: &EditorSnapshot,
24727        window: &mut Window,
24728        cx: &App,
24729    ) -> Option<gpui::Point<Pixels>> {
24730        let source_point = source.to_display_point(editor_snapshot);
24731        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
24732    }
24733
24734    pub fn display_to_pixel_point(
24735        &mut self,
24736        source: DisplayPoint,
24737        editor_snapshot: &EditorSnapshot,
24738        window: &mut Window,
24739        cx: &App,
24740    ) -> Option<gpui::Point<Pixels>> {
24741        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
24742        let text_layout_details = self.text_layout_details(window);
24743        let scroll_top = text_layout_details
24744            .scroll_anchor
24745            .scroll_position(editor_snapshot)
24746            .y;
24747
24748        if source.row().as_f64() < scroll_top.floor() {
24749            return None;
24750        }
24751        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
24752        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
24753        Some(gpui::Point::new(source_x, source_y))
24754    }
24755
24756    pub fn has_visible_completions_menu(&self) -> bool {
24757        !self.edit_prediction_preview_is_active()
24758            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
24759                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
24760            })
24761    }
24762
24763    pub fn register_addon<T: Addon>(&mut self, instance: T) {
24764        if self.mode.is_minimap() {
24765            return;
24766        }
24767        self.addons
24768            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
24769    }
24770
24771    pub fn unregister_addon<T: Addon>(&mut self) {
24772        self.addons.remove(&std::any::TypeId::of::<T>());
24773    }
24774
24775    pub fn addon<T: Addon>(&self) -> Option<&T> {
24776        let type_id = std::any::TypeId::of::<T>();
24777        self.addons
24778            .get(&type_id)
24779            .and_then(|item| item.to_any().downcast_ref::<T>())
24780    }
24781
24782    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
24783        let type_id = std::any::TypeId::of::<T>();
24784        self.addons
24785            .get_mut(&type_id)
24786            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
24787    }
24788
24789    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
24790        let text_layout_details = self.text_layout_details(window);
24791        let style = &text_layout_details.editor_style;
24792        let font_id = window.text_system().resolve_font(&style.text.font());
24793        let font_size = style.text.font_size.to_pixels(window.rem_size());
24794        let line_height = style.text.line_height_in_pixels(window.rem_size());
24795        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
24796        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
24797
24798        CharacterDimensions {
24799            em_width,
24800            em_advance,
24801            line_height,
24802        }
24803    }
24804
24805    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
24806        self.load_diff_task.clone()
24807    }
24808
24809    fn read_metadata_from_db(
24810        &mut self,
24811        item_id: u64,
24812        workspace_id: WorkspaceId,
24813        window: &mut Window,
24814        cx: &mut Context<Editor>,
24815    ) {
24816        if self.buffer_kind(cx) == ItemBufferKind::Singleton
24817            && !self.mode.is_minimap()
24818            && WorkspaceSettings::get(None, cx).restore_on_startup
24819                != RestoreOnStartupBehavior::EmptyTab
24820        {
24821            let buffer_snapshot = OnceCell::new();
24822
24823            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
24824                && !folds.is_empty()
24825            {
24826                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24827                let snapshot_len = snapshot.len().0;
24828
24829                // Helper: search for fingerprint in buffer, return offset if found
24830                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
24831                    // Ensure we start at a character boundary (defensive)
24832                    let search_start = snapshot
24833                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
24834                        .0;
24835                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
24836
24837                    let mut byte_offset = search_start;
24838                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
24839                        if byte_offset > search_end {
24840                            break;
24841                        }
24842                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
24843                            return Some(byte_offset);
24844                        }
24845                        byte_offset += ch.len_utf8();
24846                    }
24847                    None
24848                };
24849
24850                // Track search position to handle duplicate fingerprints correctly.
24851                // Folds are stored in document order, so we advance after each match.
24852                let mut search_start = 0usize;
24853
24854                let valid_folds: Vec<_> = folds
24855                    .into_iter()
24856                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
24857                        // Skip folds without fingerprints (old data before migration)
24858                        let sfp = start_fp?;
24859                        let efp = end_fp?;
24860                        let efp_len = efp.len();
24861
24862                        // Fast path: check if fingerprints match at stored offsets
24863                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
24864                        let start_matches = stored_start < snapshot_len
24865                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
24866                        let efp_check_pos = stored_end.saturating_sub(efp_len);
24867                        let end_matches = efp_check_pos >= stored_start
24868                            && stored_end <= snapshot_len
24869                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
24870
24871                        let (new_start, new_end) = if start_matches && end_matches {
24872                            // Offsets unchanged, use stored values
24873                            (stored_start, stored_end)
24874                        } else if sfp == efp {
24875                            // Short fold: identical fingerprints can only match once per search
24876                            // Use stored fold length to compute new_end
24877                            let new_start = find_fingerprint(&sfp, search_start)?;
24878                            let fold_len = stored_end - stored_start;
24879                            let new_end = new_start + fold_len;
24880                            (new_start, new_end)
24881                        } else {
24882                            // Slow path: search for fingerprints in buffer
24883                            let new_start = find_fingerprint(&sfp, search_start)?;
24884                            // Search for end_fp after start, then add efp_len to get actual fold end
24885                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
24886                            let new_end = efp_pos + efp_len;
24887                            (new_start, new_end)
24888                        };
24889
24890                        // Advance search position for next fold
24891                        search_start = new_end;
24892
24893                        // Validate fold makes sense (end must be after start)
24894                        if new_end <= new_start {
24895                            return None;
24896                        }
24897
24898                        Some(
24899                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
24900                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
24901                        )
24902                    })
24903                    .collect();
24904
24905                if !valid_folds.is_empty() {
24906                    self.fold_ranges(valid_folds, false, window, cx);
24907
24908                    // Migrate folds to current entity_id before workspace cleanup runs.
24909                    // Entity IDs change between sessions, but workspace cleanup deletes
24910                    // old editor rows (cascading to folds) based on current entity IDs.
24911                    let new_editor_id = cx.entity().entity_id().as_u64() as ItemId;
24912                    if new_editor_id != item_id {
24913                        cx.spawn(async move |_, _| {
24914                            DB.migrate_editor_folds(item_id, new_editor_id, workspace_id)
24915                                .await
24916                                .log_err();
24917                        })
24918                        .detach();
24919                    }
24920                }
24921            }
24922
24923            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
24924                && !selections.is_empty()
24925            {
24926                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
24927                // skip adding the initial selection to selection history
24928                self.selection_history.mode = SelectionHistoryMode::Skipping;
24929                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24930                    s.select_ranges(selections.into_iter().map(|(start, end)| {
24931                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
24932                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
24933                    }));
24934                });
24935                self.selection_history.mode = SelectionHistoryMode::Normal;
24936            };
24937        }
24938
24939        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
24940    }
24941
24942    fn update_lsp_data(
24943        &mut self,
24944        for_buffer: Option<BufferId>,
24945        window: &mut Window,
24946        cx: &mut Context<'_, Self>,
24947    ) {
24948        if let Some(buffer_id) = for_buffer {
24949            self.pull_diagnostics(buffer_id, window, cx);
24950        }
24951        self.refresh_colors_for_visible_range(for_buffer, window, cx);
24952    }
24953
24954    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
24955        if self.ignore_lsp_data() {
24956            return;
24957        }
24958        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
24959            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
24960        }
24961    }
24962
24963    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
24964        if self.ignore_lsp_data() {
24965            return;
24966        }
24967
24968        if !self.registered_buffers.contains_key(&buffer_id)
24969            && let Some(project) = self.project.as_ref()
24970        {
24971            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
24972                project.update(cx, |project, cx| {
24973                    self.registered_buffers.insert(
24974                        buffer_id,
24975                        project.register_buffer_with_language_servers(&buffer, cx),
24976                    );
24977                });
24978            } else {
24979                self.registered_buffers.remove(&buffer_id);
24980            }
24981        }
24982    }
24983
24984    fn ignore_lsp_data(&self) -> bool {
24985        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
24986        // skip any LSP updates for it.
24987        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
24988    }
24989
24990    pub(crate) fn create_style(&self, cx: &App) -> EditorStyle {
24991        let settings = ThemeSettings::get_global(cx);
24992
24993        let mut text_style = match self.mode {
24994            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24995                color: cx.theme().colors().editor_foreground,
24996                font_family: settings.ui_font.family.clone(),
24997                font_features: settings.ui_font.features.clone(),
24998                font_fallbacks: settings.ui_font.fallbacks.clone(),
24999                font_size: rems(0.875).into(),
25000                font_weight: settings.ui_font.weight,
25001                line_height: relative(settings.buffer_line_height.value()),
25002                ..Default::default()
25003            },
25004            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25005                color: cx.theme().colors().editor_foreground,
25006                font_family: settings.buffer_font.family.clone(),
25007                font_features: settings.buffer_font.features.clone(),
25008                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25009                font_size: settings.buffer_font_size(cx).into(),
25010                font_weight: settings.buffer_font.weight,
25011                line_height: relative(settings.buffer_line_height.value()),
25012                ..Default::default()
25013            },
25014        };
25015        if let Some(text_style_refinement) = &self.text_style_refinement {
25016            text_style.refine(text_style_refinement)
25017        }
25018
25019        let background = match self.mode {
25020            EditorMode::SingleLine => cx.theme().system().transparent,
25021            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25022            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25023            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25024        };
25025
25026        EditorStyle {
25027            background,
25028            border: cx.theme().colors().border,
25029            local_player: cx.theme().players().local(),
25030            text: text_style,
25031            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25032            syntax: cx.theme().syntax().clone(),
25033            status: cx.theme().status().clone(),
25034            inlay_hints_style: make_inlay_hints_style(cx),
25035            edit_prediction_styles: make_suggestion_styles(cx),
25036            unnecessary_code_fade: settings.unnecessary_code_fade,
25037            show_underlines: self.diagnostics_enabled(),
25038        }
25039    }
25040    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
25041        let cursor = self.selections.newest_anchor().head();
25042        let multibuffer = self.buffer().read(cx);
25043        let is_singleton = multibuffer.is_singleton();
25044        let (buffer_id, symbols) = multibuffer
25045            .read(cx)
25046            .symbols_containing(cursor, Some(variant.syntax()))?;
25047        let buffer = multibuffer.buffer(buffer_id)?;
25048
25049        let buffer = buffer.read(cx);
25050        let settings = ThemeSettings::get_global(cx);
25051        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25052        let mut breadcrumbs = if is_singleton {
25053            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25054                buffer
25055                    .snapshot()
25056                    .resolve_file_path(
25057                        self.project
25058                            .as_ref()
25059                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25060                            .unwrap_or_default(),
25061                        cx,
25062                    )
25063                    .unwrap_or_else(|| {
25064                        if multibuffer.is_singleton() {
25065                            multibuffer.title(cx).to_string()
25066                        } else {
25067                            "untitled".to_string()
25068                        }
25069                    })
25070            });
25071            vec![BreadcrumbText {
25072                text,
25073                highlights: None,
25074                font: Some(settings.buffer_font.clone()),
25075            }]
25076        } else {
25077            vec![]
25078        };
25079
25080        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
25081            text: symbol.text,
25082            highlights: Some(symbol.highlight_ranges),
25083            font: Some(settings.buffer_font.clone()),
25084        }));
25085        Some(breadcrumbs)
25086    }
25087}
25088
25089fn edit_for_markdown_paste<'a>(
25090    buffer: &MultiBufferSnapshot,
25091    range: Range<MultiBufferOffset>,
25092    to_insert: &'a str,
25093    url: Option<url::Url>,
25094) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25095    if url.is_none() {
25096        return (range, Cow::Borrowed(to_insert));
25097    };
25098
25099    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25100
25101    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25102        Cow::Borrowed(to_insert)
25103    } else {
25104        Cow::Owned(format!("[{old_text}]({to_insert})"))
25105    };
25106    (range, new_text)
25107}
25108
25109fn process_completion_for_edit(
25110    completion: &Completion,
25111    intent: CompletionIntent,
25112    buffer: &Entity<Buffer>,
25113    cursor_position: &text::Anchor,
25114    cx: &mut Context<Editor>,
25115) -> CompletionEdit {
25116    let buffer = buffer.read(cx);
25117    let buffer_snapshot = buffer.snapshot();
25118    let (snippet, new_text) = if completion.is_snippet() {
25119        let mut snippet_source = completion.new_text.clone();
25120        // Workaround for typescript language server issues so that methods don't expand within
25121        // strings and functions with type expressions. The previous point is used because the query
25122        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25123        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25124        let previous_point = if previous_point.column > 0 {
25125            cursor_position.to_previous_offset(&buffer_snapshot)
25126        } else {
25127            cursor_position.to_offset(&buffer_snapshot)
25128        };
25129        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25130            && scope.prefers_label_for_snippet_in_completion()
25131            && let Some(label) = completion.label()
25132            && matches!(
25133                completion.kind(),
25134                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25135            )
25136        {
25137            snippet_source = label;
25138        }
25139        match Snippet::parse(&snippet_source).log_err() {
25140            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25141            None => (None, completion.new_text.clone()),
25142        }
25143    } else {
25144        (None, completion.new_text.clone())
25145    };
25146
25147    let mut range_to_replace = {
25148        let replace_range = &completion.replace_range;
25149        if let CompletionSource::Lsp {
25150            insert_range: Some(insert_range),
25151            ..
25152        } = &completion.source
25153        {
25154            debug_assert_eq!(
25155                insert_range.start, replace_range.start,
25156                "insert_range and replace_range should start at the same position"
25157            );
25158            debug_assert!(
25159                insert_range
25160                    .start
25161                    .cmp(cursor_position, &buffer_snapshot)
25162                    .is_le(),
25163                "insert_range should start before or at cursor position"
25164            );
25165            debug_assert!(
25166                replace_range
25167                    .start
25168                    .cmp(cursor_position, &buffer_snapshot)
25169                    .is_le(),
25170                "replace_range should start before or at cursor position"
25171            );
25172
25173            let should_replace = match intent {
25174                CompletionIntent::CompleteWithInsert => false,
25175                CompletionIntent::CompleteWithReplace => true,
25176                CompletionIntent::Complete | CompletionIntent::Compose => {
25177                    let insert_mode =
25178                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
25179                            .completions
25180                            .lsp_insert_mode;
25181                    match insert_mode {
25182                        LspInsertMode::Insert => false,
25183                        LspInsertMode::Replace => true,
25184                        LspInsertMode::ReplaceSubsequence => {
25185                            let mut text_to_replace = buffer.chars_for_range(
25186                                buffer.anchor_before(replace_range.start)
25187                                    ..buffer.anchor_after(replace_range.end),
25188                            );
25189                            let mut current_needle = text_to_replace.next();
25190                            for haystack_ch in completion.label.text.chars() {
25191                                if let Some(needle_ch) = current_needle
25192                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25193                                {
25194                                    current_needle = text_to_replace.next();
25195                                }
25196                            }
25197                            current_needle.is_none()
25198                        }
25199                        LspInsertMode::ReplaceSuffix => {
25200                            if replace_range
25201                                .end
25202                                .cmp(cursor_position, &buffer_snapshot)
25203                                .is_gt()
25204                            {
25205                                let range_after_cursor = *cursor_position..replace_range.end;
25206                                let text_after_cursor = buffer
25207                                    .text_for_range(
25208                                        buffer.anchor_before(range_after_cursor.start)
25209                                            ..buffer.anchor_after(range_after_cursor.end),
25210                                    )
25211                                    .collect::<String>()
25212                                    .to_ascii_lowercase();
25213                                completion
25214                                    .label
25215                                    .text
25216                                    .to_ascii_lowercase()
25217                                    .ends_with(&text_after_cursor)
25218                            } else {
25219                                true
25220                            }
25221                        }
25222                    }
25223                }
25224            };
25225
25226            if should_replace {
25227                replace_range.clone()
25228            } else {
25229                insert_range.clone()
25230            }
25231        } else {
25232            replace_range.clone()
25233        }
25234    };
25235
25236    if range_to_replace
25237        .end
25238        .cmp(cursor_position, &buffer_snapshot)
25239        .is_lt()
25240    {
25241        range_to_replace.end = *cursor_position;
25242    }
25243
25244    let replace_range = range_to_replace.to_offset(buffer);
25245    CompletionEdit {
25246        new_text,
25247        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
25248        snippet,
25249    }
25250}
25251
25252struct CompletionEdit {
25253    new_text: String,
25254    replace_range: Range<BufferOffset>,
25255    snippet: Option<Snippet>,
25256}
25257
25258fn comment_delimiter_for_newline(
25259    start_point: &Point,
25260    buffer: &MultiBufferSnapshot,
25261    language: &LanguageScope,
25262) -> Option<Arc<str>> {
25263    let delimiters = language.line_comment_prefixes();
25264    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
25265    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25266
25267    let num_of_whitespaces = snapshot
25268        .chars_for_range(range.clone())
25269        .take_while(|c| c.is_whitespace())
25270        .count();
25271    let comment_candidate = snapshot
25272        .chars_for_range(range.clone())
25273        .skip(num_of_whitespaces)
25274        .take(max_len_of_delimiter)
25275        .collect::<String>();
25276    let (delimiter, trimmed_len) = delimiters
25277        .iter()
25278        .filter_map(|delimiter| {
25279            let prefix = delimiter.trim_end();
25280            if comment_candidate.starts_with(prefix) {
25281                Some((delimiter, prefix.len()))
25282            } else {
25283                None
25284            }
25285        })
25286        .max_by_key(|(_, len)| *len)?;
25287
25288    if let Some(BlockCommentConfig {
25289        start: block_start, ..
25290    }) = language.block_comment()
25291    {
25292        let block_start_trimmed = block_start.trim_end();
25293        if block_start_trimmed.starts_with(delimiter.trim_end()) {
25294            let line_content = snapshot
25295                .chars_for_range(range)
25296                .skip(num_of_whitespaces)
25297                .take(block_start_trimmed.len())
25298                .collect::<String>();
25299
25300            if line_content.starts_with(block_start_trimmed) {
25301                return None;
25302            }
25303        }
25304    }
25305
25306    let cursor_is_placed_after_comment_marker =
25307        num_of_whitespaces + trimmed_len <= start_point.column as usize;
25308    if cursor_is_placed_after_comment_marker {
25309        Some(delimiter.clone())
25310    } else {
25311        None
25312    }
25313}
25314
25315fn documentation_delimiter_for_newline(
25316    start_point: &Point,
25317    buffer: &MultiBufferSnapshot,
25318    language: &LanguageScope,
25319    newline_config: &mut NewlineConfig,
25320) -> Option<Arc<str>> {
25321    let BlockCommentConfig {
25322        start: start_tag,
25323        end: end_tag,
25324        prefix: delimiter,
25325        tab_size: len,
25326    } = language.documentation_comment()?;
25327    let is_within_block_comment = buffer
25328        .language_scope_at(*start_point)
25329        .is_some_and(|scope| scope.override_name() == Some("comment"));
25330    if !is_within_block_comment {
25331        return None;
25332    }
25333
25334    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25335
25336    let num_of_whitespaces = snapshot
25337        .chars_for_range(range.clone())
25338        .take_while(|c| c.is_whitespace())
25339        .count();
25340
25341    // 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.
25342    let column = start_point.column;
25343    let cursor_is_after_start_tag = {
25344        let start_tag_len = start_tag.len();
25345        let start_tag_line = snapshot
25346            .chars_for_range(range.clone())
25347            .skip(num_of_whitespaces)
25348            .take(start_tag_len)
25349            .collect::<String>();
25350        if start_tag_line.starts_with(start_tag.as_ref()) {
25351            num_of_whitespaces + start_tag_len <= column as usize
25352        } else {
25353            false
25354        }
25355    };
25356
25357    let cursor_is_after_delimiter = {
25358        let delimiter_trim = delimiter.trim_end();
25359        let delimiter_line = snapshot
25360            .chars_for_range(range.clone())
25361            .skip(num_of_whitespaces)
25362            .take(delimiter_trim.len())
25363            .collect::<String>();
25364        if delimiter_line.starts_with(delimiter_trim) {
25365            num_of_whitespaces + delimiter_trim.len() <= column as usize
25366        } else {
25367            false
25368        }
25369    };
25370
25371    let mut needs_extra_line = false;
25372    let mut extra_line_additional_indent = IndentSize::spaces(0);
25373
25374    let cursor_is_before_end_tag_if_exists = {
25375        let mut char_position = 0u32;
25376        let mut end_tag_offset = None;
25377
25378        'outer: for chunk in snapshot.text_for_range(range) {
25379            if let Some(byte_pos) = chunk.find(&**end_tag) {
25380                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
25381                end_tag_offset = Some(char_position + chars_before_match);
25382                break 'outer;
25383            }
25384            char_position += chunk.chars().count() as u32;
25385        }
25386
25387        if let Some(end_tag_offset) = end_tag_offset {
25388            let cursor_is_before_end_tag = column <= end_tag_offset;
25389            if cursor_is_after_start_tag {
25390                if cursor_is_before_end_tag {
25391                    needs_extra_line = true;
25392                }
25393                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
25394                if cursor_is_at_start_of_end_tag {
25395                    extra_line_additional_indent.len = *len;
25396                }
25397            }
25398            cursor_is_before_end_tag
25399        } else {
25400            true
25401        }
25402    };
25403
25404    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
25405        && cursor_is_before_end_tag_if_exists
25406    {
25407        let additional_indent = if cursor_is_after_start_tag {
25408            IndentSize::spaces(*len)
25409        } else {
25410            IndentSize::spaces(0)
25411        };
25412
25413        *newline_config = NewlineConfig::Newline {
25414            additional_indent,
25415            extra_line_additional_indent: if needs_extra_line {
25416                Some(extra_line_additional_indent)
25417            } else {
25418                None
25419            },
25420            prevent_auto_indent: true,
25421        };
25422        Some(delimiter.clone())
25423    } else {
25424        None
25425    }
25426}
25427
25428const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
25429
25430fn list_delimiter_for_newline(
25431    start_point: &Point,
25432    buffer: &MultiBufferSnapshot,
25433    language: &LanguageScope,
25434    newline_config: &mut NewlineConfig,
25435) -> Option<Arc<str>> {
25436    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25437
25438    let num_of_whitespaces = snapshot
25439        .chars_for_range(range.clone())
25440        .take_while(|c| c.is_whitespace())
25441        .count();
25442
25443    let task_list_entries: Vec<_> = language
25444        .task_list()
25445        .into_iter()
25446        .flat_map(|config| {
25447            config
25448                .prefixes
25449                .iter()
25450                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
25451        })
25452        .collect();
25453    let unordered_list_entries: Vec<_> = language
25454        .unordered_list()
25455        .iter()
25456        .map(|marker| (marker.as_ref(), marker.as_ref()))
25457        .collect();
25458
25459    let all_entries: Vec<_> = task_list_entries
25460        .into_iter()
25461        .chain(unordered_list_entries)
25462        .collect();
25463
25464    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
25465        let candidate: String = snapshot
25466            .chars_for_range(range.clone())
25467            .skip(num_of_whitespaces)
25468            .take(max_prefix_len)
25469            .collect();
25470
25471        if let Some((prefix, continuation)) = all_entries
25472            .iter()
25473            .filter(|(prefix, _)| candidate.starts_with(*prefix))
25474            .max_by_key(|(prefix, _)| prefix.len())
25475        {
25476            let end_of_prefix = num_of_whitespaces + prefix.len();
25477            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25478            let has_content_after_marker = snapshot
25479                .chars_for_range(range)
25480                .skip(end_of_prefix)
25481                .any(|c| !c.is_whitespace());
25482
25483            if has_content_after_marker && cursor_is_after_prefix {
25484                return Some((*continuation).into());
25485            }
25486
25487            if start_point.column as usize == end_of_prefix {
25488                if num_of_whitespaces == 0 {
25489                    *newline_config = NewlineConfig::ClearCurrentLine;
25490                } else {
25491                    *newline_config = NewlineConfig::UnindentCurrentLine {
25492                        continuation: (*continuation).into(),
25493                    };
25494                }
25495            }
25496
25497            return None;
25498        }
25499    }
25500
25501    let candidate: String = snapshot
25502        .chars_for_range(range.clone())
25503        .skip(num_of_whitespaces)
25504        .take(ORDERED_LIST_MAX_MARKER_LEN)
25505        .collect();
25506
25507    for ordered_config in language.ordered_list() {
25508        let regex = match Regex::new(&ordered_config.pattern) {
25509            Ok(r) => r,
25510            Err(_) => continue,
25511        };
25512
25513        if let Some(captures) = regex.captures(&candidate) {
25514            let full_match = captures.get(0)?;
25515            let marker_len = full_match.len();
25516            let end_of_prefix = num_of_whitespaces + marker_len;
25517            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25518
25519            let has_content_after_marker = snapshot
25520                .chars_for_range(range)
25521                .skip(end_of_prefix)
25522                .any(|c| !c.is_whitespace());
25523
25524            if has_content_after_marker && cursor_is_after_prefix {
25525                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
25526                let continuation = ordered_config
25527                    .format
25528                    .replace("{1}", &(number + 1).to_string());
25529                return Some(continuation.into());
25530            }
25531
25532            if start_point.column as usize == end_of_prefix {
25533                let continuation = ordered_config.format.replace("{1}", "1");
25534                if num_of_whitespaces == 0 {
25535                    *newline_config = NewlineConfig::ClearCurrentLine;
25536                } else {
25537                    *newline_config = NewlineConfig::UnindentCurrentLine {
25538                        continuation: continuation.into(),
25539                    };
25540                }
25541            }
25542
25543            return None;
25544        }
25545    }
25546
25547    None
25548}
25549
25550fn is_list_prefix_row(
25551    row: MultiBufferRow,
25552    buffer: &MultiBufferSnapshot,
25553    language: &LanguageScope,
25554) -> bool {
25555    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
25556        return false;
25557    };
25558
25559    let num_of_whitespaces = snapshot
25560        .chars_for_range(range.clone())
25561        .take_while(|c| c.is_whitespace())
25562        .count();
25563
25564    let task_list_prefixes: Vec<_> = language
25565        .task_list()
25566        .into_iter()
25567        .flat_map(|config| {
25568            config
25569                .prefixes
25570                .iter()
25571                .map(|p| p.as_ref())
25572                .collect::<Vec<_>>()
25573        })
25574        .collect();
25575    let unordered_list_markers: Vec<_> = language
25576        .unordered_list()
25577        .iter()
25578        .map(|marker| marker.as_ref())
25579        .collect();
25580    let all_prefixes: Vec<_> = task_list_prefixes
25581        .into_iter()
25582        .chain(unordered_list_markers)
25583        .collect();
25584    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
25585        let candidate: String = snapshot
25586            .chars_for_range(range.clone())
25587            .skip(num_of_whitespaces)
25588            .take(max_prefix_len)
25589            .collect();
25590        if all_prefixes
25591            .iter()
25592            .any(|prefix| candidate.starts_with(*prefix))
25593        {
25594            return true;
25595        }
25596    }
25597
25598    let ordered_list_candidate: String = snapshot
25599        .chars_for_range(range)
25600        .skip(num_of_whitespaces)
25601        .take(ORDERED_LIST_MAX_MARKER_LEN)
25602        .collect();
25603    for ordered_config in language.ordered_list() {
25604        let regex = match Regex::new(&ordered_config.pattern) {
25605            Ok(r) => r,
25606            Err(_) => continue,
25607        };
25608        if let Some(captures) = regex.captures(&ordered_list_candidate) {
25609            return captures.get(0).is_some();
25610        }
25611    }
25612
25613    false
25614}
25615
25616#[derive(Debug)]
25617enum NewlineConfig {
25618    /// Insert newline with optional additional indent and optional extra blank line
25619    Newline {
25620        additional_indent: IndentSize,
25621        extra_line_additional_indent: Option<IndentSize>,
25622        prevent_auto_indent: bool,
25623    },
25624    /// Clear the current line
25625    ClearCurrentLine,
25626    /// Unindent the current line and add continuation
25627    UnindentCurrentLine { continuation: Arc<str> },
25628}
25629
25630impl NewlineConfig {
25631    fn has_extra_line(&self) -> bool {
25632        matches!(
25633            self,
25634            Self::Newline {
25635                extra_line_additional_indent: Some(_),
25636                ..
25637            }
25638        )
25639    }
25640
25641    fn insert_extra_newline_brackets(
25642        buffer: &MultiBufferSnapshot,
25643        range: Range<MultiBufferOffset>,
25644        language: &language::LanguageScope,
25645    ) -> bool {
25646        let leading_whitespace_len = buffer
25647            .reversed_chars_at(range.start)
25648            .take_while(|c| c.is_whitespace() && *c != '\n')
25649            .map(|c| c.len_utf8())
25650            .sum::<usize>();
25651        let trailing_whitespace_len = buffer
25652            .chars_at(range.end)
25653            .take_while(|c| c.is_whitespace() && *c != '\n')
25654            .map(|c| c.len_utf8())
25655            .sum::<usize>();
25656        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
25657
25658        language.brackets().any(|(pair, enabled)| {
25659            let pair_start = pair.start.trim_end();
25660            let pair_end = pair.end.trim_start();
25661
25662            enabled
25663                && pair.newline
25664                && buffer.contains_str_at(range.end, pair_end)
25665                && buffer.contains_str_at(
25666                    range.start.saturating_sub_usize(pair_start.len()),
25667                    pair_start,
25668                )
25669        })
25670    }
25671
25672    fn insert_extra_newline_tree_sitter(
25673        buffer: &MultiBufferSnapshot,
25674        range: Range<MultiBufferOffset>,
25675    ) -> bool {
25676        let (buffer, range) = match buffer
25677            .range_to_buffer_ranges(range.start..=range.end)
25678            .as_slice()
25679        {
25680            [(buffer, range, _)] => (*buffer, range.clone()),
25681            _ => return false,
25682        };
25683        let pair = {
25684            let mut result: Option<BracketMatch<usize>> = None;
25685
25686            for pair in buffer
25687                .all_bracket_ranges(range.start.0..range.end.0)
25688                .filter(move |pair| {
25689                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
25690                })
25691            {
25692                let len = pair.close_range.end - pair.open_range.start;
25693
25694                if let Some(existing) = &result {
25695                    let existing_len = existing.close_range.end - existing.open_range.start;
25696                    if len > existing_len {
25697                        continue;
25698                    }
25699                }
25700
25701                result = Some(pair);
25702            }
25703
25704            result
25705        };
25706        let Some(pair) = pair else {
25707            return false;
25708        };
25709        pair.newline_only
25710            && buffer
25711                .chars_for_range(pair.open_range.end..range.start.0)
25712                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
25713                .all(|c| c.is_whitespace() && c != '\n')
25714    }
25715}
25716
25717fn update_uncommitted_diff_for_buffer(
25718    editor: Entity<Editor>,
25719    project: &Entity<Project>,
25720    buffers: impl IntoIterator<Item = Entity<Buffer>>,
25721    buffer: Entity<MultiBuffer>,
25722    cx: &mut App,
25723) -> Task<()> {
25724    let mut tasks = Vec::new();
25725    project.update(cx, |project, cx| {
25726        for buffer in buffers {
25727            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
25728                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
25729            }
25730        }
25731    });
25732    cx.spawn(async move |cx| {
25733        let diffs = future::join_all(tasks).await;
25734        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
25735            return;
25736        }
25737
25738        buffer.update(cx, |buffer, cx| {
25739            for diff in diffs.into_iter().flatten() {
25740                buffer.add_diff(diff, cx);
25741            }
25742        });
25743    })
25744}
25745
25746fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
25747    let tab_size = tab_size.get() as usize;
25748    let mut width = offset;
25749
25750    for ch in text.chars() {
25751        width += if ch == '\t' {
25752            tab_size - (width % tab_size)
25753        } else {
25754            1
25755        };
25756    }
25757
25758    width - offset
25759}
25760
25761#[cfg(test)]
25762mod tests {
25763    use super::*;
25764
25765    #[test]
25766    fn test_string_size_with_expanded_tabs() {
25767        let nz = |val| NonZeroU32::new(val).unwrap();
25768        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
25769        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
25770        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
25771        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
25772        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
25773        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
25774        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
25775        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
25776    }
25777}
25778
25779/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
25780struct WordBreakingTokenizer<'a> {
25781    input: &'a str,
25782}
25783
25784impl<'a> WordBreakingTokenizer<'a> {
25785    fn new(input: &'a str) -> Self {
25786        Self { input }
25787    }
25788}
25789
25790fn is_char_ideographic(ch: char) -> bool {
25791    use unicode_script::Script::*;
25792    use unicode_script::UnicodeScript;
25793    matches!(ch.script(), Han | Tangut | Yi)
25794}
25795
25796fn is_grapheme_ideographic(text: &str) -> bool {
25797    text.chars().any(is_char_ideographic)
25798}
25799
25800fn is_grapheme_whitespace(text: &str) -> bool {
25801    text.chars().any(|x| x.is_whitespace())
25802}
25803
25804fn should_stay_with_preceding_ideograph(text: &str) -> bool {
25805    text.chars()
25806        .next()
25807        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
25808}
25809
25810#[derive(PartialEq, Eq, Debug, Clone, Copy)]
25811enum WordBreakToken<'a> {
25812    Word { token: &'a str, grapheme_len: usize },
25813    InlineWhitespace { token: &'a str, grapheme_len: usize },
25814    Newline,
25815}
25816
25817impl<'a> Iterator for WordBreakingTokenizer<'a> {
25818    /// Yields a span, the count of graphemes in the token, and whether it was
25819    /// whitespace. Note that it also breaks at word boundaries.
25820    type Item = WordBreakToken<'a>;
25821
25822    fn next(&mut self) -> Option<Self::Item> {
25823        use unicode_segmentation::UnicodeSegmentation;
25824        if self.input.is_empty() {
25825            return None;
25826        }
25827
25828        let mut iter = self.input.graphemes(true).peekable();
25829        let mut offset = 0;
25830        let mut grapheme_len = 0;
25831        if let Some(first_grapheme) = iter.next() {
25832            let is_newline = first_grapheme == "\n";
25833            let is_whitespace = is_grapheme_whitespace(first_grapheme);
25834            offset += first_grapheme.len();
25835            grapheme_len += 1;
25836            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
25837                if let Some(grapheme) = iter.peek().copied()
25838                    && should_stay_with_preceding_ideograph(grapheme)
25839                {
25840                    offset += grapheme.len();
25841                    grapheme_len += 1;
25842                }
25843            } else {
25844                let mut words = self.input[offset..].split_word_bound_indices().peekable();
25845                let mut next_word_bound = words.peek().copied();
25846                if next_word_bound.is_some_and(|(i, _)| i == 0) {
25847                    next_word_bound = words.next();
25848                }
25849                while let Some(grapheme) = iter.peek().copied() {
25850                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
25851                        break;
25852                    };
25853                    if is_grapheme_whitespace(grapheme) != is_whitespace
25854                        || (grapheme == "\n") != is_newline
25855                    {
25856                        break;
25857                    };
25858                    offset += grapheme.len();
25859                    grapheme_len += 1;
25860                    iter.next();
25861                }
25862            }
25863            let token = &self.input[..offset];
25864            self.input = &self.input[offset..];
25865            if token == "\n" {
25866                Some(WordBreakToken::Newline)
25867            } else if is_whitespace {
25868                Some(WordBreakToken::InlineWhitespace {
25869                    token,
25870                    grapheme_len,
25871                })
25872            } else {
25873                Some(WordBreakToken::Word {
25874                    token,
25875                    grapheme_len,
25876                })
25877            }
25878        } else {
25879            None
25880        }
25881    }
25882}
25883
25884#[test]
25885fn test_word_breaking_tokenizer() {
25886    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
25887        ("", &[]),
25888        ("  ", &[whitespace("  ", 2)]),
25889        ("Ʒ", &[word("Ʒ", 1)]),
25890        ("Ǽ", &[word("Ǽ", 1)]),
25891        ("", &[word("", 1)]),
25892        ("⋑⋑", &[word("⋑⋑", 2)]),
25893        (
25894            "原理,进而",
25895            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
25896        ),
25897        (
25898            "hello world",
25899            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
25900        ),
25901        (
25902            "hello, world",
25903            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
25904        ),
25905        (
25906            "  hello world",
25907            &[
25908                whitespace("  ", 2),
25909                word("hello", 5),
25910                whitespace(" ", 1),
25911                word("world", 5),
25912            ],
25913        ),
25914        (
25915            "这是什么 \n 钢笔",
25916            &[
25917                word("", 1),
25918                word("", 1),
25919                word("", 1),
25920                word("", 1),
25921                whitespace(" ", 1),
25922                newline(),
25923                whitespace(" ", 1),
25924                word("", 1),
25925                word("", 1),
25926            ],
25927        ),
25928        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
25929    ];
25930
25931    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25932        WordBreakToken::Word {
25933            token,
25934            grapheme_len,
25935        }
25936    }
25937
25938    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
25939        WordBreakToken::InlineWhitespace {
25940            token,
25941            grapheme_len,
25942        }
25943    }
25944
25945    fn newline() -> WordBreakToken<'static> {
25946        WordBreakToken::Newline
25947    }
25948
25949    for (input, result) in tests {
25950        assert_eq!(
25951            WordBreakingTokenizer::new(input)
25952                .collect::<Vec<_>>()
25953                .as_slice(),
25954            *result,
25955        );
25956    }
25957}
25958
25959fn wrap_with_prefix(
25960    first_line_prefix: String,
25961    subsequent_lines_prefix: String,
25962    unwrapped_text: String,
25963    wrap_column: usize,
25964    tab_size: NonZeroU32,
25965    preserve_existing_whitespace: bool,
25966) -> String {
25967    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
25968    let subsequent_lines_prefix_len =
25969        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
25970    let mut wrapped_text = String::new();
25971    let mut current_line = first_line_prefix;
25972    let mut is_first_line = true;
25973
25974    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
25975    let mut current_line_len = first_line_prefix_len;
25976    let mut in_whitespace = false;
25977    for token in tokenizer {
25978        let have_preceding_whitespace = in_whitespace;
25979        match token {
25980            WordBreakToken::Word {
25981                token,
25982                grapheme_len,
25983            } => {
25984                in_whitespace = false;
25985                let current_prefix_len = if is_first_line {
25986                    first_line_prefix_len
25987                } else {
25988                    subsequent_lines_prefix_len
25989                };
25990                if current_line_len + grapheme_len > wrap_column
25991                    && current_line_len != current_prefix_len
25992                {
25993                    wrapped_text.push_str(current_line.trim_end());
25994                    wrapped_text.push('\n');
25995                    is_first_line = false;
25996                    current_line = subsequent_lines_prefix.clone();
25997                    current_line_len = subsequent_lines_prefix_len;
25998                }
25999                current_line.push_str(token);
26000                current_line_len += grapheme_len;
26001            }
26002            WordBreakToken::InlineWhitespace {
26003                mut token,
26004                mut grapheme_len,
26005            } => {
26006                in_whitespace = true;
26007                if have_preceding_whitespace && !preserve_existing_whitespace {
26008                    continue;
26009                }
26010                if !preserve_existing_whitespace {
26011                    // Keep a single whitespace grapheme as-is
26012                    if let Some(first) =
26013                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26014                    {
26015                        token = first;
26016                    } else {
26017                        token = " ";
26018                    }
26019                    grapheme_len = 1;
26020                }
26021                let current_prefix_len = if is_first_line {
26022                    first_line_prefix_len
26023                } else {
26024                    subsequent_lines_prefix_len
26025                };
26026                if current_line_len + grapheme_len > wrap_column {
26027                    wrapped_text.push_str(current_line.trim_end());
26028                    wrapped_text.push('\n');
26029                    is_first_line = false;
26030                    current_line = subsequent_lines_prefix.clone();
26031                    current_line_len = subsequent_lines_prefix_len;
26032                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26033                    current_line.push_str(token);
26034                    current_line_len += grapheme_len;
26035                }
26036            }
26037            WordBreakToken::Newline => {
26038                in_whitespace = true;
26039                let current_prefix_len = if is_first_line {
26040                    first_line_prefix_len
26041                } else {
26042                    subsequent_lines_prefix_len
26043                };
26044                if preserve_existing_whitespace {
26045                    wrapped_text.push_str(current_line.trim_end());
26046                    wrapped_text.push('\n');
26047                    is_first_line = false;
26048                    current_line = subsequent_lines_prefix.clone();
26049                    current_line_len = subsequent_lines_prefix_len;
26050                } else if have_preceding_whitespace {
26051                    continue;
26052                } else if current_line_len + 1 > wrap_column
26053                    && current_line_len != current_prefix_len
26054                {
26055                    wrapped_text.push_str(current_line.trim_end());
26056                    wrapped_text.push('\n');
26057                    is_first_line = false;
26058                    current_line = subsequent_lines_prefix.clone();
26059                    current_line_len = subsequent_lines_prefix_len;
26060                } else if current_line_len != current_prefix_len {
26061                    current_line.push(' ');
26062                    current_line_len += 1;
26063                }
26064            }
26065        }
26066    }
26067
26068    if !current_line.is_empty() {
26069        wrapped_text.push_str(&current_line);
26070    }
26071    wrapped_text
26072}
26073
26074#[test]
26075fn test_wrap_with_prefix() {
26076    assert_eq!(
26077        wrap_with_prefix(
26078            "# ".to_string(),
26079            "# ".to_string(),
26080            "abcdefg".to_string(),
26081            4,
26082            NonZeroU32::new(4).unwrap(),
26083            false,
26084        ),
26085        "# abcdefg"
26086    );
26087    assert_eq!(
26088        wrap_with_prefix(
26089            "".to_string(),
26090            "".to_string(),
26091            "\thello world".to_string(),
26092            8,
26093            NonZeroU32::new(4).unwrap(),
26094            false,
26095        ),
26096        "hello\nworld"
26097    );
26098    assert_eq!(
26099        wrap_with_prefix(
26100            "// ".to_string(),
26101            "// ".to_string(),
26102            "xx \nyy zz aa bb cc".to_string(),
26103            12,
26104            NonZeroU32::new(4).unwrap(),
26105            false,
26106        ),
26107        "// xx yy zz\n// aa bb cc"
26108    );
26109    assert_eq!(
26110        wrap_with_prefix(
26111            String::new(),
26112            String::new(),
26113            "这是什么 \n 钢笔".to_string(),
26114            3,
26115            NonZeroU32::new(4).unwrap(),
26116            false,
26117        ),
26118        "这是什\n么 钢\n"
26119    );
26120    assert_eq!(
26121        wrap_with_prefix(
26122            String::new(),
26123            String::new(),
26124            format!("foo{}bar", '\u{2009}'), // thin space
26125            80,
26126            NonZeroU32::new(4).unwrap(),
26127            false,
26128        ),
26129        format!("foo{}bar", '\u{2009}')
26130    );
26131}
26132
26133pub trait CollaborationHub {
26134    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26135    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26136    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26137}
26138
26139impl CollaborationHub for Entity<Project> {
26140    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26141        self.read(cx).collaborators()
26142    }
26143
26144    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26145        self.read(cx).user_store().read(cx).participant_indices()
26146    }
26147
26148    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26149        let this = self.read(cx);
26150        let user_ids = this.collaborators().values().map(|c| c.user_id);
26151        this.user_store().read(cx).participant_names(user_ids, cx)
26152    }
26153}
26154
26155pub trait SemanticsProvider {
26156    fn hover(
26157        &self,
26158        buffer: &Entity<Buffer>,
26159        position: text::Anchor,
26160        cx: &mut App,
26161    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26162
26163    fn inline_values(
26164        &self,
26165        buffer_handle: Entity<Buffer>,
26166        range: Range<text::Anchor>,
26167        cx: &mut App,
26168    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26169
26170    fn applicable_inlay_chunks(
26171        &self,
26172        buffer: &Entity<Buffer>,
26173        ranges: &[Range<text::Anchor>],
26174        cx: &mut App,
26175    ) -> Vec<Range<BufferRow>>;
26176
26177    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26178
26179    fn inlay_hints(
26180        &self,
26181        invalidate: InvalidationStrategy,
26182        buffer: Entity<Buffer>,
26183        ranges: Vec<Range<text::Anchor>>,
26184        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26185        cx: &mut App,
26186    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
26187
26188    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26189
26190    fn document_highlights(
26191        &self,
26192        buffer: &Entity<Buffer>,
26193        position: text::Anchor,
26194        cx: &mut App,
26195    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
26196
26197    fn definitions(
26198        &self,
26199        buffer: &Entity<Buffer>,
26200        position: text::Anchor,
26201        kind: GotoDefinitionKind,
26202        cx: &mut App,
26203    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
26204
26205    fn range_for_rename(
26206        &self,
26207        buffer: &Entity<Buffer>,
26208        position: text::Anchor,
26209        cx: &mut App,
26210    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
26211
26212    fn perform_rename(
26213        &self,
26214        buffer: &Entity<Buffer>,
26215        position: text::Anchor,
26216        new_name: String,
26217        cx: &mut App,
26218    ) -> Option<Task<Result<ProjectTransaction>>>;
26219}
26220
26221pub trait CompletionProvider {
26222    fn completions(
26223        &self,
26224        excerpt_id: ExcerptId,
26225        buffer: &Entity<Buffer>,
26226        buffer_position: text::Anchor,
26227        trigger: CompletionContext,
26228        window: &mut Window,
26229        cx: &mut Context<Editor>,
26230    ) -> Task<Result<Vec<CompletionResponse>>>;
26231
26232    fn resolve_completions(
26233        &self,
26234        _buffer: Entity<Buffer>,
26235        _completion_indices: Vec<usize>,
26236        _completions: Rc<RefCell<Box<[Completion]>>>,
26237        _cx: &mut Context<Editor>,
26238    ) -> Task<Result<bool>> {
26239        Task::ready(Ok(false))
26240    }
26241
26242    fn apply_additional_edits_for_completion(
26243        &self,
26244        _buffer: Entity<Buffer>,
26245        _completions: Rc<RefCell<Box<[Completion]>>>,
26246        _completion_index: usize,
26247        _push_to_history: bool,
26248        _cx: &mut Context<Editor>,
26249    ) -> Task<Result<Option<language::Transaction>>> {
26250        Task::ready(Ok(None))
26251    }
26252
26253    fn is_completion_trigger(
26254        &self,
26255        buffer: &Entity<Buffer>,
26256        position: language::Anchor,
26257        text: &str,
26258        trigger_in_words: bool,
26259        cx: &mut Context<Editor>,
26260    ) -> bool;
26261
26262    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
26263
26264    fn sort_completions(&self) -> bool {
26265        true
26266    }
26267
26268    fn filter_completions(&self) -> bool {
26269        true
26270    }
26271
26272    fn show_snippets(&self) -> bool {
26273        false
26274    }
26275}
26276
26277pub trait CodeActionProvider {
26278    fn id(&self) -> Arc<str>;
26279
26280    fn code_actions(
26281        &self,
26282        buffer: &Entity<Buffer>,
26283        range: Range<text::Anchor>,
26284        window: &mut Window,
26285        cx: &mut App,
26286    ) -> Task<Result<Vec<CodeAction>>>;
26287
26288    fn apply_code_action(
26289        &self,
26290        buffer_handle: Entity<Buffer>,
26291        action: CodeAction,
26292        excerpt_id: ExcerptId,
26293        push_to_history: bool,
26294        window: &mut Window,
26295        cx: &mut App,
26296    ) -> Task<Result<ProjectTransaction>>;
26297}
26298
26299impl CodeActionProvider for Entity<Project> {
26300    fn id(&self) -> Arc<str> {
26301        "project".into()
26302    }
26303
26304    fn code_actions(
26305        &self,
26306        buffer: &Entity<Buffer>,
26307        range: Range<text::Anchor>,
26308        _window: &mut Window,
26309        cx: &mut App,
26310    ) -> Task<Result<Vec<CodeAction>>> {
26311        self.update(cx, |project, cx| {
26312            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
26313            let code_actions = project.code_actions(buffer, range, None, cx);
26314            cx.background_spawn(async move {
26315                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
26316                Ok(code_lens_actions
26317                    .context("code lens fetch")?
26318                    .into_iter()
26319                    .flatten()
26320                    .chain(
26321                        code_actions
26322                            .context("code action fetch")?
26323                            .into_iter()
26324                            .flatten(),
26325                    )
26326                    .collect())
26327            })
26328        })
26329    }
26330
26331    fn apply_code_action(
26332        &self,
26333        buffer_handle: Entity<Buffer>,
26334        action: CodeAction,
26335        _excerpt_id: ExcerptId,
26336        push_to_history: bool,
26337        _window: &mut Window,
26338        cx: &mut App,
26339    ) -> Task<Result<ProjectTransaction>> {
26340        self.update(cx, |project, cx| {
26341            project.apply_code_action(buffer_handle, action, push_to_history, cx)
26342        })
26343    }
26344}
26345
26346fn snippet_completions(
26347    project: &Project,
26348    buffer: &Entity<Buffer>,
26349    buffer_anchor: text::Anchor,
26350    classifier: CharClassifier,
26351    cx: &mut App,
26352) -> Task<Result<CompletionResponse>> {
26353    let languages = buffer.read(cx).languages_at(buffer_anchor);
26354    let snippet_store = project.snippets().read(cx);
26355
26356    let scopes: Vec<_> = languages
26357        .iter()
26358        .filter_map(|language| {
26359            let language_name = language.lsp_id();
26360            let snippets = snippet_store.snippets_for(Some(language_name), cx);
26361
26362            if snippets.is_empty() {
26363                None
26364            } else {
26365                Some((language.default_scope(), snippets))
26366            }
26367        })
26368        .collect();
26369
26370    if scopes.is_empty() {
26371        return Task::ready(Ok(CompletionResponse {
26372            completions: vec![],
26373            display_options: CompletionDisplayOptions::default(),
26374            is_incomplete: false,
26375        }));
26376    }
26377
26378    let snapshot = buffer.read(cx).text_snapshot();
26379    let executor = cx.background_executor().clone();
26380
26381    cx.background_spawn(async move {
26382        let is_word_char = |c| classifier.is_word(c);
26383
26384        let mut is_incomplete = false;
26385        let mut completions: Vec<Completion> = Vec::new();
26386
26387        const MAX_PREFIX_LEN: usize = 128;
26388        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
26389        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
26390        let window_start = snapshot.clip_offset(window_start, Bias::Left);
26391
26392        let max_buffer_window: String = snapshot
26393            .text_for_range(window_start..buffer_offset)
26394            .collect();
26395
26396        if max_buffer_window.is_empty() {
26397            return Ok(CompletionResponse {
26398                completions: vec![],
26399                display_options: CompletionDisplayOptions::default(),
26400                is_incomplete: true,
26401            });
26402        }
26403
26404        for (_scope, snippets) in scopes.into_iter() {
26405            // Sort snippets by word count to match longer snippet prefixes first.
26406            let mut sorted_snippet_candidates = snippets
26407                .iter()
26408                .enumerate()
26409                .flat_map(|(snippet_ix, snippet)| {
26410                    snippet
26411                        .prefix
26412                        .iter()
26413                        .enumerate()
26414                        .map(move |(prefix_ix, prefix)| {
26415                            let word_count =
26416                                snippet_candidate_suffixes(prefix, is_word_char).count();
26417                            ((snippet_ix, prefix_ix), prefix, word_count)
26418                        })
26419                })
26420                .collect_vec();
26421            sorted_snippet_candidates
26422                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
26423
26424            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
26425
26426            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
26427                .take(
26428                    sorted_snippet_candidates
26429                        .first()
26430                        .map(|(_, _, word_count)| *word_count)
26431                        .unwrap_or_default(),
26432                )
26433                .collect_vec();
26434
26435            const MAX_RESULTS: usize = 100;
26436            // Each match also remembers how many characters from the buffer it consumed
26437            let mut matches: Vec<(StringMatch, usize)> = vec![];
26438
26439            let mut snippet_list_cutoff_index = 0;
26440            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
26441                let word_count = buffer_index + 1;
26442                // Increase `snippet_list_cutoff_index` until we have all of the
26443                // snippets with sufficiently many words.
26444                while sorted_snippet_candidates
26445                    .get(snippet_list_cutoff_index)
26446                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
26447                        *snippet_word_count >= word_count
26448                    })
26449                {
26450                    snippet_list_cutoff_index += 1;
26451                }
26452
26453                // Take only the candidates with at least `word_count` many words
26454                let snippet_candidates_at_word_len =
26455                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
26456
26457                let candidates = snippet_candidates_at_word_len
26458                    .iter()
26459                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
26460                    .enumerate() // index in `sorted_snippet_candidates`
26461                    // First char must match
26462                    .filter(|(_ix, prefix)| {
26463                        itertools::equal(
26464                            prefix
26465                                .chars()
26466                                .next()
26467                                .into_iter()
26468                                .flat_map(|c| c.to_lowercase()),
26469                            buffer_window
26470                                .chars()
26471                                .next()
26472                                .into_iter()
26473                                .flat_map(|c| c.to_lowercase()),
26474                        )
26475                    })
26476                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
26477                    .collect::<Vec<StringMatchCandidate>>();
26478
26479                matches.extend(
26480                    fuzzy::match_strings(
26481                        &candidates,
26482                        &buffer_window,
26483                        buffer_window.chars().any(|c| c.is_uppercase()),
26484                        true,
26485                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
26486                        &Default::default(),
26487                        executor.clone(),
26488                    )
26489                    .await
26490                    .into_iter()
26491                    .map(|string_match| (string_match, buffer_window.len())),
26492                );
26493
26494                if matches.len() >= MAX_RESULTS {
26495                    break;
26496                }
26497            }
26498
26499            let to_lsp = |point: &text::Anchor| {
26500                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
26501                point_to_lsp(end)
26502            };
26503            let lsp_end = to_lsp(&buffer_anchor);
26504
26505            if matches.len() >= MAX_RESULTS {
26506                is_incomplete = true;
26507            }
26508
26509            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
26510                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
26511                    sorted_snippet_candidates[string_match.candidate_id];
26512                let snippet = &snippets[snippet_index];
26513                let start = buffer_offset - buffer_window_len;
26514                let start = snapshot.anchor_before(start);
26515                let range = start..buffer_anchor;
26516                let lsp_start = to_lsp(&start);
26517                let lsp_range = lsp::Range {
26518                    start: lsp_start,
26519                    end: lsp_end,
26520                };
26521                Completion {
26522                    replace_range: range,
26523                    new_text: snippet.body.clone(),
26524                    source: CompletionSource::Lsp {
26525                        insert_range: None,
26526                        server_id: LanguageServerId(usize::MAX),
26527                        resolved: true,
26528                        lsp_completion: Box::new(lsp::CompletionItem {
26529                            label: snippet.prefix.first().unwrap().clone(),
26530                            kind: Some(CompletionItemKind::SNIPPET),
26531                            label_details: snippet.description.as_ref().map(|description| {
26532                                lsp::CompletionItemLabelDetails {
26533                                    detail: Some(description.clone()),
26534                                    description: None,
26535                                }
26536                            }),
26537                            insert_text_format: Some(InsertTextFormat::SNIPPET),
26538                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
26539                                lsp::InsertReplaceEdit {
26540                                    new_text: snippet.body.clone(),
26541                                    insert: lsp_range,
26542                                    replace: lsp_range,
26543                                },
26544                            )),
26545                            filter_text: Some(snippet.body.clone()),
26546                            sort_text: Some(char::MAX.to_string()),
26547                            ..lsp::CompletionItem::default()
26548                        }),
26549                        lsp_defaults: None,
26550                    },
26551                    label: CodeLabel {
26552                        text: matching_prefix.clone(),
26553                        runs: Vec::new(),
26554                        filter_range: 0..matching_prefix.len(),
26555                    },
26556                    icon_path: None,
26557                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
26558                        single_line: snippet.name.clone().into(),
26559                        plain_text: snippet
26560                            .description
26561                            .clone()
26562                            .map(|description| description.into()),
26563                    }),
26564                    insert_text_mode: None,
26565                    confirm: None,
26566                    match_start: Some(start),
26567                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
26568                }
26569            }));
26570        }
26571
26572        Ok(CompletionResponse {
26573            completions,
26574            display_options: CompletionDisplayOptions::default(),
26575            is_incomplete,
26576        })
26577    })
26578}
26579
26580impl CompletionProvider for Entity<Project> {
26581    fn completions(
26582        &self,
26583        _excerpt_id: ExcerptId,
26584        buffer: &Entity<Buffer>,
26585        buffer_position: text::Anchor,
26586        options: CompletionContext,
26587        _window: &mut Window,
26588        cx: &mut Context<Editor>,
26589    ) -> Task<Result<Vec<CompletionResponse>>> {
26590        self.update(cx, |project, cx| {
26591            let task = project.completions(buffer, buffer_position, options, cx);
26592            cx.background_spawn(task)
26593        })
26594    }
26595
26596    fn resolve_completions(
26597        &self,
26598        buffer: Entity<Buffer>,
26599        completion_indices: Vec<usize>,
26600        completions: Rc<RefCell<Box<[Completion]>>>,
26601        cx: &mut Context<Editor>,
26602    ) -> Task<Result<bool>> {
26603        self.update(cx, |project, cx| {
26604            project.lsp_store().update(cx, |lsp_store, cx| {
26605                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
26606            })
26607        })
26608    }
26609
26610    fn apply_additional_edits_for_completion(
26611        &self,
26612        buffer: Entity<Buffer>,
26613        completions: Rc<RefCell<Box<[Completion]>>>,
26614        completion_index: usize,
26615        push_to_history: bool,
26616        cx: &mut Context<Editor>,
26617    ) -> Task<Result<Option<language::Transaction>>> {
26618        self.update(cx, |project, cx| {
26619            project.lsp_store().update(cx, |lsp_store, cx| {
26620                lsp_store.apply_additional_edits_for_completion(
26621                    buffer,
26622                    completions,
26623                    completion_index,
26624                    push_to_history,
26625                    cx,
26626                )
26627            })
26628        })
26629    }
26630
26631    fn is_completion_trigger(
26632        &self,
26633        buffer: &Entity<Buffer>,
26634        position: language::Anchor,
26635        text: &str,
26636        trigger_in_words: bool,
26637        cx: &mut Context<Editor>,
26638    ) -> bool {
26639        let mut chars = text.chars();
26640        let char = if let Some(char) = chars.next() {
26641            char
26642        } else {
26643            return false;
26644        };
26645        if chars.next().is_some() {
26646            return false;
26647        }
26648
26649        let buffer = buffer.read(cx);
26650        let snapshot = buffer.snapshot();
26651        let classifier = snapshot
26652            .char_classifier_at(position)
26653            .scope_context(Some(CharScopeContext::Completion));
26654        if trigger_in_words && classifier.is_word(char) {
26655            return true;
26656        }
26657
26658        buffer.completion_triggers().contains(text)
26659    }
26660
26661    fn show_snippets(&self) -> bool {
26662        true
26663    }
26664}
26665
26666impl SemanticsProvider for Entity<Project> {
26667    fn hover(
26668        &self,
26669        buffer: &Entity<Buffer>,
26670        position: text::Anchor,
26671        cx: &mut App,
26672    ) -> Option<Task<Option<Vec<project::Hover>>>> {
26673        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
26674    }
26675
26676    fn document_highlights(
26677        &self,
26678        buffer: &Entity<Buffer>,
26679        position: text::Anchor,
26680        cx: &mut App,
26681    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
26682        Some(self.update(cx, |project, cx| {
26683            project.document_highlights(buffer, position, cx)
26684        }))
26685    }
26686
26687    fn definitions(
26688        &self,
26689        buffer: &Entity<Buffer>,
26690        position: text::Anchor,
26691        kind: GotoDefinitionKind,
26692        cx: &mut App,
26693    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
26694        Some(self.update(cx, |project, cx| match kind {
26695            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
26696            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
26697            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
26698            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
26699        }))
26700    }
26701
26702    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
26703        self.update(cx, |project, cx| {
26704            if project
26705                .active_debug_session(cx)
26706                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
26707            {
26708                return true;
26709            }
26710
26711            buffer.update(cx, |buffer, cx| {
26712                project.any_language_server_supports_inlay_hints(buffer, cx)
26713            })
26714        })
26715    }
26716
26717    fn inline_values(
26718        &self,
26719        buffer_handle: Entity<Buffer>,
26720        range: Range<text::Anchor>,
26721        cx: &mut App,
26722    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
26723        self.update(cx, |project, cx| {
26724            let (session, active_stack_frame) = project.active_debug_session(cx)?;
26725
26726            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
26727        })
26728    }
26729
26730    fn applicable_inlay_chunks(
26731        &self,
26732        buffer: &Entity<Buffer>,
26733        ranges: &[Range<text::Anchor>],
26734        cx: &mut App,
26735    ) -> Vec<Range<BufferRow>> {
26736        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26737            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
26738        })
26739    }
26740
26741    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
26742        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
26743            lsp_store.invalidate_inlay_hints(for_buffers)
26744        });
26745    }
26746
26747    fn inlay_hints(
26748        &self,
26749        invalidate: InvalidationStrategy,
26750        buffer: Entity<Buffer>,
26751        ranges: Vec<Range<text::Anchor>>,
26752        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26753        cx: &mut App,
26754    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
26755        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
26756            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
26757        }))
26758    }
26759
26760    fn range_for_rename(
26761        &self,
26762        buffer: &Entity<Buffer>,
26763        position: text::Anchor,
26764        cx: &mut App,
26765    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
26766        Some(self.update(cx, |project, cx| {
26767            let buffer = buffer.clone();
26768            let task = project.prepare_rename(buffer.clone(), position, cx);
26769            cx.spawn(async move |_, cx| {
26770                Ok(match task.await? {
26771                    PrepareRenameResponse::Success(range) => Some(range),
26772                    PrepareRenameResponse::InvalidPosition => None,
26773                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
26774                        // Fallback on using TreeSitter info to determine identifier range
26775                        buffer.read_with(cx, |buffer, _| {
26776                            let snapshot = buffer.snapshot();
26777                            let (range, kind) = snapshot.surrounding_word(position, None);
26778                            if kind != Some(CharKind::Word) {
26779                                return None;
26780                            }
26781                            Some(
26782                                snapshot.anchor_before(range.start)
26783                                    ..snapshot.anchor_after(range.end),
26784                            )
26785                        })
26786                    }
26787                })
26788            })
26789        }))
26790    }
26791
26792    fn perform_rename(
26793        &self,
26794        buffer: &Entity<Buffer>,
26795        position: text::Anchor,
26796        new_name: String,
26797        cx: &mut App,
26798    ) -> Option<Task<Result<ProjectTransaction>>> {
26799        Some(self.update(cx, |project, cx| {
26800            project.perform_rename(buffer.clone(), position, new_name, cx)
26801        }))
26802    }
26803}
26804
26805fn consume_contiguous_rows(
26806    contiguous_row_selections: &mut Vec<Selection<Point>>,
26807    selection: &Selection<Point>,
26808    display_map: &DisplaySnapshot,
26809    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
26810) -> (MultiBufferRow, MultiBufferRow) {
26811    contiguous_row_selections.push(selection.clone());
26812    let start_row = starting_row(selection, display_map);
26813    let mut end_row = ending_row(selection, display_map);
26814
26815    while let Some(next_selection) = selections.peek() {
26816        if next_selection.start.row <= end_row.0 {
26817            end_row = ending_row(next_selection, display_map);
26818            contiguous_row_selections.push(selections.next().unwrap().clone());
26819        } else {
26820            break;
26821        }
26822    }
26823    (start_row, end_row)
26824}
26825
26826fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26827    if selection.start.column > 0 {
26828        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
26829    } else {
26830        MultiBufferRow(selection.start.row)
26831    }
26832}
26833
26834fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
26835    if next_selection.end.column > 0 || next_selection.is_empty() {
26836        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
26837    } else {
26838        MultiBufferRow(next_selection.end.row)
26839    }
26840}
26841
26842impl EditorSnapshot {
26843    pub fn remote_selections_in_range<'a>(
26844        &'a self,
26845        range: &'a Range<Anchor>,
26846        collaboration_hub: &dyn CollaborationHub,
26847        cx: &'a App,
26848    ) -> impl 'a + Iterator<Item = RemoteSelection> {
26849        let participant_names = collaboration_hub.user_names(cx);
26850        let participant_indices = collaboration_hub.user_participant_indices(cx);
26851        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
26852        let collaborators_by_replica_id = collaborators_by_peer_id
26853            .values()
26854            .map(|collaborator| (collaborator.replica_id, collaborator))
26855            .collect::<HashMap<_, _>>();
26856        self.buffer_snapshot()
26857            .selections_in_range(range, false)
26858            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
26859                if replica_id == ReplicaId::AGENT {
26860                    Some(RemoteSelection {
26861                        replica_id,
26862                        selection,
26863                        cursor_shape,
26864                        line_mode,
26865                        collaborator_id: CollaboratorId::Agent,
26866                        user_name: Some("Agent".into()),
26867                        color: cx.theme().players().agent(),
26868                    })
26869                } else {
26870                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
26871                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
26872                    let user_name = participant_names.get(&collaborator.user_id).cloned();
26873                    Some(RemoteSelection {
26874                        replica_id,
26875                        selection,
26876                        cursor_shape,
26877                        line_mode,
26878                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
26879                        user_name,
26880                        color: if let Some(index) = participant_index {
26881                            cx.theme().players().color_for_participant(index.0)
26882                        } else {
26883                            cx.theme().players().absent()
26884                        },
26885                    })
26886                }
26887            })
26888    }
26889
26890    pub fn hunks_for_ranges(
26891        &self,
26892        ranges: impl IntoIterator<Item = Range<Point>>,
26893    ) -> Vec<MultiBufferDiffHunk> {
26894        let mut hunks = Vec::new();
26895        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
26896            HashMap::default();
26897        for query_range in ranges {
26898            let query_rows =
26899                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
26900            for hunk in self.buffer_snapshot().diff_hunks_in_range(
26901                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
26902            ) {
26903                // Include deleted hunks that are adjacent to the query range, because
26904                // otherwise they would be missed.
26905                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
26906                if hunk.status().is_deleted() {
26907                    intersects_range |= hunk.row_range.start == query_rows.end;
26908                    intersects_range |= hunk.row_range.end == query_rows.start;
26909                }
26910                if intersects_range {
26911                    if !processed_buffer_rows
26912                        .entry(hunk.buffer_id)
26913                        .or_default()
26914                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
26915                    {
26916                        continue;
26917                    }
26918                    hunks.push(hunk);
26919                }
26920            }
26921        }
26922
26923        hunks
26924    }
26925
26926    fn display_diff_hunks_for_rows<'a>(
26927        &'a self,
26928        display_rows: Range<DisplayRow>,
26929        folded_buffers: &'a HashSet<BufferId>,
26930    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
26931        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
26932        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
26933
26934        self.buffer_snapshot()
26935            .diff_hunks_in_range(buffer_start..buffer_end)
26936            .filter_map(|hunk| {
26937                if folded_buffers.contains(&hunk.buffer_id) {
26938                    return None;
26939                }
26940
26941                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
26942                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
26943
26944                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
26945                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
26946
26947                let display_hunk = if hunk_display_start.column() != 0 {
26948                    DisplayDiffHunk::Folded {
26949                        display_row: hunk_display_start.row(),
26950                    }
26951                } else {
26952                    let mut end_row = hunk_display_end.row();
26953                    if hunk_display_end.column() > 0 {
26954                        end_row.0 += 1;
26955                    }
26956                    let is_created_file = hunk.is_created_file();
26957
26958                    DisplayDiffHunk::Unfolded {
26959                        status: hunk.status(),
26960                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
26961                            ..hunk.diff_base_byte_range.end.0,
26962                        word_diffs: hunk.word_diffs,
26963                        display_row_range: hunk_display_start.row()..end_row,
26964                        multi_buffer_range: Anchor::range_in_buffer(
26965                            hunk.excerpt_id,
26966                            hunk.buffer_range,
26967                        ),
26968                        is_created_file,
26969                    }
26970                };
26971
26972                Some(display_hunk)
26973            })
26974    }
26975
26976    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
26977        self.display_snapshot
26978            .buffer_snapshot()
26979            .language_at(position)
26980    }
26981
26982    pub fn is_focused(&self) -> bool {
26983        self.is_focused
26984    }
26985
26986    pub fn placeholder_text(&self) -> Option<String> {
26987        self.placeholder_display_snapshot
26988            .as_ref()
26989            .map(|display_map| display_map.text())
26990    }
26991
26992    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
26993        self.scroll_anchor.scroll_position(&self.display_snapshot)
26994    }
26995
26996    pub fn gutter_dimensions(
26997        &self,
26998        font_id: FontId,
26999        font_size: Pixels,
27000        style: &EditorStyle,
27001        window: &mut Window,
27002        cx: &App,
27003    ) -> GutterDimensions {
27004        if self.show_gutter
27005            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27006            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27007        {
27008            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27009                matches!(
27010                    ProjectSettings::get_global(cx).git.git_gutter,
27011                    GitGutterSetting::TrackedFiles
27012                )
27013            });
27014            let gutter_settings = EditorSettings::get_global(cx).gutter;
27015            let show_line_numbers = self
27016                .show_line_numbers
27017                .unwrap_or(gutter_settings.line_numbers);
27018            let line_gutter_width = if show_line_numbers {
27019                // Avoid flicker-like gutter resizes when the line number gains another digit by
27020                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27021                let min_width_for_number_on_gutter =
27022                    ch_advance * gutter_settings.min_line_number_digits as f32;
27023                self.max_line_number_width(style, window)
27024                    .max(min_width_for_number_on_gutter)
27025            } else {
27026                0.0.into()
27027            };
27028
27029            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27030            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27031
27032            let git_blame_entries_width =
27033                self.git_blame_gutter_max_author_length
27034                    .map(|max_author_length| {
27035                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27036                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27037
27038                        /// The number of characters to dedicate to gaps and margins.
27039                        const SPACING_WIDTH: usize = 4;
27040
27041                        let max_char_count = max_author_length.min(renderer.max_author_length())
27042                            + ::git::SHORT_SHA_LENGTH
27043                            + MAX_RELATIVE_TIMESTAMP.len()
27044                            + SPACING_WIDTH;
27045
27046                        ch_advance * max_char_count
27047                    });
27048
27049            let is_singleton = self.buffer_snapshot().is_singleton();
27050
27051            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27052            left_padding += if !is_singleton {
27053                ch_width * 4.0
27054            } else if show_runnables || show_breakpoints {
27055                ch_width * 3.0
27056            } else if show_git_gutter && show_line_numbers {
27057                ch_width * 2.0
27058            } else if show_git_gutter || show_line_numbers {
27059                ch_width
27060            } else {
27061                px(0.)
27062            };
27063
27064            let shows_folds = is_singleton && gutter_settings.folds;
27065
27066            let right_padding = if shows_folds && show_line_numbers {
27067                ch_width * 4.0
27068            } else if shows_folds || (!is_singleton && show_line_numbers) {
27069                ch_width * 3.0
27070            } else if show_line_numbers {
27071                ch_width
27072            } else {
27073                px(0.)
27074            };
27075
27076            GutterDimensions {
27077                left_padding,
27078                right_padding,
27079                width: line_gutter_width + left_padding + right_padding,
27080                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27081                git_blame_entries_width,
27082            }
27083        } else if self.offset_content {
27084            GutterDimensions::default_with_margin(font_id, font_size, cx)
27085        } else {
27086            GutterDimensions::default()
27087        }
27088    }
27089
27090    pub fn render_crease_toggle(
27091        &self,
27092        buffer_row: MultiBufferRow,
27093        row_contains_cursor: bool,
27094        editor: Entity<Editor>,
27095        window: &mut Window,
27096        cx: &mut App,
27097    ) -> Option<AnyElement> {
27098        let folded = self.is_line_folded(buffer_row);
27099        let mut is_foldable = false;
27100
27101        if let Some(crease) = self
27102            .crease_snapshot
27103            .query_row(buffer_row, self.buffer_snapshot())
27104        {
27105            is_foldable = true;
27106            match crease {
27107                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27108                    if let Some(render_toggle) = render_toggle {
27109                        let toggle_callback =
27110                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27111                                if folded {
27112                                    editor.update(cx, |editor, cx| {
27113                                        editor.fold_at(buffer_row, window, cx)
27114                                    });
27115                                } else {
27116                                    editor.update(cx, |editor, cx| {
27117                                        editor.unfold_at(buffer_row, window, cx)
27118                                    });
27119                                }
27120                            });
27121                        return Some((render_toggle)(
27122                            buffer_row,
27123                            folded,
27124                            toggle_callback,
27125                            window,
27126                            cx,
27127                        ));
27128                    }
27129                }
27130            }
27131        }
27132
27133        is_foldable |= self.starts_indent(buffer_row);
27134
27135        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
27136            Some(
27137                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
27138                    .toggle_state(folded)
27139                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
27140                        if folded {
27141                            this.unfold_at(buffer_row, window, cx);
27142                        } else {
27143                            this.fold_at(buffer_row, window, cx);
27144                        }
27145                    }))
27146                    .into_any_element(),
27147            )
27148        } else {
27149            None
27150        }
27151    }
27152
27153    pub fn render_crease_trailer(
27154        &self,
27155        buffer_row: MultiBufferRow,
27156        window: &mut Window,
27157        cx: &mut App,
27158    ) -> Option<AnyElement> {
27159        let folded = self.is_line_folded(buffer_row);
27160        if let Crease::Inline { render_trailer, .. } = self
27161            .crease_snapshot
27162            .query_row(buffer_row, self.buffer_snapshot())?
27163        {
27164            let render_trailer = render_trailer.as_ref()?;
27165            Some(render_trailer(buffer_row, folded, window, cx))
27166        } else {
27167            None
27168        }
27169    }
27170
27171    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
27172        let digit_count = self.widest_line_number().ilog10() + 1;
27173        column_pixels(style, digit_count as usize, window)
27174    }
27175
27176    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
27177    ///
27178    /// This is positive if `base` is before `line`.
27179    fn relative_line_delta(
27180        &self,
27181        current_selection_head: DisplayRow,
27182        first_visible_row: DisplayRow,
27183        consider_wrapped_lines: bool,
27184    ) -> i64 {
27185        let current_selection_head = current_selection_head.as_display_point().to_point(self);
27186        let first_visible_row = first_visible_row.as_display_point().to_point(self);
27187
27188        if consider_wrapped_lines {
27189            let wrap_snapshot = self.wrap_snapshot();
27190            let base_wrap_row = wrap_snapshot
27191                .make_wrap_point(current_selection_head, Bias::Left)
27192                .row();
27193            let wrap_row = wrap_snapshot
27194                .make_wrap_point(first_visible_row, Bias::Left)
27195                .row();
27196
27197            wrap_row.0 as i64 - base_wrap_row.0 as i64
27198        } else {
27199            let fold_snapshot = self.fold_snapshot();
27200            let base_fold_row = fold_snapshot
27201                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
27202                .row();
27203            let fold_row = fold_snapshot
27204                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
27205                .row();
27206
27207            fold_row as i64 - base_fold_row as i64
27208        }
27209    }
27210
27211    /// Returns the unsigned relative line number to display for each row in `rows`.
27212    ///
27213    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
27214    pub fn calculate_relative_line_numbers(
27215        &self,
27216        rows: &Range<DisplayRow>,
27217        current_selection_head: DisplayRow,
27218        count_wrapped_lines: bool,
27219    ) -> HashMap<DisplayRow, u32> {
27220        let initial_offset =
27221            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
27222        let current_selection_point = current_selection_head.as_display_point().to_point(self);
27223
27224        self.row_infos(rows.start)
27225            .take(rows.len())
27226            .enumerate()
27227            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
27228            .filter(|(_row, row_info)| {
27229                row_info.buffer_row.is_some()
27230                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
27231            })
27232            .enumerate()
27233            .filter(|(_, (row, row_info))| {
27234                // We want to check here that
27235                // - the row is not the current selection head to ensure the current
27236                // line has absolute numbering
27237                // - similarly, should the selection head live in a soft-wrapped line
27238                // and we are not counting those, that the parent line keeps its
27239                // absolute number
27240                // - lastly, if we are in a deleted line, it is fine to number this
27241                // relative with 0, as otherwise it would have no line number at all
27242                (*row != current_selection_head
27243                    && (count_wrapped_lines
27244                        || row_info.buffer_row != Some(current_selection_point.row)))
27245                    || row_info
27246                        .diff_status
27247                        .is_some_and(|status| status.is_deleted())
27248            })
27249            .map(|(i, (row, _))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
27250            .collect()
27251    }
27252}
27253
27254pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
27255    let font_size = style.text.font_size.to_pixels(window.rem_size());
27256    let layout = window.text_system().shape_line(
27257        SharedString::from(" ".repeat(column)),
27258        font_size,
27259        &[TextRun {
27260            len: column,
27261            font: style.text.font(),
27262            color: Hsla::default(),
27263            ..Default::default()
27264        }],
27265        None,
27266    );
27267
27268    layout.width
27269}
27270
27271impl Deref for EditorSnapshot {
27272    type Target = DisplaySnapshot;
27273
27274    fn deref(&self) -> &Self::Target {
27275        &self.display_snapshot
27276    }
27277}
27278
27279#[derive(Clone, Debug, PartialEq, Eq)]
27280pub enum EditorEvent {
27281    /// Emitted when the stored review comments change (added, removed, or updated).
27282    ReviewCommentsChanged {
27283        /// The new total count of review comments.
27284        total_count: usize,
27285    },
27286    InputIgnored {
27287        text: Arc<str>,
27288    },
27289    InputHandled {
27290        utf16_range_to_replace: Option<Range<isize>>,
27291        text: Arc<str>,
27292    },
27293    ExcerptsAdded {
27294        buffer: Entity<Buffer>,
27295        predecessor: ExcerptId,
27296        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
27297    },
27298    ExcerptsRemoved {
27299        ids: Vec<ExcerptId>,
27300        removed_buffer_ids: Vec<BufferId>,
27301    },
27302    BufferFoldToggled {
27303        ids: Vec<ExcerptId>,
27304        folded: bool,
27305    },
27306    ExcerptsEdited {
27307        ids: Vec<ExcerptId>,
27308    },
27309    ExcerptsExpanded {
27310        ids: Vec<ExcerptId>,
27311    },
27312    ExpandExcerptsRequested {
27313        excerpt_ids: Vec<ExcerptId>,
27314        lines: u32,
27315        direction: ExpandExcerptDirection,
27316    },
27317    BufferEdited,
27318    Edited {
27319        transaction_id: clock::Lamport,
27320    },
27321    Reparsed(BufferId),
27322    Focused,
27323    FocusedIn,
27324    Blurred,
27325    DirtyChanged,
27326    Saved,
27327    TitleChanged,
27328    SelectionsChanged {
27329        local: bool,
27330    },
27331    ScrollPositionChanged {
27332        local: bool,
27333        autoscroll: bool,
27334    },
27335    TransactionUndone {
27336        transaction_id: clock::Lamport,
27337    },
27338    TransactionBegun {
27339        transaction_id: clock::Lamport,
27340    },
27341    CursorShapeChanged,
27342    BreadcrumbsChanged,
27343    PushedToNavHistory {
27344        anchor: Anchor,
27345        is_deactivate: bool,
27346    },
27347}
27348
27349impl EventEmitter<EditorEvent> for Editor {}
27350
27351impl Focusable for Editor {
27352    fn focus_handle(&self, _cx: &App) -> FocusHandle {
27353        self.focus_handle.clone()
27354    }
27355}
27356
27357impl Render for Editor {
27358    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27359        EditorElement::new(&cx.entity(), self.create_style(cx))
27360    }
27361}
27362
27363impl EntityInputHandler for Editor {
27364    fn text_for_range(
27365        &mut self,
27366        range_utf16: Range<usize>,
27367        adjusted_range: &mut Option<Range<usize>>,
27368        _: &mut Window,
27369        cx: &mut Context<Self>,
27370    ) -> Option<String> {
27371        let snapshot = self.buffer.read(cx).read(cx);
27372        let start = snapshot.clip_offset_utf16(
27373            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
27374            Bias::Left,
27375        );
27376        let end = snapshot.clip_offset_utf16(
27377            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
27378            Bias::Right,
27379        );
27380        if (start.0.0..end.0.0) != range_utf16 {
27381            adjusted_range.replace(start.0.0..end.0.0);
27382        }
27383        Some(snapshot.text_for_range(start..end).collect())
27384    }
27385
27386    fn selected_text_range(
27387        &mut self,
27388        ignore_disabled_input: bool,
27389        _: &mut Window,
27390        cx: &mut Context<Self>,
27391    ) -> Option<UTF16Selection> {
27392        // Prevent the IME menu from appearing when holding down an alphabetic key
27393        // while input is disabled.
27394        if !ignore_disabled_input && !self.input_enabled {
27395            return None;
27396        }
27397
27398        let selection = self
27399            .selections
27400            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
27401        let range = selection.range();
27402
27403        Some(UTF16Selection {
27404            range: range.start.0.0..range.end.0.0,
27405            reversed: selection.reversed,
27406        })
27407    }
27408
27409    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
27410        let snapshot = self.buffer.read(cx).read(cx);
27411        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
27412        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
27413    }
27414
27415    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
27416        self.clear_highlights::<InputComposition>(cx);
27417        self.ime_transaction.take();
27418    }
27419
27420    fn replace_text_in_range(
27421        &mut self,
27422        range_utf16: Option<Range<usize>>,
27423        text: &str,
27424        window: &mut Window,
27425        cx: &mut Context<Self>,
27426    ) {
27427        if !self.input_enabled {
27428            cx.emit(EditorEvent::InputIgnored { text: text.into() });
27429            return;
27430        }
27431
27432        self.transact(window, cx, |this, window, cx| {
27433            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
27434                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27435                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27436                Some(this.selection_replacement_ranges(range_utf16, cx))
27437            } else {
27438                this.marked_text_ranges(cx)
27439            };
27440
27441            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
27442                let newest_selection_id = this.selections.newest_anchor().id;
27443                this.selections
27444                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27445                    .iter()
27446                    .zip(ranges_to_replace.iter())
27447                    .find_map(|(selection, range)| {
27448                        if selection.id == newest_selection_id {
27449                            Some(
27450                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27451                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27452                            )
27453                        } else {
27454                            None
27455                        }
27456                    })
27457            });
27458
27459            cx.emit(EditorEvent::InputHandled {
27460                utf16_range_to_replace: range_to_replace,
27461                text: text.into(),
27462            });
27463
27464            if let Some(new_selected_ranges) = new_selected_ranges {
27465                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27466                    selections.select_ranges(new_selected_ranges)
27467                });
27468                this.backspace(&Default::default(), window, cx);
27469            }
27470
27471            this.handle_input(text, window, cx);
27472        });
27473
27474        if let Some(transaction) = self.ime_transaction {
27475            self.buffer.update(cx, |buffer, cx| {
27476                buffer.group_until_transaction(transaction, cx);
27477            });
27478        }
27479
27480        self.unmark_text(window, cx);
27481    }
27482
27483    fn replace_and_mark_text_in_range(
27484        &mut self,
27485        range_utf16: Option<Range<usize>>,
27486        text: &str,
27487        new_selected_range_utf16: Option<Range<usize>>,
27488        window: &mut Window,
27489        cx: &mut Context<Self>,
27490    ) {
27491        if !self.input_enabled {
27492            return;
27493        }
27494
27495        let transaction = self.transact(window, cx, |this, window, cx| {
27496            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
27497                let snapshot = this.buffer.read(cx).read(cx);
27498                if let Some(relative_range_utf16) = range_utf16.as_ref() {
27499                    for marked_range in &mut marked_ranges {
27500                        marked_range.end = marked_range.start + relative_range_utf16.end;
27501                        marked_range.start += relative_range_utf16.start;
27502                        marked_range.start =
27503                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
27504                        marked_range.end =
27505                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
27506                    }
27507                }
27508                Some(marked_ranges)
27509            } else if let Some(range_utf16) = range_utf16 {
27510                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27511                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27512                Some(this.selection_replacement_ranges(range_utf16, cx))
27513            } else {
27514                None
27515            };
27516
27517            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
27518                let newest_selection_id = this.selections.newest_anchor().id;
27519                this.selections
27520                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27521                    .iter()
27522                    .zip(ranges_to_replace.iter())
27523                    .find_map(|(selection, range)| {
27524                        if selection.id == newest_selection_id {
27525                            Some(
27526                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27527                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27528                            )
27529                        } else {
27530                            None
27531                        }
27532                    })
27533            });
27534
27535            cx.emit(EditorEvent::InputHandled {
27536                utf16_range_to_replace: range_to_replace,
27537                text: text.into(),
27538            });
27539
27540            if let Some(ranges) = ranges_to_replace {
27541                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
27542                    s.select_ranges(ranges)
27543                });
27544            }
27545
27546            let marked_ranges = {
27547                let snapshot = this.buffer.read(cx).read(cx);
27548                this.selections
27549                    .disjoint_anchors_arc()
27550                    .iter()
27551                    .map(|selection| {
27552                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
27553                    })
27554                    .collect::<Vec<_>>()
27555            };
27556
27557            if text.is_empty() {
27558                this.unmark_text(window, cx);
27559            } else {
27560                this.highlight_text::<InputComposition>(
27561                    marked_ranges.clone(),
27562                    HighlightStyle {
27563                        underline: Some(UnderlineStyle {
27564                            thickness: px(1.),
27565                            color: None,
27566                            wavy: false,
27567                        }),
27568                        ..Default::default()
27569                    },
27570                    cx,
27571                );
27572            }
27573
27574            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
27575            let use_autoclose = this.use_autoclose;
27576            let use_auto_surround = this.use_auto_surround;
27577            this.set_use_autoclose(false);
27578            this.set_use_auto_surround(false);
27579            this.handle_input(text, window, cx);
27580            this.set_use_autoclose(use_autoclose);
27581            this.set_use_auto_surround(use_auto_surround);
27582
27583            if let Some(new_selected_range) = new_selected_range_utf16 {
27584                let snapshot = this.buffer.read(cx).read(cx);
27585                let new_selected_ranges = marked_ranges
27586                    .into_iter()
27587                    .map(|marked_range| {
27588                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
27589                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
27590                            insertion_start.0 + new_selected_range.start,
27591                        ));
27592                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
27593                            insertion_start.0 + new_selected_range.end,
27594                        ));
27595                        snapshot.clip_offset_utf16(new_start, Bias::Left)
27596                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
27597                    })
27598                    .collect::<Vec<_>>();
27599
27600                drop(snapshot);
27601                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27602                    selections.select_ranges(new_selected_ranges)
27603                });
27604            }
27605        });
27606
27607        self.ime_transaction = self.ime_transaction.or(transaction);
27608        if let Some(transaction) = self.ime_transaction {
27609            self.buffer.update(cx, |buffer, cx| {
27610                buffer.group_until_transaction(transaction, cx);
27611            });
27612        }
27613
27614        if self.text_highlights::<InputComposition>(cx).is_none() {
27615            self.ime_transaction.take();
27616        }
27617    }
27618
27619    fn bounds_for_range(
27620        &mut self,
27621        range_utf16: Range<usize>,
27622        element_bounds: gpui::Bounds<Pixels>,
27623        window: &mut Window,
27624        cx: &mut Context<Self>,
27625    ) -> Option<gpui::Bounds<Pixels>> {
27626        let text_layout_details = self.text_layout_details(window);
27627        let CharacterDimensions {
27628            em_width,
27629            em_advance,
27630            line_height,
27631        } = self.character_dimensions(window);
27632
27633        let snapshot = self.snapshot(window, cx);
27634        let scroll_position = snapshot.scroll_position();
27635        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
27636
27637        let start =
27638            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
27639        let x = Pixels::from(
27640            ScrollOffset::from(
27641                snapshot.x_for_display_point(start, &text_layout_details)
27642                    + self.gutter_dimensions.full_width(),
27643            ) - scroll_left,
27644        );
27645        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
27646
27647        Some(Bounds {
27648            origin: element_bounds.origin + point(x, y),
27649            size: size(em_width, line_height),
27650        })
27651    }
27652
27653    fn character_index_for_point(
27654        &mut self,
27655        point: gpui::Point<Pixels>,
27656        _window: &mut Window,
27657        _cx: &mut Context<Self>,
27658    ) -> Option<usize> {
27659        let position_map = self.last_position_map.as_ref()?;
27660        if !position_map.text_hitbox.contains(&point) {
27661            return None;
27662        }
27663        let display_point = position_map.point_for_position(point).previous_valid;
27664        let anchor = position_map
27665            .snapshot
27666            .display_point_to_anchor(display_point, Bias::Left);
27667        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
27668        Some(utf16_offset.0.0)
27669    }
27670
27671    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
27672        self.input_enabled
27673    }
27674}
27675
27676trait SelectionExt {
27677    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
27678    fn spanned_rows(
27679        &self,
27680        include_end_if_at_line_start: bool,
27681        map: &DisplaySnapshot,
27682    ) -> Range<MultiBufferRow>;
27683}
27684
27685impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
27686    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
27687        let start = self
27688            .start
27689            .to_point(map.buffer_snapshot())
27690            .to_display_point(map);
27691        let end = self
27692            .end
27693            .to_point(map.buffer_snapshot())
27694            .to_display_point(map);
27695        if self.reversed {
27696            end..start
27697        } else {
27698            start..end
27699        }
27700    }
27701
27702    fn spanned_rows(
27703        &self,
27704        include_end_if_at_line_start: bool,
27705        map: &DisplaySnapshot,
27706    ) -> Range<MultiBufferRow> {
27707        let start = self.start.to_point(map.buffer_snapshot());
27708        let mut end = self.end.to_point(map.buffer_snapshot());
27709        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
27710            end.row -= 1;
27711        }
27712
27713        let buffer_start = map.prev_line_boundary(start).0;
27714        let buffer_end = map.next_line_boundary(end).0;
27715        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
27716    }
27717}
27718
27719impl<T: InvalidationRegion> InvalidationStack<T> {
27720    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
27721    where
27722        S: Clone + ToOffset,
27723    {
27724        while let Some(region) = self.last() {
27725            let all_selections_inside_invalidation_ranges =
27726                if selections.len() == region.ranges().len() {
27727                    selections
27728                        .iter()
27729                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
27730                        .all(|(selection, invalidation_range)| {
27731                            let head = selection.head().to_offset(buffer);
27732                            invalidation_range.start <= head && invalidation_range.end >= head
27733                        })
27734                } else {
27735                    false
27736                };
27737
27738            if all_selections_inside_invalidation_ranges {
27739                break;
27740            } else {
27741                self.pop();
27742            }
27743        }
27744    }
27745}
27746
27747#[derive(Clone)]
27748struct ErasedEditorImpl(Entity<Editor>);
27749
27750impl ui_input::ErasedEditor for ErasedEditorImpl {
27751    fn text(&self, cx: &App) -> String {
27752        self.0.read(cx).text(cx)
27753    }
27754
27755    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
27756        self.0.update(cx, |this, cx| {
27757            this.set_text(text, window, cx);
27758        })
27759    }
27760
27761    fn clear(&self, window: &mut Window, cx: &mut App) {
27762        self.0.update(cx, |this, cx| this.clear(window, cx));
27763    }
27764
27765    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
27766        self.0.update(cx, |this, cx| {
27767            this.set_placeholder_text(text, window, cx);
27768        });
27769    }
27770
27771    fn focus_handle(&self, cx: &App) -> FocusHandle {
27772        self.0.read(cx).focus_handle(cx)
27773    }
27774
27775    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
27776        let settings = ThemeSettings::get_global(cx);
27777        let theme_color = cx.theme().colors();
27778
27779        let text_style = TextStyle {
27780            font_family: settings.ui_font.family.clone(),
27781            font_features: settings.ui_font.features.clone(),
27782            font_size: rems(0.875).into(),
27783            font_weight: settings.buffer_font.weight,
27784            font_style: FontStyle::Normal,
27785            line_height: relative(1.2),
27786            color: theme_color.text,
27787            ..Default::default()
27788        };
27789        let editor_style = EditorStyle {
27790            background: theme_color.ghost_element_background,
27791            local_player: cx.theme().players().local(),
27792            syntax: cx.theme().syntax().clone(),
27793            text: text_style,
27794            ..Default::default()
27795        };
27796        EditorElement::new(&self.0, editor_style).into_any()
27797    }
27798
27799    fn as_any(&self) -> &dyn Any {
27800        &self.0
27801    }
27802
27803    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
27804        self.0.update(cx, |editor, cx| {
27805            let editor_offset = editor.buffer().read(cx).len(cx);
27806            editor.change_selections(
27807                SelectionEffects::scroll(Autoscroll::Next),
27808                window,
27809                cx,
27810                |s| s.select_ranges(Some(editor_offset..editor_offset)),
27811            );
27812        });
27813    }
27814
27815    fn subscribe(
27816        &self,
27817        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
27818        window: &mut Window,
27819        cx: &mut App,
27820    ) -> Subscription {
27821        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
27822            let event = match event {
27823                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
27824                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
27825                _ => return,
27826            };
27827            (callback)(event, window, cx);
27828        })
27829    }
27830}
27831impl<T> Default for InvalidationStack<T> {
27832    fn default() -> Self {
27833        Self(Default::default())
27834    }
27835}
27836
27837impl<T> Deref for InvalidationStack<T> {
27838    type Target = Vec<T>;
27839
27840    fn deref(&self) -> &Self::Target {
27841        &self.0
27842    }
27843}
27844
27845impl<T> DerefMut for InvalidationStack<T> {
27846    fn deref_mut(&mut self) -> &mut Self::Target {
27847        &mut self.0
27848    }
27849}
27850
27851impl InvalidationRegion for SnippetState {
27852    fn ranges(&self) -> &[Range<Anchor>] {
27853        &self.ranges[self.active_index]
27854    }
27855}
27856
27857fn edit_prediction_edit_text(
27858    current_snapshot: &BufferSnapshot,
27859    edits: &[(Range<Anchor>, impl AsRef<str>)],
27860    edit_preview: &EditPreview,
27861    include_deletions: bool,
27862    cx: &App,
27863) -> HighlightedText {
27864    let edits = edits
27865        .iter()
27866        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
27867        .collect::<Vec<_>>();
27868
27869    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
27870}
27871
27872fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
27873    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
27874    // Just show the raw edit text with basic styling
27875    let mut text = String::new();
27876    let mut highlights = Vec::new();
27877
27878    let insertion_highlight_style = HighlightStyle {
27879        color: Some(cx.theme().colors().text),
27880        ..Default::default()
27881    };
27882
27883    for (_, edit_text) in edits {
27884        let start_offset = text.len();
27885        text.push_str(edit_text);
27886        let end_offset = text.len();
27887
27888        if start_offset < end_offset {
27889            highlights.push((start_offset..end_offset, insertion_highlight_style));
27890        }
27891    }
27892
27893    HighlightedText {
27894        text: text.into(),
27895        highlights,
27896    }
27897}
27898
27899pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
27900    match severity {
27901        lsp::DiagnosticSeverity::ERROR => colors.error,
27902        lsp::DiagnosticSeverity::WARNING => colors.warning,
27903        lsp::DiagnosticSeverity::INFORMATION => colors.info,
27904        lsp::DiagnosticSeverity::HINT => colors.info,
27905        _ => colors.ignored,
27906    }
27907}
27908
27909pub fn styled_runs_for_code_label<'a>(
27910    label: &'a CodeLabel,
27911    syntax_theme: &'a theme::SyntaxTheme,
27912    local_player: &'a theme::PlayerColor,
27913) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
27914    let fade_out = HighlightStyle {
27915        fade_out: Some(0.35),
27916        ..Default::default()
27917    };
27918
27919    let mut prev_end = label.filter_range.end;
27920    label
27921        .runs
27922        .iter()
27923        .enumerate()
27924        .flat_map(move |(ix, (range, highlight_id))| {
27925            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
27926                HighlightStyle {
27927                    color: Some(local_player.cursor),
27928                    ..Default::default()
27929                }
27930            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
27931                HighlightStyle {
27932                    background_color: Some(local_player.selection),
27933                    ..Default::default()
27934                }
27935            } else if let Some(style) = highlight_id.style(syntax_theme) {
27936                style
27937            } else {
27938                return Default::default();
27939            };
27940            let muted_style = style.highlight(fade_out);
27941
27942            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
27943            if range.start >= label.filter_range.end {
27944                if range.start > prev_end {
27945                    runs.push((prev_end..range.start, fade_out));
27946                }
27947                runs.push((range.clone(), muted_style));
27948            } else if range.end <= label.filter_range.end {
27949                runs.push((range.clone(), style));
27950            } else {
27951                runs.push((range.start..label.filter_range.end, style));
27952                runs.push((label.filter_range.end..range.end, muted_style));
27953            }
27954            prev_end = cmp::max(prev_end, range.end);
27955
27956            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
27957                runs.push((prev_end..label.text.len(), fade_out));
27958            }
27959
27960            runs
27961        })
27962}
27963
27964pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
27965    let mut prev_index = 0;
27966    let mut prev_codepoint: Option<char> = None;
27967    text.char_indices()
27968        .chain([(text.len(), '\0')])
27969        .filter_map(move |(index, codepoint)| {
27970            let prev_codepoint = prev_codepoint.replace(codepoint)?;
27971            let is_boundary = index == text.len()
27972                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
27973                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
27974            if is_boundary {
27975                let chunk = &text[prev_index..index];
27976                prev_index = index;
27977                Some(chunk)
27978            } else {
27979                None
27980            }
27981        })
27982}
27983
27984/// Given a string of text immediately before the cursor, iterates over possible
27985/// strings a snippet could match to. More precisely: returns an iterator over
27986/// suffixes of `text` created by splitting at word boundaries (before & after
27987/// every non-word character).
27988///
27989/// Shorter suffixes are returned first.
27990pub(crate) fn snippet_candidate_suffixes(
27991    text: &str,
27992    is_word_char: impl Fn(char) -> bool,
27993) -> impl std::iter::Iterator<Item = &str> {
27994    let mut prev_index = text.len();
27995    let mut prev_codepoint = None;
27996    text.char_indices()
27997        .rev()
27998        .chain([(0, '\0')])
27999        .filter_map(move |(index, codepoint)| {
28000            let prev_index = std::mem::replace(&mut prev_index, index);
28001            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28002            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28003                None
28004            } else {
28005                let chunk = &text[prev_index..]; // go to end of string
28006                Some(chunk)
28007            }
28008        })
28009}
28010
28011pub trait RangeToAnchorExt: Sized {
28012    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28013
28014    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28015        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28016        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28017    }
28018}
28019
28020impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28021    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28022        let start_offset = self.start.to_offset(snapshot);
28023        let end_offset = self.end.to_offset(snapshot);
28024        if start_offset == end_offset {
28025            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28026        } else {
28027            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28028        }
28029    }
28030}
28031
28032pub trait RowExt {
28033    fn as_f64(&self) -> f64;
28034
28035    fn next_row(&self) -> Self;
28036
28037    fn previous_row(&self) -> Self;
28038
28039    fn minus(&self, other: Self) -> u32;
28040}
28041
28042impl RowExt for DisplayRow {
28043    fn as_f64(&self) -> f64 {
28044        self.0 as _
28045    }
28046
28047    fn next_row(&self) -> Self {
28048        Self(self.0 + 1)
28049    }
28050
28051    fn previous_row(&self) -> Self {
28052        Self(self.0.saturating_sub(1))
28053    }
28054
28055    fn minus(&self, other: Self) -> u32 {
28056        self.0 - other.0
28057    }
28058}
28059
28060impl RowExt for MultiBufferRow {
28061    fn as_f64(&self) -> f64 {
28062        self.0 as _
28063    }
28064
28065    fn next_row(&self) -> Self {
28066        Self(self.0 + 1)
28067    }
28068
28069    fn previous_row(&self) -> Self {
28070        Self(self.0.saturating_sub(1))
28071    }
28072
28073    fn minus(&self, other: Self) -> u32 {
28074        self.0 - other.0
28075    }
28076}
28077
28078trait RowRangeExt {
28079    type Row;
28080
28081    fn len(&self) -> usize;
28082
28083    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
28084}
28085
28086impl RowRangeExt for Range<MultiBufferRow> {
28087    type Row = MultiBufferRow;
28088
28089    fn len(&self) -> usize {
28090        (self.end.0 - self.start.0) as usize
28091    }
28092
28093    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
28094        (self.start.0..self.end.0).map(MultiBufferRow)
28095    }
28096}
28097
28098impl RowRangeExt for Range<DisplayRow> {
28099    type Row = DisplayRow;
28100
28101    fn len(&self) -> usize {
28102        (self.end.0 - self.start.0) as usize
28103    }
28104
28105    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
28106        (self.start.0..self.end.0).map(DisplayRow)
28107    }
28108}
28109
28110/// If select range has more than one line, we
28111/// just point the cursor to range.start.
28112fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
28113    if range.start.row == range.end.row {
28114        range
28115    } else {
28116        range.start..range.start
28117    }
28118}
28119pub struct KillRing(ClipboardItem);
28120impl Global for KillRing {}
28121
28122const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
28123
28124enum BreakpointPromptEditAction {
28125    Log,
28126    Condition,
28127    HitCondition,
28128}
28129
28130struct BreakpointPromptEditor {
28131    pub(crate) prompt: Entity<Editor>,
28132    editor: WeakEntity<Editor>,
28133    breakpoint_anchor: Anchor,
28134    breakpoint: Breakpoint,
28135    edit_action: BreakpointPromptEditAction,
28136    block_ids: HashSet<CustomBlockId>,
28137    editor_margins: Arc<Mutex<EditorMargins>>,
28138    _subscriptions: Vec<Subscription>,
28139}
28140
28141impl BreakpointPromptEditor {
28142    const MAX_LINES: u8 = 4;
28143
28144    fn new(
28145        editor: WeakEntity<Editor>,
28146        breakpoint_anchor: Anchor,
28147        breakpoint: Breakpoint,
28148        edit_action: BreakpointPromptEditAction,
28149        window: &mut Window,
28150        cx: &mut Context<Self>,
28151    ) -> Self {
28152        let base_text = match edit_action {
28153            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
28154            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
28155            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
28156        }
28157        .map(|msg| msg.to_string())
28158        .unwrap_or_default();
28159
28160        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
28161        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
28162
28163        let prompt = cx.new(|cx| {
28164            let mut prompt = Editor::new(
28165                EditorMode::AutoHeight {
28166                    min_lines: 1,
28167                    max_lines: Some(Self::MAX_LINES as usize),
28168                },
28169                buffer,
28170                None,
28171                window,
28172                cx,
28173            );
28174            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
28175            prompt.set_show_cursor_when_unfocused(false, cx);
28176            prompt.set_placeholder_text(
28177                match edit_action {
28178                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
28179                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
28180                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
28181                },
28182                window,
28183                cx,
28184            );
28185
28186            prompt
28187        });
28188
28189        Self {
28190            prompt,
28191            editor,
28192            breakpoint_anchor,
28193            breakpoint,
28194            edit_action,
28195            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
28196            block_ids: Default::default(),
28197            _subscriptions: vec![],
28198        }
28199    }
28200
28201    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
28202        self.block_ids.extend(block_ids)
28203    }
28204
28205    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
28206        if let Some(editor) = self.editor.upgrade() {
28207            let message = self
28208                .prompt
28209                .read(cx)
28210                .buffer
28211                .read(cx)
28212                .as_singleton()
28213                .expect("A multi buffer in breakpoint prompt isn't possible")
28214                .read(cx)
28215                .as_rope()
28216                .to_string();
28217
28218            editor.update(cx, |editor, cx| {
28219                editor.edit_breakpoint_at_anchor(
28220                    self.breakpoint_anchor,
28221                    self.breakpoint.clone(),
28222                    match self.edit_action {
28223                        BreakpointPromptEditAction::Log => {
28224                            BreakpointEditAction::EditLogMessage(message.into())
28225                        }
28226                        BreakpointPromptEditAction::Condition => {
28227                            BreakpointEditAction::EditCondition(message.into())
28228                        }
28229                        BreakpointPromptEditAction::HitCondition => {
28230                            BreakpointEditAction::EditHitCondition(message.into())
28231                        }
28232                    },
28233                    cx,
28234                );
28235
28236                editor.remove_blocks(self.block_ids.clone(), None, cx);
28237                cx.focus_self(window);
28238            });
28239        }
28240    }
28241
28242    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
28243        self.editor
28244            .update(cx, |editor, cx| {
28245                editor.remove_blocks(self.block_ids.clone(), None, cx);
28246                window.focus(&editor.focus_handle, cx);
28247            })
28248            .log_err();
28249    }
28250
28251    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
28252        let settings = ThemeSettings::get_global(cx);
28253        let text_style = TextStyle {
28254            color: if self.prompt.read(cx).read_only(cx) {
28255                cx.theme().colors().text_disabled
28256            } else {
28257                cx.theme().colors().text
28258            },
28259            font_family: settings.buffer_font.family.clone(),
28260            font_fallbacks: settings.buffer_font.fallbacks.clone(),
28261            font_size: settings.buffer_font_size(cx).into(),
28262            font_weight: settings.buffer_font.weight,
28263            line_height: relative(settings.buffer_line_height.value()),
28264            ..Default::default()
28265        };
28266        EditorElement::new(
28267            &self.prompt,
28268            EditorStyle {
28269                background: cx.theme().colors().editor_background,
28270                local_player: cx.theme().players().local(),
28271                text: text_style,
28272                ..Default::default()
28273            },
28274        )
28275    }
28276}
28277
28278impl Render for BreakpointPromptEditor {
28279    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28280        let editor_margins = *self.editor_margins.lock();
28281        let gutter_dimensions = editor_margins.gutter;
28282        h_flex()
28283            .key_context("Editor")
28284            .bg(cx.theme().colors().editor_background)
28285            .border_y_1()
28286            .border_color(cx.theme().status().info_border)
28287            .size_full()
28288            .py(window.line_height() / 2.5)
28289            .on_action(cx.listener(Self::confirm))
28290            .on_action(cx.listener(Self::cancel))
28291            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
28292            .child(div().flex_1().child(self.render_prompt_editor(cx)))
28293    }
28294}
28295
28296impl Focusable for BreakpointPromptEditor {
28297    fn focus_handle(&self, cx: &App) -> FocusHandle {
28298        self.prompt.focus_handle(cx)
28299    }
28300}
28301
28302fn all_edits_insertions_or_deletions(
28303    edits: &Vec<(Range<Anchor>, Arc<str>)>,
28304    snapshot: &MultiBufferSnapshot,
28305) -> bool {
28306    let mut all_insertions = true;
28307    let mut all_deletions = true;
28308
28309    for (range, new_text) in edits.iter() {
28310        let range_is_empty = range.to_offset(snapshot).is_empty();
28311        let text_is_empty = new_text.is_empty();
28312
28313        if range_is_empty != text_is_empty {
28314            if range_is_empty {
28315                all_deletions = false;
28316            } else {
28317                all_insertions = false;
28318            }
28319        } else {
28320            return false;
28321        }
28322
28323        if !all_insertions && !all_deletions {
28324            return false;
28325        }
28326    }
28327    all_insertions || all_deletions
28328}
28329
28330struct MissingEditPredictionKeybindingTooltip;
28331
28332impl Render for MissingEditPredictionKeybindingTooltip {
28333    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28334        ui::tooltip_container(cx, |container, cx| {
28335            container
28336                .flex_shrink_0()
28337                .max_w_80()
28338                .min_h(rems_from_px(124.))
28339                .justify_between()
28340                .child(
28341                    v_flex()
28342                        .flex_1()
28343                        .text_ui_sm(cx)
28344                        .child(Label::new("Conflict with Accept Keybinding"))
28345                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
28346                )
28347                .child(
28348                    h_flex()
28349                        .pb_1()
28350                        .gap_1()
28351                        .items_end()
28352                        .w_full()
28353                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
28354                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
28355                        }))
28356                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
28357                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
28358                        })),
28359                )
28360        })
28361    }
28362}
28363
28364#[derive(Debug, Clone, Copy, PartialEq)]
28365pub struct LineHighlight {
28366    pub background: Background,
28367    pub border: Option<gpui::Hsla>,
28368    pub include_gutter: bool,
28369    pub type_id: Option<TypeId>,
28370}
28371
28372struct LineManipulationResult {
28373    pub new_text: String,
28374    pub line_count_before: usize,
28375    pub line_count_after: usize,
28376}
28377
28378fn render_diff_hunk_controls(
28379    row: u32,
28380    status: &DiffHunkStatus,
28381    hunk_range: Range<Anchor>,
28382    is_created_file: bool,
28383    line_height: Pixels,
28384    editor: &Entity<Editor>,
28385    _window: &mut Window,
28386    cx: &mut App,
28387) -> AnyElement {
28388    h_flex()
28389        .h(line_height)
28390        .mr_1()
28391        .gap_1()
28392        .px_0p5()
28393        .pb_1()
28394        .border_x_1()
28395        .border_b_1()
28396        .border_color(cx.theme().colors().border_variant)
28397        .rounded_b_lg()
28398        .bg(cx.theme().colors().editor_background)
28399        .gap_1()
28400        .block_mouse_except_scroll()
28401        .shadow_md()
28402        .child(if status.has_secondary_hunk() {
28403            Button::new(("stage", row as u64), "Stage")
28404                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28405                .tooltip({
28406                    let focus_handle = editor.focus_handle(cx);
28407                    move |_window, cx| {
28408                        Tooltip::for_action_in(
28409                            "Stage Hunk",
28410                            &::git::ToggleStaged,
28411                            &focus_handle,
28412                            cx,
28413                        )
28414                    }
28415                })
28416                .on_click({
28417                    let editor = editor.clone();
28418                    move |_event, _window, cx| {
28419                        editor.update(cx, |editor, cx| {
28420                            editor.stage_or_unstage_diff_hunks(
28421                                true,
28422                                vec![hunk_range.start..hunk_range.start],
28423                                cx,
28424                            );
28425                        });
28426                    }
28427                })
28428        } else {
28429            Button::new(("unstage", row as u64), "Unstage")
28430                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28431                .tooltip({
28432                    let focus_handle = editor.focus_handle(cx);
28433                    move |_window, cx| {
28434                        Tooltip::for_action_in(
28435                            "Unstage Hunk",
28436                            &::git::ToggleStaged,
28437                            &focus_handle,
28438                            cx,
28439                        )
28440                    }
28441                })
28442                .on_click({
28443                    let editor = editor.clone();
28444                    move |_event, _window, cx| {
28445                        editor.update(cx, |editor, cx| {
28446                            editor.stage_or_unstage_diff_hunks(
28447                                false,
28448                                vec![hunk_range.start..hunk_range.start],
28449                                cx,
28450                            );
28451                        });
28452                    }
28453                })
28454        })
28455        .child(
28456            Button::new(("restore", row as u64), "Restore")
28457                .tooltip({
28458                    let focus_handle = editor.focus_handle(cx);
28459                    move |_window, cx| {
28460                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
28461                    }
28462                })
28463                .on_click({
28464                    let editor = editor.clone();
28465                    move |_event, window, cx| {
28466                        editor.update(cx, |editor, cx| {
28467                            let snapshot = editor.snapshot(window, cx);
28468                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
28469                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
28470                        });
28471                    }
28472                })
28473                .disabled(is_created_file),
28474        )
28475        .when(
28476            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
28477            |el| {
28478                el.child(
28479                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
28480                        .shape(IconButtonShape::Square)
28481                        .icon_size(IconSize::Small)
28482                        // .disabled(!has_multiple_hunks)
28483                        .tooltip({
28484                            let focus_handle = editor.focus_handle(cx);
28485                            move |_window, cx| {
28486                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
28487                            }
28488                        })
28489                        .on_click({
28490                            let editor = editor.clone();
28491                            move |_event, window, cx| {
28492                                editor.update(cx, |editor, cx| {
28493                                    let snapshot = editor.snapshot(window, cx);
28494                                    let position =
28495                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
28496                                    editor.go_to_hunk_before_or_after_position(
28497                                        &snapshot,
28498                                        position,
28499                                        Direction::Next,
28500                                        window,
28501                                        cx,
28502                                    );
28503                                    editor.expand_selected_diff_hunks(cx);
28504                                });
28505                            }
28506                        }),
28507                )
28508                .child(
28509                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
28510                        .shape(IconButtonShape::Square)
28511                        .icon_size(IconSize::Small)
28512                        // .disabled(!has_multiple_hunks)
28513                        .tooltip({
28514                            let focus_handle = editor.focus_handle(cx);
28515                            move |_window, cx| {
28516                                Tooltip::for_action_in(
28517                                    "Previous Hunk",
28518                                    &GoToPreviousHunk,
28519                                    &focus_handle,
28520                                    cx,
28521                                )
28522                            }
28523                        })
28524                        .on_click({
28525                            let editor = editor.clone();
28526                            move |_event, window, cx| {
28527                                editor.update(cx, |editor, cx| {
28528                                    let snapshot = editor.snapshot(window, cx);
28529                                    let point =
28530                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
28531                                    editor.go_to_hunk_before_or_after_position(
28532                                        &snapshot,
28533                                        point,
28534                                        Direction::Prev,
28535                                        window,
28536                                        cx,
28537                                    );
28538                                    editor.expand_selected_diff_hunks(cx);
28539                                });
28540                            }
28541                        }),
28542                )
28543            },
28544        )
28545        .into_any_element()
28546}
28547
28548pub fn multibuffer_context_lines(cx: &App) -> u32 {
28549    EditorSettings::try_get(cx)
28550        .map(|settings| settings.excerpt_context_lines)
28551        .unwrap_or(2)
28552        .min(32)
28553}