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 document_colors;
   21mod document_symbols;
   22mod editor_settings;
   23mod element;
   24mod folding_ranges;
   25mod git;
   26mod highlight_matching_bracket;
   27mod hover_links;
   28pub mod hover_popover;
   29mod indent_guides;
   30mod inlays;
   31pub mod items;
   32mod jsx_tag_auto_close;
   33mod linked_editing_ranges;
   34mod lsp_ext;
   35mod mouse_context_menu;
   36pub mod movement;
   37mod persistence;
   38mod runnables;
   39mod rust_analyzer_ext;
   40pub mod scroll;
   41mod selections_collection;
   42pub mod semantic_tokens;
   43mod split;
   44pub mod split_editor_view;
   45
   46#[cfg(test)]
   47mod code_completion_tests;
   48#[cfg(test)]
   49mod edit_prediction_tests;
   50#[cfg(test)]
   51mod editor_tests;
   52mod signature_help;
   53#[cfg(any(test, feature = "test-support"))]
   54pub mod test;
   55
   56pub(crate) use actions::*;
   57pub use display_map::{
   58    ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder, HighlightKey,
   59    SemanticTokenHighlight,
   60};
   61pub use edit_prediction_types::Direction;
   62pub use editor_settings::{
   63    CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
   64    EditorSettings, EditorSettingsScrollbarProxy, HideMouseMode, ScrollBeyondLastLine,
   65    ScrollbarAxes, SearchSettings, ShowMinimap, ui_scrollbar_settings_from_raw,
   66};
   67pub use element::{
   68    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   69    render_breadcrumb_text,
   70};
   71pub use git::blame::BlameRenderer;
   72pub use hover_popover::hover_markdown_style;
   73pub use inlays::Inlay;
   74pub use items::MAX_TAB_TITLE_LEN;
   75pub use linked_editing_ranges::LinkedEdits;
   76pub use lsp::CompletionContext;
   77pub use lsp_ext::lsp_tasks;
   78pub use multi_buffer::{
   79    Anchor, AnchorRangeExt, BufferOffset, ExcerptRange, MBTextSummary, MultiBuffer,
   80    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   81    ToPoint,
   82};
   83pub use split::{SplittableEditor, ToggleSplitDiff};
   84pub use split_editor_view::SplitEditorView;
   85pub use text::Bias;
   86
   87use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   88use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   89use anyhow::{Context as _, Result, anyhow, bail};
   90use blink_manager::BlinkManager;
   91use buffer_diff::DiffHunkStatus;
   92use client::{Collaborator, ParticipantIndex, parse_zed_link};
   93use clock::ReplicaId;
   94use code_context_menus::{
   95    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   96    CompletionsMenu, ContextMenuOrigin,
   97};
   98use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   99use convert_case::{Case, Casing};
  100use dap::TelemetrySpawnLocation;
  101use display_map::*;
  102use document_colors::LspColorData;
  103use edit_prediction_types::{
  104    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason,
  105    EditPredictionGranularity, SuggestionDisplayType,
  106};
  107use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
  108use element::{LineWithInvisibles, PositionMap, layout_line};
  109use futures::{
  110    FutureExt,
  111    future::{self, Shared, join},
  112};
  113use fuzzy::{StringMatch, StringMatchCandidate};
  114use git::blame::{GitBlame, GlobalBlameRenderer};
  115use gpui::{
  116    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  117    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  118    DispatchPhase, Edges, Entity, EntityId, EntityInputHandler, EventEmitter, FocusHandle,
  119    FocusOutEvent, Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla,
  120    KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement,
  121    Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled,
  122    Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  123    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  124    pulsating_between, px, relative, size,
  125};
  126use hover_links::{HoverLink, HoveredLinkState, find_file};
  127use hover_popover::{HoverState, hide_hover};
  128use indent_guides::ActiveIndentGuidesState;
  129use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  130use itertools::{Either, Itertools};
  131use language::{
  132    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  133    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  134    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  135    IndentSize, Language, LanguageAwareStyling, LanguageName, LanguageRegistry, LanguageScope,
  136    LocalFile, OffsetRangeExt, OutlineItem, Point, Selection, SelectionGoal, TextObject,
  137    TransactionId, TreeSitterOptions, WordsQuery,
  138    language_settings::{
  139        self, AllLanguageSettings, LanguageSettings, LspInsertMode, RewrapBehavior,
  140        WordsCompletionMode, all_language_settings,
  141    },
  142    point_from_lsp, point_to_lsp, text_diff_with_options,
  143};
  144use linked_editing_ranges::refresh_linked_ranges;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId,
  148};
  149use markdown::Markdown;
  150use mouse_context_menu::MouseContextMenu;
  151use movement::TextLayoutDetails;
  152use multi_buffer::{
  153    ExcerptBoundaryInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint,
  154    MultiBufferRow,
  155};
  156use parking_lot::Mutex;
  157use persistence::EditorDb;
  158use project::{
  159    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  160    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  161    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  162    ProjectItem, ProjectPath, ProjectTransaction,
  163    debugger::{
  164        breakpoint_store::{
  165            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  166            BreakpointStore, BreakpointStoreEvent,
  167        },
  168        session::{Session, SessionEvent},
  169    },
  170    git_store::GitStoreEvent,
  171    lsp_store::{
  172        BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger,
  173        LspFormatTarget, OpenLspBufferHandle, RefreshForServer,
  174    },
  175    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  176};
  177use rand::seq::SliceRandom;
  178use regex::Regex;
  179use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  180use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};
  181use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  182use serde::{Deserialize, Serialize};
  183use settings::{
  184    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  185    update_settings_file,
  186};
  187use smallvec::{SmallVec, smallvec};
  188use snippet::Snippet;
  189use std::{
  190    any::{Any, TypeId},
  191    borrow::Cow,
  192    cell::{OnceCell, RefCell},
  193    cmp::{self, Ordering, Reverse},
  194    collections::hash_map,
  195    iter::{self, Peekable},
  196    mem,
  197    num::NonZeroU32,
  198    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  199    path::{Path, PathBuf},
  200    rc::Rc,
  201    sync::Arc,
  202    time::{Duration, Instant},
  203};
  204use task::TaskVariables;
  205use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};
  206use theme::{
  207    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  208};
  209use theme_settings::{ThemeSettings, observe_buffer_font_size_adjustment};
  210use ui::{
  211    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  212    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  213    utils::WithRemSize,
  214};
  215use ui_input::ErasedEditor;
  216use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  217use workspace::{
  218    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  219    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  220    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  221    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  222    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  223    searchable::SearchEvent,
  224};
  225pub use zed_actions::editor::RevealInFileManager;
  226use zed_actions::editor::{MoveDown, MoveUp};
  227
  228use crate::{
  229    code_context_menus::CompletionsMenuSource,
  230    editor_settings::MultiCursorModifier,
  231    hover_links::{find_url, find_url_from_range},
  232    inlays::{
  233        InlineValueCache,
  234        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  235    },
  236    runnables::{ResolvedTasks, RunnableData, RunnableTasks},
  237    scroll::{ScrollOffset, ScrollPixelOffset},
  238    selections_collection::resolve_selections_wrapping_blocks,
  239    semantic_tokens::SemanticTokenState,
  240    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  241};
  242
  243pub const FILE_HEADER_HEIGHT: u32 = 2;
  244pub const BUFFER_HEADER_PADDING: Rems = rems(0.25);
  245pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  246const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  247const MAX_LINE_LEN: usize = 1024;
  248const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  249const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  250pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  251#[doc(hidden)]
  252pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  253pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  254
  255pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  256pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  257pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  258pub const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50);
  259
  260pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  261pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  262
  263pub type RenderDiffHunkControlsFn = Arc<
  264    dyn Fn(
  265        u32,
  266        &DiffHunkStatus,
  267        Range<Anchor>,
  268        bool,
  269        Pixels,
  270        &Entity<Editor>,
  271        &mut Window,
  272        &mut App,
  273    ) -> AnyElement,
  274>;
  275
  276enum ReportEditorEvent {
  277    Saved { auto_saved: bool },
  278    EditorOpened,
  279    Closed,
  280}
  281
  282impl ReportEditorEvent {
  283    pub fn event_type(&self) -> &'static str {
  284        match self {
  285            Self::Saved { .. } => "Editor Saved",
  286            Self::EditorOpened => "Editor Opened",
  287            Self::Closed => "Editor Closed",
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294
  295pub enum ConflictsOuter {}
  296pub enum ConflictsOurs {}
  297pub enum ConflictsTheirs {}
  298pub enum ConflictsOursMarker {}
  299pub enum ConflictsTheirsMarker {}
  300
  301pub struct HunkAddedColor;
  302pub struct HunkRemovedColor;
  303
  304#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  305pub enum Navigated {
  306    Yes,
  307    No,
  308}
  309
  310impl Navigated {
  311    pub fn from_bool(yes: bool) -> Navigated {
  312        if yes { Navigated::Yes } else { Navigated::No }
  313    }
  314}
  315
  316#[derive(Debug, Clone, PartialEq, Eq)]
  317enum DisplayDiffHunk {
  318    Folded {
  319        display_row: DisplayRow,
  320    },
  321    Unfolded {
  322        is_created_file: bool,
  323        diff_base_byte_range: Range<usize>,
  324        display_row_range: Range<DisplayRow>,
  325        multi_buffer_range: Range<Anchor>,
  326        status: DiffHunkStatus,
  327        word_diffs: Vec<Range<MultiBufferOffset>>,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init(cx: &mut App) {
  337    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  338    cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
  339
  340    workspace::register_project_item::<Editor>(cx);
  341    workspace::FollowableViewRegistry::register::<Editor>(cx);
  342    workspace::register_serializable_item::<Editor>(cx);
  343
  344    cx.observe_new(
  345        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  346            workspace.register_action(Editor::new_file);
  347            workspace.register_action(Editor::new_file_split);
  348            workspace.register_action(Editor::new_file_vertical);
  349            workspace.register_action(Editor::new_file_horizontal);
  350            workspace.register_action(Editor::cancel_language_server_work);
  351            workspace.register_action(Editor::toggle_focus);
  352        },
  353    )
  354    .detach();
  355
  356    cx.on_action(move |_: &workspace::NewFile, cx| {
  357        let app_state = workspace::AppState::global(cx);
  358        workspace::open_new(
  359            Default::default(),
  360            app_state,
  361            cx,
  362            |workspace, window, cx| Editor::new_file(workspace, &Default::default(), window, cx),
  363        )
  364        .detach_and_log_err(cx);
  365    })
  366    .on_action(move |_: &workspace::NewWindow, cx| {
  367        let app_state = workspace::AppState::global(cx);
  368        workspace::open_new(
  369            Default::default(),
  370            app_state,
  371            cx,
  372            |workspace, window, cx| {
  373                cx.activate(true);
  374                Editor::new_file(workspace, &Default::default(), window, cx)
  375            },
  376        )
  377        .detach_and_log_err(cx);
  378    });
  379    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  380        Arc::new(ErasedEditorImpl(
  381            cx.new(|cx| Editor::single_line(window, cx)),
  382        )) as Arc<dyn ErasedEditor>
  383    });
  384    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  385}
  386
  387pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  388    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  389}
  390
  391pub trait DiagnosticRenderer {
  392    fn render_group(
  393        &self,
  394        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  395        buffer_id: BufferId,
  396        snapshot: EditorSnapshot,
  397        editor: WeakEntity<Editor>,
  398        language_registry: Option<Arc<LanguageRegistry>>,
  399        cx: &mut App,
  400    ) -> Vec<BlockProperties<Anchor>>;
  401
  402    fn render_hover(
  403        &self,
  404        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  405        range: Range<Point>,
  406        buffer_id: BufferId,
  407        language_registry: Option<Arc<LanguageRegistry>>,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  479pub enum SizingBehavior {
  480    /// The editor will layout itself using `size_full` and will include the vertical
  481    /// scroll margin as requested by user settings.
  482    #[default]
  483    Default,
  484    /// The editor will layout itself using `size_full`, but will not have any
  485    /// vertical overscroll.
  486    ExcludeOverscrollMargin,
  487    /// The editor will request a vertical size according to its content and will be
  488    /// layouted without a vertical scroll margin.
  489    SizeByContent,
  490}
  491
  492#[derive(Clone, PartialEq, Eq, Debug)]
  493pub enum EditorMode {
  494    SingleLine,
  495    AutoHeight {
  496        min_lines: usize,
  497        max_lines: Option<usize>,
  498    },
  499    Full {
  500        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  501        scale_ui_elements_with_buffer_font_size: bool,
  502        /// When set to `true`, the editor will render a background for the active line.
  503        show_active_line_background: bool,
  504        /// Determines the sizing behavior for this editor
  505        sizing_behavior: SizingBehavior,
  506    },
  507    Minimap {
  508        parent: WeakEntity<Editor>,
  509    },
  510}
  511
  512impl EditorMode {
  513    pub fn full() -> Self {
  514        Self::Full {
  515            scale_ui_elements_with_buffer_font_size: true,
  516            show_active_line_background: true,
  517            sizing_behavior: SizingBehavior::Default,
  518        }
  519    }
  520
  521    #[inline]
  522    pub fn is_full(&self) -> bool {
  523        matches!(self, Self::Full { .. })
  524    }
  525
  526    #[inline]
  527    pub fn is_single_line(&self) -> bool {
  528        matches!(self, Self::SingleLine { .. })
  529    }
  530
  531    #[inline]
  532    fn is_minimap(&self) -> bool {
  533        matches!(self, Self::Minimap { .. })
  534    }
  535}
  536
  537#[derive(Copy, Clone, Debug)]
  538pub enum SoftWrap {
  539    /// Prefer not to wrap at all.
  540    ///
  541    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  542    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  543    GitDiff,
  544    /// Prefer a single line generally, unless an overly long line is encountered.
  545    None,
  546    /// Soft wrap lines that exceed the editor width.
  547    EditorWidth,
  548    /// Soft wrap lines at the preferred line length.
  549    Column(u32),
  550    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  551    Bounded(u32),
  552}
  553
  554#[derive(Clone)]
  555pub struct EditorStyle {
  556    pub background: Hsla,
  557    pub border: Hsla,
  558    pub local_player: PlayerColor,
  559    pub text: TextStyle,
  560    pub scrollbar_width: Pixels,
  561    pub syntax: Arc<SyntaxTheme>,
  562    pub status: StatusColors,
  563    pub inlay_hints_style: HighlightStyle,
  564    pub edit_prediction_styles: EditPredictionStyles,
  565    pub unnecessary_code_fade: f32,
  566    pub show_underlines: bool,
  567}
  568
  569impl Default for EditorStyle {
  570    fn default() -> Self {
  571        Self {
  572            background: Hsla::default(),
  573            border: Hsla::default(),
  574            local_player: PlayerColor::default(),
  575            text: TextStyle::default(),
  576            scrollbar_width: Pixels::default(),
  577            syntax: Default::default(),
  578            // HACK: Status colors don't have a real default.
  579            // We should look into removing the status colors from the editor
  580            // style and retrieve them directly from the theme.
  581            status: StatusColors::dark(),
  582            inlay_hints_style: HighlightStyle::default(),
  583            edit_prediction_styles: EditPredictionStyles {
  584                insertion: HighlightStyle::default(),
  585                whitespace: HighlightStyle::default(),
  586            },
  587            unnecessary_code_fade: Default::default(),
  588            show_underlines: true,
  589        }
  590    }
  591}
  592
  593pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  594    let show_background = AllLanguageSettings::get_global(cx)
  595        .defaults
  596        .inlay_hints
  597        .show_background;
  598
  599    let mut style = cx
  600        .theme()
  601        .syntax()
  602        .style_for_name("hint")
  603        .unwrap_or_default();
  604
  605    if style.color.is_none() {
  606        style.color = Some(cx.theme().status().hint);
  607    }
  608
  609    if !show_background {
  610        style.background_color = None;
  611        return style;
  612    }
  613
  614    if style.background_color.is_none() {
  615        style.background_color = Some(cx.theme().status().hint_background);
  616    }
  617
  618    style
  619}
  620
  621pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  622    EditPredictionStyles {
  623        insertion: HighlightStyle {
  624            color: Some(cx.theme().status().predictive),
  625            ..HighlightStyle::default()
  626        },
  627        whitespace: HighlightStyle {
  628            background_color: Some(cx.theme().status().created_background),
  629            ..HighlightStyle::default()
  630        },
  631    }
  632}
  633
  634type CompletionId = usize;
  635
  636pub(crate) enum EditDisplayMode {
  637    TabAccept,
  638    DiffPopover,
  639    Inline,
  640}
  641
  642enum EditPrediction {
  643    Edit {
  644        // TODO could be a language::Anchor?
  645        edits: Vec<(Range<Anchor>, Arc<str>)>,
  646        /// Predicted cursor position as (anchor, offset_from_anchor).
  647        /// The anchor is in multibuffer coordinates; after applying edits,
  648        /// resolve the anchor and add the offset to get the final cursor position.
  649        cursor_position: Option<(Anchor, usize)>,
  650        edit_preview: Option<EditPreview>,
  651        display_mode: EditDisplayMode,
  652        snapshot: BufferSnapshot,
  653    },
  654    /// Move to a specific location in the active editor
  655    MoveWithin {
  656        target: Anchor,
  657        snapshot: BufferSnapshot,
  658    },
  659    /// Move to a specific location in a different editor (not the active one)
  660    MoveOutside {
  661        target: language::Anchor,
  662        snapshot: BufferSnapshot,
  663    },
  664}
  665
  666struct EditPredictionState {
  667    inlay_ids: Vec<InlayId>,
  668    completion: EditPrediction,
  669    completion_id: Option<SharedString>,
  670    invalidation_range: Option<Range<Anchor>>,
  671}
  672
  673enum EditPredictionSettings {
  674    Disabled,
  675    Enabled {
  676        show_in_menu: bool,
  677        preview_requires_modifier: bool,
  678    },
  679}
  680
  681#[derive(Debug, Clone)]
  682struct InlineDiagnostic {
  683    message: SharedString,
  684    group_id: usize,
  685    is_primary: bool,
  686    start: Point,
  687    severity: lsp::DiagnosticSeverity,
  688}
  689
  690pub enum MenuEditPredictionsPolicy {
  691    Never,
  692    ByProvider,
  693}
  694
  695pub enum EditPredictionPreview {
  696    /// Modifier is not pressed
  697    Inactive { released_too_fast: bool },
  698    /// Modifier pressed
  699    Active {
  700        since: Instant,
  701        previous_scroll_position: Option<SharedScrollAnchor>,
  702    },
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq)]
  706enum EditPredictionKeybindSurface {
  707    Inline,
  708    CursorPopoverCompact,
  709    CursorPopoverExpanded,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, Debug)]
  713enum EditPredictionKeybindAction {
  714    Accept,
  715    Preview,
  716}
  717
  718struct EditPredictionKeybindDisplay {
  719    #[cfg(test)]
  720    accept_keystroke: Option<gpui::KeybindingKeystroke>,
  721    #[cfg(test)]
  722    preview_keystroke: Option<gpui::KeybindingKeystroke>,
  723    displayed_keystroke: Option<gpui::KeybindingKeystroke>,
  724    action: EditPredictionKeybindAction,
  725    missing_accept_keystroke: bool,
  726    show_hold_label: bool,
  727}
  728
  729impl EditPredictionPreview {
  730    pub fn released_too_fast(&self) -> bool {
  731        match self {
  732            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  733            EditPredictionPreview::Active { .. } => false,
  734        }
  735    }
  736
  737    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  738        if let EditPredictionPreview::Active {
  739            previous_scroll_position,
  740            ..
  741        } = self
  742        {
  743            *previous_scroll_position = scroll_position;
  744        }
  745    }
  746}
  747
  748pub struct ContextMenuOptions {
  749    pub min_entries_visible: usize,
  750    pub max_entries_visible: usize,
  751    pub placement: Option<ContextMenuPlacement>,
  752}
  753
  754#[derive(Debug, Clone, PartialEq, Eq)]
  755pub enum ContextMenuPlacement {
  756    Above,
  757    Below,
  758}
  759
  760#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  761struct EditorActionId(usize);
  762
  763impl EditorActionId {
  764    pub fn post_inc(&mut self) -> Self {
  765        let answer = self.0;
  766
  767        *self = Self(answer + 1);
  768
  769        Self(answer)
  770    }
  771}
  772
  773// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  774// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  775
  776type BackgroundHighlight = (
  777    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  778    Arc<[Range<Anchor>]>,
  779);
  780type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  781
  782#[derive(Default)]
  783struct ScrollbarMarkerState {
  784    scrollbar_size: Size<Pixels>,
  785    dirty: bool,
  786    markers: Arc<[PaintQuad]>,
  787    pending_refresh: Option<Task<Result<()>>>,
  788}
  789
  790impl ScrollbarMarkerState {
  791    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  792        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  793    }
  794}
  795
  796#[derive(Clone, Copy, PartialEq, Eq)]
  797pub enum MinimapVisibility {
  798    Disabled,
  799    Enabled {
  800        /// The configuration currently present in the users settings.
  801        setting_configuration: bool,
  802        /// Whether to override the currently set visibility from the users setting.
  803        toggle_override: bool,
  804    },
  805}
  806
  807impl MinimapVisibility {
  808    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  809        if mode.is_full() {
  810            Self::Enabled {
  811                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  812                toggle_override: false,
  813            }
  814        } else {
  815            Self::Disabled
  816        }
  817    }
  818
  819    fn hidden(&self) -> Self {
  820        match *self {
  821            Self::Enabled {
  822                setting_configuration,
  823                ..
  824            } => Self::Enabled {
  825                setting_configuration,
  826                toggle_override: setting_configuration,
  827            },
  828            Self::Disabled => Self::Disabled,
  829        }
  830    }
  831
  832    fn disabled(&self) -> bool {
  833        matches!(*self, Self::Disabled)
  834    }
  835
  836    fn settings_visibility(&self) -> bool {
  837        match *self {
  838            Self::Enabled {
  839                setting_configuration,
  840                ..
  841            } => setting_configuration,
  842            _ => false,
  843        }
  844    }
  845
  846    fn visible(&self) -> bool {
  847        match *self {
  848            Self::Enabled {
  849                setting_configuration,
  850                toggle_override,
  851            } => setting_configuration ^ toggle_override,
  852            _ => false,
  853        }
  854    }
  855
  856    fn toggle_visibility(&self) -> Self {
  857        match *self {
  858            Self::Enabled {
  859                toggle_override,
  860                setting_configuration,
  861            } => Self::Enabled {
  862                setting_configuration,
  863                toggle_override: !toggle_override,
  864            },
  865            Self::Disabled => Self::Disabled,
  866        }
  867    }
  868}
  869
  870#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  871pub enum BufferSerialization {
  872    All,
  873    NonDirtyBuffers,
  874}
  875
  876impl BufferSerialization {
  877    fn new(restore_unsaved_buffers: bool) -> Self {
  878        if restore_unsaved_buffers {
  879            Self::All
  880        } else {
  881            Self::NonDirtyBuffers
  882        }
  883    }
  884}
  885
  886/// Addons allow storing per-editor state in other crates (e.g. Vim)
  887pub trait Addon: 'static {
  888    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  889
  890    fn render_buffer_header_controls(
  891        &self,
  892        _: &ExcerptBoundaryInfo,
  893        _: &language::BufferSnapshot,
  894        _: &Window,
  895        _: &App,
  896    ) -> Option<AnyElement> {
  897        None
  898    }
  899
  900    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  901        None
  902    }
  903
  904    fn to_any(&self) -> &dyn std::any::Any;
  905
  906    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  907        None
  908    }
  909}
  910
  911struct ChangeLocation {
  912    current: Option<Vec<Anchor>>,
  913    original: Vec<Anchor>,
  914}
  915impl ChangeLocation {
  916    fn locations(&self) -> &[Anchor] {
  917        self.current.as_ref().unwrap_or(&self.original)
  918    }
  919}
  920
  921/// A set of caret positions, registered when the editor was edited.
  922pub struct ChangeList {
  923    changes: Vec<ChangeLocation>,
  924    /// Currently "selected" change.
  925    position: Option<usize>,
  926}
  927
  928impl ChangeList {
  929    pub fn new() -> Self {
  930        Self {
  931            changes: Vec::new(),
  932            position: None,
  933        }
  934    }
  935
  936    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  937    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  938    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  939        if self.changes.is_empty() {
  940            return None;
  941        }
  942
  943        let prev = self.position.unwrap_or(self.changes.len());
  944        let next = if direction == Direction::Prev {
  945            prev.saturating_sub(count)
  946        } else {
  947            (prev + count).min(self.changes.len() - 1)
  948        };
  949        self.position = Some(next);
  950        self.changes.get(next).map(|change| change.locations())
  951    }
  952
  953    /// Adds a new change to the list, resetting the change list position.
  954    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  955        self.position.take();
  956        if let Some(last) = self.changes.last_mut()
  957            && group
  958        {
  959            last.current = Some(new_positions)
  960        } else {
  961            self.changes.push(ChangeLocation {
  962                original: new_positions,
  963                current: None,
  964            });
  965        }
  966    }
  967
  968    pub fn last(&self) -> Option<&[Anchor]> {
  969        self.changes.last().map(|change| change.locations())
  970    }
  971
  972    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  973        self.changes.last().map(|change| change.original.as_slice())
  974    }
  975
  976    pub fn invert_last_group(&mut self) {
  977        if let Some(last) = self.changes.last_mut()
  978            && let Some(current) = last.current.as_mut()
  979        {
  980            mem::swap(&mut last.original, current);
  981        }
  982    }
  983}
  984
  985#[derive(Clone)]
  986struct InlineBlamePopoverState {
  987    scroll_handle: ScrollHandle,
  988    commit_message: Option<ParsedCommitMessage>,
  989    markdown: Entity<Markdown>,
  990}
  991
  992struct InlineBlamePopover {
  993    position: gpui::Point<Pixels>,
  994    hide_task: Option<Task<()>>,
  995    popover_bounds: Option<Bounds<Pixels>>,
  996    popover_state: InlineBlamePopoverState,
  997    keyboard_grace: bool,
  998}
  999
 1000enum SelectionDragState {
 1001    /// State when no drag related activity is detected.
 1002    None,
 1003    /// State when the mouse is down on a selection that is about to be dragged.
 1004    ReadyToDrag {
 1005        selection: Selection<Anchor>,
 1006        click_position: gpui::Point<Pixels>,
 1007        mouse_down_time: Instant,
 1008    },
 1009    /// State when the mouse is dragging the selection in the editor.
 1010    Dragging {
 1011        selection: Selection<Anchor>,
 1012        drop_cursor: Selection<Anchor>,
 1013        hide_drop_cursor: bool,
 1014    },
 1015}
 1016
 1017enum ColumnarSelectionState {
 1018    FromMouse {
 1019        selection_tail: Anchor,
 1020        display_point: Option<DisplayPoint>,
 1021    },
 1022    FromSelection {
 1023        selection_tail: Anchor,
 1024    },
 1025}
 1026
 1027/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1028/// a breakpoint on them.
 1029#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1030struct PhantomBreakpointIndicator {
 1031    display_row: DisplayRow,
 1032    /// There's a small debounce between hovering over the line and showing the indicator.
 1033    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1034    is_active: bool,
 1035    collides_with_existing_breakpoint: bool,
 1036}
 1037
 1038/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1039/// in diff view mode.
 1040#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1041pub(crate) struct PhantomDiffReviewIndicator {
 1042    /// The starting anchor of the selection (or the only row if not dragging).
 1043    pub start: Anchor,
 1044    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1045    pub end: Anchor,
 1046    /// There's a small debounce between hovering over the line and showing the indicator.
 1047    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1048    pub is_active: bool,
 1049}
 1050
 1051#[derive(Clone, Debug)]
 1052pub(crate) struct DiffReviewDragState {
 1053    pub start_anchor: Anchor,
 1054    pub current_anchor: Anchor,
 1055}
 1056
 1057impl DiffReviewDragState {
 1058    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1059        let start = self.start_anchor.to_display_point(snapshot).row();
 1060        let current = self.current_anchor.to_display_point(snapshot).row();
 1061
 1062        (start..=current).sorted()
 1063    }
 1064}
 1065
 1066/// Identifies a specific hunk in the diff buffer.
 1067/// Used as a key to group comments by their location.
 1068#[derive(Clone, Debug)]
 1069pub struct DiffHunkKey {
 1070    /// The file path (relative to worktree) this hunk belongs to.
 1071    pub file_path: Arc<util::rel_path::RelPath>,
 1072    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1073    pub hunk_start_anchor: Anchor,
 1074}
 1075
 1076/// A review comment stored locally before being sent to the Agent panel.
 1077#[derive(Clone)]
 1078pub struct StoredReviewComment {
 1079    /// Unique identifier for this comment (for edit/delete operations).
 1080    pub id: usize,
 1081    /// The comment text entered by the user.
 1082    pub comment: String,
 1083    /// Anchors for the code range being reviewed.
 1084    pub range: Range<Anchor>,
 1085    /// Timestamp when the comment was created (for chronological ordering).
 1086    pub created_at: Instant,
 1087    /// Whether this comment is currently being edited inline.
 1088    pub is_editing: bool,
 1089}
 1090
 1091impl StoredReviewComment {
 1092    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1093        Self {
 1094            id,
 1095            comment,
 1096            range: anchor_range,
 1097            created_at: Instant::now(),
 1098            is_editing: false,
 1099        }
 1100    }
 1101}
 1102
 1103/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1104pub(crate) struct DiffReviewOverlay {
 1105    pub anchor_range: Range<Anchor>,
 1106    /// The block ID for the overlay.
 1107    pub block_id: CustomBlockId,
 1108    /// The editor entity for the review input.
 1109    pub prompt_editor: Entity<Editor>,
 1110    /// The hunk key this overlay belongs to.
 1111    pub hunk_key: DiffHunkKey,
 1112    /// Whether the comments section is expanded.
 1113    pub comments_expanded: bool,
 1114    /// Editors for comments currently being edited inline.
 1115    /// Key: comment ID, Value: Editor entity for inline editing.
 1116    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1117    /// Subscriptions for inline edit editors' action handlers.
 1118    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1119    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1120    /// The current user's avatar URI for display in comment rows.
 1121    pub user_avatar_uri: Option<SharedUri>,
 1122    /// Subscription to keep the action handler alive.
 1123    _subscription: Subscription,
 1124}
 1125
 1126/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1127///
 1128/// See the [module level documentation](self) for more information.
 1129pub struct Editor {
 1130    focus_handle: FocusHandle,
 1131    last_focused_descendant: Option<WeakFocusHandle>,
 1132    /// The text buffer being edited
 1133    buffer: Entity<MultiBuffer>,
 1134    /// Map of how text in the buffer should be displayed.
 1135    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1136    pub display_map: Entity<DisplayMap>,
 1137    placeholder_display_map: Option<Entity<DisplayMap>>,
 1138    pub selections: SelectionsCollection,
 1139    pub scroll_manager: ScrollManager,
 1140    /// When inline assist editors are linked, they all render cursors because
 1141    /// typing enters text into each of them, even the ones that aren't focused.
 1142    pub(crate) show_cursor_when_unfocused: bool,
 1143    columnar_selection_state: Option<ColumnarSelectionState>,
 1144    add_selections_state: Option<AddSelectionsState>,
 1145    select_next_state: Option<SelectNextState>,
 1146    select_prev_state: Option<SelectNextState>,
 1147    selection_history: SelectionHistory,
 1148    defer_selection_effects: bool,
 1149    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1150    autoclose_regions: Vec<AutocloseRegion>,
 1151    snippet_stack: InvalidationStack<SnippetState>,
 1152    select_syntax_node_history: SelectSyntaxNodeHistory,
 1153    ime_transaction: Option<TransactionId>,
 1154    pub diagnostics_max_severity: DiagnosticSeverity,
 1155    active_diagnostics: ActiveDiagnostic,
 1156    show_inline_diagnostics: bool,
 1157    inline_diagnostics_update: Task<()>,
 1158    inline_diagnostics_enabled: bool,
 1159    diagnostics_enabled: bool,
 1160    word_completions_enabled: bool,
 1161    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1162    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1163    hard_wrap: Option<usize>,
 1164    project: Option<Entity<Project>>,
 1165    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1166    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1167    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1168    blink_manager: Entity<BlinkManager>,
 1169    show_cursor_names: bool,
 1170    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1171    pub show_local_selections: bool,
 1172    mode: EditorMode,
 1173    show_breadcrumbs: bool,
 1174    show_gutter: bool,
 1175    show_scrollbars: ScrollbarAxes,
 1176    minimap_visibility: MinimapVisibility,
 1177    offset_content: bool,
 1178    disable_expand_excerpt_buttons: bool,
 1179    delegate_expand_excerpts: bool,
 1180    delegate_stage_and_restore: bool,
 1181    delegate_open_excerpts: bool,
 1182    enable_lsp_data: bool,
 1183    enable_runnables: bool,
 1184    show_line_numbers: Option<bool>,
 1185    use_relative_line_numbers: Option<bool>,
 1186    show_git_diff_gutter: Option<bool>,
 1187    show_code_actions: Option<bool>,
 1188    show_runnables: Option<bool>,
 1189    show_breakpoints: Option<bool>,
 1190    show_diff_review_button: bool,
 1191    show_wrap_guides: Option<bool>,
 1192    show_indent_guides: Option<bool>,
 1193    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1194    highlight_order: usize,
 1195    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1196    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1197    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1198    scrollbar_marker_state: ScrollbarMarkerState,
 1199    active_indent_guides_state: ActiveIndentGuidesState,
 1200    nav_history: Option<ItemNavHistory>,
 1201    context_menu: RefCell<Option<CodeContextMenu>>,
 1202    context_menu_options: Option<ContextMenuOptions>,
 1203    mouse_context_menu: Option<MouseContextMenu>,
 1204    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1205    inline_blame_popover: Option<InlineBlamePopover>,
 1206    inline_blame_popover_show_task: Option<Task<()>>,
 1207    signature_help_state: SignatureHelpState,
 1208    auto_signature_help: Option<bool>,
 1209    find_all_references_task_sources: Vec<Anchor>,
 1210    next_completion_id: CompletionId,
 1211    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1212    code_actions_task: Option<Task<Result<()>>>,
 1213    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1214    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1215    debounced_selection_highlight_complete: bool,
 1216    document_highlights_task: Option<Task<()>>,
 1217    linked_editing_range_task: Option<Task<Option<()>>>,
 1218    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1219    pending_rename: Option<RenameState>,
 1220    searchable: bool,
 1221    cursor_shape: CursorShape,
 1222    /// Whether the cursor is offset one character to the left when something is
 1223    /// selected (needed for vim visual mode)
 1224    cursor_offset_on_selection: bool,
 1225    current_line_highlight: Option<CurrentLineHighlight>,
 1226    /// Whether to collapse search match ranges to just their start position.
 1227    /// When true, navigating to a match positions the cursor at the match
 1228    /// without selecting the matched text.
 1229    collapse_matches: bool,
 1230    autoindent_mode: Option<AutoindentMode>,
 1231    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1232    input_enabled: bool,
 1233    expects_character_input: bool,
 1234    use_modal_editing: bool,
 1235    read_only: bool,
 1236    leader_id: Option<CollaboratorId>,
 1237    remote_id: Option<ViewId>,
 1238    pub hover_state: HoverState,
 1239    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1240    prev_pressure_stage: Option<PressureStage>,
 1241    gutter_hovered: bool,
 1242    hovered_link_state: Option<HoveredLinkState>,
 1243    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1244    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1245    active_edit_prediction: Option<EditPredictionState>,
 1246    /// Used to prevent flickering as the user types while the menu is open
 1247    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1248    edit_prediction_settings: EditPredictionSettings,
 1249    edit_predictions_hidden_for_vim_mode: bool,
 1250    show_edit_predictions_override: Option<bool>,
 1251    show_completions_on_input_override: Option<bool>,
 1252    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1253    edit_prediction_preview: EditPredictionPreview,
 1254    in_leading_whitespace: bool,
 1255    next_inlay_id: usize,
 1256    next_color_inlay_id: usize,
 1257    _subscriptions: Vec<Subscription>,
 1258    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1259    gutter_dimensions: GutterDimensions,
 1260    style: Option<EditorStyle>,
 1261    text_style_refinement: Option<TextStyleRefinement>,
 1262    next_editor_action_id: EditorActionId,
 1263    editor_actions: Rc<
 1264        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1265    >,
 1266    use_autoclose: bool,
 1267    use_auto_surround: bool,
 1268    use_selection_highlight: bool,
 1269    auto_replace_emoji_shortcode: bool,
 1270    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1271    show_git_blame_gutter: bool,
 1272    show_git_blame_inline: bool,
 1273    show_git_blame_inline_delay_task: Option<Task<()>>,
 1274    git_blame_inline_enabled: bool,
 1275    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1276    buffer_serialization: Option<BufferSerialization>,
 1277    show_selection_menu: Option<bool>,
 1278    blame: Option<Entity<GitBlame>>,
 1279    blame_subscription: Option<Subscription>,
 1280    custom_context_menu: Option<
 1281        Box<
 1282            dyn 'static
 1283                + Fn(
 1284                    &mut Self,
 1285                    DisplayPoint,
 1286                    &mut Window,
 1287                    &mut Context<Self>,
 1288                ) -> Option<Entity<ui::ContextMenu>>,
 1289        >,
 1290    >,
 1291    last_bounds: Option<Bounds<Pixels>>,
 1292    last_position_map: Option<Rc<PositionMap>>,
 1293    expect_bounds_change: Option<Bounds<Pixels>>,
 1294    runnables: RunnableData,
 1295    breakpoint_store: Option<Entity<BreakpointStore>>,
 1296    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1297    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1298    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1299    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1300    /// when hunks have comments stored.
 1301    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1302    /// Stored review comments grouped by hunk.
 1303    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1304    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1305    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1306    /// Counter for generating unique comment IDs.
 1307    next_review_comment_id: usize,
 1308    hovered_diff_hunk_row: Option<DisplayRow>,
 1309    pull_diagnostics_task: Task<()>,
 1310    in_project_search: bool,
 1311    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1312    breadcrumb_header: Option<String>,
 1313    focused_block: Option<FocusedBlock>,
 1314    next_scroll_position: NextScrollCursorCenterTopBottom,
 1315    addons: HashMap<TypeId, Box<dyn Addon>>,
 1316    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1317    load_diff_task: Option<Shared<Task<()>>>,
 1318    /// Whether we are temporarily displaying a diff other than git's
 1319    temporary_diff_override: bool,
 1320    selection_mark_mode: bool,
 1321    toggle_fold_multiple_buffers: Task<()>,
 1322    _scroll_cursor_center_top_bottom_task: Task<()>,
 1323    serialize_selections: Task<()>,
 1324    serialize_folds: Task<()>,
 1325    mouse_cursor_hidden: bool,
 1326    minimap: Option<Entity<Self>>,
 1327    hide_mouse_mode: HideMouseMode,
 1328    pub change_list: ChangeList,
 1329    inline_value_cache: InlineValueCache,
 1330    number_deleted_lines: bool,
 1331
 1332    selection_drag_state: SelectionDragState,
 1333    colors: Option<LspColorData>,
 1334    post_scroll_update: Task<()>,
 1335    refresh_colors_task: Task<()>,
 1336    use_document_folding_ranges: bool,
 1337    refresh_folding_ranges_task: Task<()>,
 1338    inlay_hints: Option<LspInlayHintData>,
 1339    folding_newlines: Task<()>,
 1340    select_next_is_case_sensitive: Option<bool>,
 1341    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1342    on_local_selections_changed:
 1343        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1344    suppress_selection_callback: bool,
 1345    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1346    accent_data: Option<AccentData>,
 1347    bracket_fetched_tree_sitter_chunks: HashMap<Range<text::Anchor>, HashSet<Range<BufferRow>>>,
 1348    semantic_token_state: SemanticTokenState,
 1349    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1350    refresh_document_symbols_task: Shared<Task<()>>,
 1351    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1352    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1353    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1354    sticky_headers_task: Task<()>,
 1355    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1356    pub(crate) colorize_brackets_task: Task<()>,
 1357}
 1358
 1359#[derive(Debug, PartialEq)]
 1360struct AccentData {
 1361    colors: AccentColors,
 1362    overrides: Vec<SharedString>,
 1363}
 1364
 1365fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1366    if debounce_ms > 0 {
 1367        Some(Duration::from_millis(debounce_ms))
 1368    } else {
 1369        None
 1370    }
 1371}
 1372
 1373#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1374enum NextScrollCursorCenterTopBottom {
 1375    #[default]
 1376    Center,
 1377    Top,
 1378    Bottom,
 1379}
 1380
 1381impl NextScrollCursorCenterTopBottom {
 1382    fn next(&self) -> Self {
 1383        match self {
 1384            Self::Center => Self::Top,
 1385            Self::Top => Self::Bottom,
 1386            Self::Bottom => Self::Center,
 1387        }
 1388    }
 1389}
 1390
 1391#[derive(Clone)]
 1392pub struct EditorSnapshot {
 1393    pub mode: EditorMode,
 1394    show_gutter: bool,
 1395    offset_content: bool,
 1396    show_line_numbers: Option<bool>,
 1397    number_deleted_lines: bool,
 1398    show_git_diff_gutter: Option<bool>,
 1399    show_code_actions: Option<bool>,
 1400    show_runnables: Option<bool>,
 1401    show_breakpoints: Option<bool>,
 1402    git_blame_gutter_max_author_length: Option<usize>,
 1403    pub display_snapshot: DisplaySnapshot,
 1404    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1405    is_focused: bool,
 1406    scroll_anchor: SharedScrollAnchor,
 1407    ongoing_scroll: OngoingScroll,
 1408    current_line_highlight: CurrentLineHighlight,
 1409    gutter_hovered: bool,
 1410    semantic_tokens_enabled: bool,
 1411}
 1412
 1413#[derive(Default, Debug, Clone, Copy)]
 1414pub struct GutterDimensions {
 1415    pub left_padding: Pixels,
 1416    pub right_padding: Pixels,
 1417    pub width: Pixels,
 1418    pub margin: Pixels,
 1419    pub git_blame_entries_width: Option<Pixels>,
 1420}
 1421
 1422impl GutterDimensions {
 1423    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1424        Self {
 1425            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1426            ..Default::default()
 1427        }
 1428    }
 1429
 1430    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1431        -cx.text_system().descent(font_id, font_size)
 1432    }
 1433    /// The full width of the space taken up by the gutter.
 1434    pub fn full_width(&self) -> Pixels {
 1435        self.margin + self.width
 1436    }
 1437
 1438    /// The width of the space reserved for the fold indicators,
 1439    /// use alongside 'justify_end' and `gutter_width` to
 1440    /// right align content with the line numbers
 1441    pub fn fold_area_width(&self) -> Pixels {
 1442        self.margin + self.right_padding
 1443    }
 1444}
 1445
 1446struct CharacterDimensions {
 1447    em_width: Pixels,
 1448    em_advance: Pixels,
 1449    line_height: Pixels,
 1450}
 1451
 1452#[derive(Debug)]
 1453pub struct RemoteSelection {
 1454    pub replica_id: ReplicaId,
 1455    pub selection: Selection<Anchor>,
 1456    pub cursor_shape: CursorShape,
 1457    pub collaborator_id: CollaboratorId,
 1458    pub line_mode: bool,
 1459    pub user_name: Option<SharedString>,
 1460    pub color: PlayerColor,
 1461}
 1462
 1463#[derive(Clone, Debug)]
 1464struct SelectionHistoryEntry {
 1465    selections: Arc<[Selection<Anchor>]>,
 1466    select_next_state: Option<SelectNextState>,
 1467    select_prev_state: Option<SelectNextState>,
 1468    add_selections_state: Option<AddSelectionsState>,
 1469}
 1470
 1471#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1472enum SelectionHistoryMode {
 1473    #[default]
 1474    Normal,
 1475    Undoing,
 1476    Redoing,
 1477    Skipping,
 1478}
 1479
 1480#[derive(Clone, PartialEq, Eq, Hash)]
 1481struct HoveredCursor {
 1482    replica_id: ReplicaId,
 1483    selection_id: usize,
 1484}
 1485
 1486#[derive(Debug)]
 1487/// SelectionEffects controls the side-effects of updating the selection.
 1488///
 1489/// The default behaviour does "what you mostly want":
 1490/// - it pushes to the nav history if the cursor moved by >10 lines
 1491/// - it re-triggers completion requests
 1492/// - it scrolls to fit
 1493///
 1494/// You might want to modify these behaviours. For example when doing a "jump"
 1495/// like go to definition, we always want to add to nav history; but when scrolling
 1496/// in vim mode we never do.
 1497///
 1498/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1499/// move.
 1500#[derive(Clone)]
 1501pub struct SelectionEffects {
 1502    nav_history: Option<bool>,
 1503    completions: bool,
 1504    scroll: Option<Autoscroll>,
 1505}
 1506
 1507impl Default for SelectionEffects {
 1508    fn default() -> Self {
 1509        Self {
 1510            nav_history: None,
 1511            completions: true,
 1512            scroll: Some(Autoscroll::fit()),
 1513        }
 1514    }
 1515}
 1516impl SelectionEffects {
 1517    pub fn scroll(scroll: Autoscroll) -> Self {
 1518        Self {
 1519            scroll: Some(scroll),
 1520            ..Default::default()
 1521        }
 1522    }
 1523
 1524    pub fn no_scroll() -> Self {
 1525        Self {
 1526            scroll: None,
 1527            ..Default::default()
 1528        }
 1529    }
 1530
 1531    pub fn completions(self, completions: bool) -> Self {
 1532        Self {
 1533            completions,
 1534            ..self
 1535        }
 1536    }
 1537
 1538    pub fn nav_history(self, nav_history: bool) -> Self {
 1539        Self {
 1540            nav_history: Some(nav_history),
 1541            ..self
 1542        }
 1543    }
 1544}
 1545
 1546struct DeferredSelectionEffectsState {
 1547    changed: bool,
 1548    effects: SelectionEffects,
 1549    old_cursor_position: Anchor,
 1550    history_entry: SelectionHistoryEntry,
 1551}
 1552
 1553#[derive(Default)]
 1554struct SelectionHistory {
 1555    #[allow(clippy::type_complexity)]
 1556    selections_by_transaction:
 1557        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1558    mode: SelectionHistoryMode,
 1559    undo_stack: VecDeque<SelectionHistoryEntry>,
 1560    redo_stack: VecDeque<SelectionHistoryEntry>,
 1561}
 1562
 1563impl SelectionHistory {
 1564    #[track_caller]
 1565    fn insert_transaction(
 1566        &mut self,
 1567        transaction_id: TransactionId,
 1568        selections: Arc<[Selection<Anchor>]>,
 1569    ) {
 1570        if selections.is_empty() {
 1571            log::error!(
 1572                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1573                std::panic::Location::caller()
 1574            );
 1575            return;
 1576        }
 1577        self.selections_by_transaction
 1578            .insert(transaction_id, (selections, None));
 1579    }
 1580
 1581    #[allow(clippy::type_complexity)]
 1582    fn transaction(
 1583        &self,
 1584        transaction_id: TransactionId,
 1585    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1586        self.selections_by_transaction.get(&transaction_id)
 1587    }
 1588
 1589    #[allow(clippy::type_complexity)]
 1590    fn transaction_mut(
 1591        &mut self,
 1592        transaction_id: TransactionId,
 1593    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1594        self.selections_by_transaction.get_mut(&transaction_id)
 1595    }
 1596
 1597    fn push(&mut self, entry: SelectionHistoryEntry) {
 1598        if !entry.selections.is_empty() {
 1599            match self.mode {
 1600                SelectionHistoryMode::Normal => {
 1601                    self.push_undo(entry);
 1602                    self.redo_stack.clear();
 1603                }
 1604                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1605                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1606                SelectionHistoryMode::Skipping => {}
 1607            }
 1608        }
 1609    }
 1610
 1611    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1612        if self
 1613            .undo_stack
 1614            .back()
 1615            .is_none_or(|e| e.selections != entry.selections)
 1616        {
 1617            self.undo_stack.push_back(entry);
 1618            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1619                self.undo_stack.pop_front();
 1620            }
 1621        }
 1622    }
 1623
 1624    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1625        if self
 1626            .redo_stack
 1627            .back()
 1628            .is_none_or(|e| e.selections != entry.selections)
 1629        {
 1630            self.redo_stack.push_back(entry);
 1631            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1632                self.redo_stack.pop_front();
 1633            }
 1634        }
 1635    }
 1636}
 1637
 1638#[derive(Clone, Copy)]
 1639pub struct RowHighlightOptions {
 1640    pub autoscroll: bool,
 1641    pub include_gutter: bool,
 1642}
 1643
 1644impl Default for RowHighlightOptions {
 1645    fn default() -> Self {
 1646        Self {
 1647            autoscroll: Default::default(),
 1648            include_gutter: true,
 1649        }
 1650    }
 1651}
 1652
 1653struct RowHighlight {
 1654    index: usize,
 1655    range: Range<Anchor>,
 1656    color: Hsla,
 1657    options: RowHighlightOptions,
 1658    type_id: TypeId,
 1659}
 1660
 1661#[derive(Clone, Debug)]
 1662struct AddSelectionsState {
 1663    groups: Vec<AddSelectionsGroup>,
 1664}
 1665
 1666#[derive(Clone, Debug)]
 1667struct AddSelectionsGroup {
 1668    above: bool,
 1669    stack: Vec<usize>,
 1670}
 1671
 1672#[derive(Clone)]
 1673struct SelectNextState {
 1674    query: AhoCorasick,
 1675    wordwise: bool,
 1676    done: bool,
 1677}
 1678
 1679impl std::fmt::Debug for SelectNextState {
 1680    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1681        f.debug_struct(std::any::type_name::<Self>())
 1682            .field("wordwise", &self.wordwise)
 1683            .field("done", &self.done)
 1684            .finish()
 1685    }
 1686}
 1687
 1688#[derive(Debug)]
 1689struct AutocloseRegion {
 1690    selection_id: usize,
 1691    range: Range<Anchor>,
 1692    pair: BracketPair,
 1693}
 1694
 1695#[derive(Debug)]
 1696struct SnippetState {
 1697    ranges: Vec<Vec<Range<Anchor>>>,
 1698    active_index: usize,
 1699    choices: Vec<Option<Vec<String>>>,
 1700}
 1701
 1702#[doc(hidden)]
 1703pub struct RenameState {
 1704    pub range: Range<Anchor>,
 1705    pub old_name: Arc<str>,
 1706    pub editor: Entity<Editor>,
 1707    block_id: CustomBlockId,
 1708}
 1709
 1710struct InvalidationStack<T>(Vec<T>);
 1711
 1712struct RegisteredEditPredictionDelegate {
 1713    provider: Arc<dyn EditPredictionDelegateHandle>,
 1714    _subscription: Subscription,
 1715}
 1716
 1717#[derive(Debug, PartialEq, Eq)]
 1718pub struct ActiveDiagnosticGroup {
 1719    pub active_range: Range<Anchor>,
 1720    pub active_message: String,
 1721    pub group_id: usize,
 1722    pub blocks: HashSet<CustomBlockId>,
 1723}
 1724
 1725#[derive(Debug, PartialEq, Eq)]
 1726
 1727pub(crate) enum ActiveDiagnostic {
 1728    None,
 1729    All,
 1730    Group(ActiveDiagnosticGroup),
 1731}
 1732
 1733#[derive(Serialize, Deserialize, Clone, Debug)]
 1734pub struct ClipboardSelection {
 1735    /// The number of bytes in this selection.
 1736    pub len: usize,
 1737    /// Whether this was a full-line selection.
 1738    pub is_entire_line: bool,
 1739    /// The indentation of the first line when this content was originally copied.
 1740    pub first_line_indent: u32,
 1741    #[serde(default)]
 1742    pub file_path: Option<PathBuf>,
 1743    #[serde(default)]
 1744    pub line_range: Option<RangeInclusive<u32>>,
 1745}
 1746
 1747impl ClipboardSelection {
 1748    pub fn for_buffer(
 1749        len: usize,
 1750        is_entire_line: bool,
 1751        range: Range<Point>,
 1752        buffer: &MultiBufferSnapshot,
 1753        project: Option<&Entity<Project>>,
 1754        cx: &App,
 1755    ) -> Self {
 1756        let first_line_indent = buffer
 1757            .indent_size_for_line(MultiBufferRow(range.start.row))
 1758            .len;
 1759
 1760        let file_path = util::maybe!({
 1761            let project = project?.read(cx);
 1762            let file = buffer.file_at(range.start)?;
 1763            let project_path = ProjectPath {
 1764                worktree_id: file.worktree_id(cx),
 1765                path: file.path().clone(),
 1766            };
 1767            project.absolute_path(&project_path, cx)
 1768        });
 1769
 1770        let line_range = if file_path.is_some() {
 1771            buffer
 1772                .range_to_buffer_range(range)
 1773                .map(|(_, buffer_range)| buffer_range.start.row..=buffer_range.end.row)
 1774        } else {
 1775            None
 1776        };
 1777
 1778        Self {
 1779            len,
 1780            is_entire_line,
 1781            first_line_indent,
 1782            file_path,
 1783            line_range,
 1784        }
 1785    }
 1786}
 1787
 1788// selections, scroll behavior, was newest selection reversed
 1789type SelectSyntaxNodeHistoryState = (
 1790    Box<[Selection<Anchor>]>,
 1791    SelectSyntaxNodeScrollBehavior,
 1792    bool,
 1793);
 1794
 1795#[derive(Default)]
 1796struct SelectSyntaxNodeHistory {
 1797    stack: Vec<SelectSyntaxNodeHistoryState>,
 1798    // disable temporarily to allow changing selections without losing the stack
 1799    pub disable_clearing: bool,
 1800}
 1801
 1802impl SelectSyntaxNodeHistory {
 1803    pub fn try_clear(&mut self) {
 1804        if !self.disable_clearing {
 1805            self.stack.clear();
 1806        }
 1807    }
 1808
 1809    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1810        self.stack.push(selection);
 1811    }
 1812
 1813    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1814        self.stack.pop()
 1815    }
 1816}
 1817
 1818enum SelectSyntaxNodeScrollBehavior {
 1819    CursorTop,
 1820    FitSelection,
 1821    CursorBottom,
 1822}
 1823
 1824#[derive(Debug, Clone, Copy)]
 1825pub(crate) struct NavigationData {
 1826    cursor_anchor: Anchor,
 1827    cursor_position: Point,
 1828    scroll_anchor: ScrollAnchor,
 1829    scroll_top_row: u32,
 1830}
 1831
 1832#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1833pub enum GotoDefinitionKind {
 1834    Symbol,
 1835    Declaration,
 1836    Type,
 1837    Implementation,
 1838}
 1839
 1840pub enum FormatTarget {
 1841    Buffers(HashSet<Entity<Buffer>>),
 1842    Ranges(Vec<Range<MultiBufferPoint>>),
 1843}
 1844
 1845pub(crate) struct FocusedBlock {
 1846    id: BlockId,
 1847    focus_handle: WeakFocusHandle,
 1848}
 1849
 1850#[derive(Clone, Debug)]
 1851pub enum JumpData {
 1852    MultiBufferRow {
 1853        row: MultiBufferRow,
 1854        line_offset_from_top: u32,
 1855    },
 1856    MultiBufferPoint {
 1857        anchor: language::Anchor,
 1858        position: Point,
 1859        line_offset_from_top: u32,
 1860    },
 1861}
 1862
 1863pub enum MultibufferSelectionMode {
 1864    First,
 1865    All,
 1866}
 1867
 1868#[derive(Clone, Copy, Debug, Default)]
 1869pub struct RewrapOptions {
 1870    pub override_language_settings: bool,
 1871    pub preserve_existing_whitespace: bool,
 1872    pub line_length: Option<usize>,
 1873}
 1874
 1875impl Editor {
 1876    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1877        let buffer = cx.new(|cx| Buffer::local("", cx));
 1878        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1879        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1880    }
 1881
 1882    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1883        let buffer = cx.new(|cx| Buffer::local("", cx));
 1884        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1885        Self::new(EditorMode::full(), buffer, None, window, cx)
 1886    }
 1887
 1888    pub fn auto_height(
 1889        min_lines: usize,
 1890        max_lines: usize,
 1891        window: &mut Window,
 1892        cx: &mut Context<Self>,
 1893    ) -> Self {
 1894        let buffer = cx.new(|cx| Buffer::local("", cx));
 1895        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1896        Self::new(
 1897            EditorMode::AutoHeight {
 1898                min_lines,
 1899                max_lines: Some(max_lines),
 1900            },
 1901            buffer,
 1902            None,
 1903            window,
 1904            cx,
 1905        )
 1906    }
 1907
 1908    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1909    /// The editor grows as tall as needed to fit its content.
 1910    pub fn auto_height_unbounded(
 1911        min_lines: usize,
 1912        window: &mut Window,
 1913        cx: &mut Context<Self>,
 1914    ) -> Self {
 1915        let buffer = cx.new(|cx| Buffer::local("", cx));
 1916        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1917        Self::new(
 1918            EditorMode::AutoHeight {
 1919                min_lines,
 1920                max_lines: None,
 1921            },
 1922            buffer,
 1923            None,
 1924            window,
 1925            cx,
 1926        )
 1927    }
 1928
 1929    pub fn for_buffer(
 1930        buffer: Entity<Buffer>,
 1931        project: Option<Entity<Project>>,
 1932        window: &mut Window,
 1933        cx: &mut Context<Self>,
 1934    ) -> Self {
 1935        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1936        Self::new(EditorMode::full(), buffer, project, window, cx)
 1937    }
 1938
 1939    pub fn for_multibuffer(
 1940        buffer: Entity<MultiBuffer>,
 1941        project: Option<Entity<Project>>,
 1942        window: &mut Window,
 1943        cx: &mut Context<Self>,
 1944    ) -> Self {
 1945        Self::new(EditorMode::full(), buffer, project, window, cx)
 1946    }
 1947
 1948    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1949        let mut clone = Self::new(
 1950            self.mode.clone(),
 1951            self.buffer.clone(),
 1952            self.project.clone(),
 1953            window,
 1954            cx,
 1955        );
 1956        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1957            let snapshot = display_map.snapshot(cx);
 1958            clone.display_map.update(cx, |display_map, cx| {
 1959                display_map.set_state(&snapshot, cx);
 1960            });
 1961            snapshot
 1962        });
 1963        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1964        clone.folds_did_change(cx);
 1965        clone.selections.clone_state(&self.selections);
 1966        clone
 1967            .scroll_manager
 1968            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1969        clone.searchable = self.searchable;
 1970        clone.read_only = self.read_only;
 1971        clone.buffers_with_disabled_indent_guides =
 1972            self.buffers_with_disabled_indent_guides.clone();
 1973        clone
 1974    }
 1975
 1976    pub fn new(
 1977        mode: EditorMode,
 1978        buffer: Entity<MultiBuffer>,
 1979        project: Option<Entity<Project>>,
 1980        window: &mut Window,
 1981        cx: &mut Context<Self>,
 1982    ) -> Self {
 1983        Editor::new_internal(mode, buffer, project, None, window, cx)
 1984    }
 1985
 1986    pub fn refresh_sticky_headers(
 1987        &mut self,
 1988        display_snapshot: &DisplaySnapshot,
 1989        cx: &mut Context<Editor>,
 1990    ) {
 1991        if !self.mode.is_full() {
 1992            return;
 1993        }
 1994        let multi_buffer = display_snapshot.buffer_snapshot().clone();
 1995        let scroll_anchor = self
 1996            .scroll_manager
 1997            .native_anchor(display_snapshot, cx)
 1998            .anchor;
 1999        let Some(buffer_snapshot) = multi_buffer.as_singleton() else {
 2000            return;
 2001        };
 2002
 2003        let buffer = buffer_snapshot.clone();
 2004        let Some((buffer_visible_start, _)) = multi_buffer.anchor_to_buffer_anchor(scroll_anchor)
 2005        else {
 2006            return;
 2007        };
 2008        let buffer_visible_start = buffer_visible_start.to_point(&buffer);
 2009        let max_row = buffer.max_point().row;
 2010        let start_row = buffer_visible_start.row.min(max_row);
 2011        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2012
 2013        let syntax = self.style(cx).syntax.clone();
 2014        let background_task = cx.background_spawn(async move {
 2015            buffer
 2016                .outline_items_containing(
 2017                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2018                    true,
 2019                    Some(syntax.as_ref()),
 2020                )
 2021                .into_iter()
 2022                .filter_map(|outline_item| {
 2023                    Some(OutlineItem {
 2024                        depth: outline_item.depth,
 2025                        range: multi_buffer
 2026                            .buffer_anchor_range_to_anchor_range(outline_item.range)?,
 2027                        source_range_for_text: multi_buffer.buffer_anchor_range_to_anchor_range(
 2028                            outline_item.source_range_for_text,
 2029                        )?,
 2030                        text: outline_item.text,
 2031                        highlight_ranges: outline_item.highlight_ranges,
 2032                        name_ranges: outline_item.name_ranges,
 2033                        body_range: outline_item.body_range.and_then(|range| {
 2034                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2035                        }),
 2036                        annotation_range: outline_item.annotation_range.and_then(|range| {
 2037                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2038                        }),
 2039                    })
 2040                })
 2041                .collect()
 2042        });
 2043        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2044            let sticky_headers = background_task.await;
 2045            this.update(cx, |this, cx| {
 2046                this.sticky_headers = Some(sticky_headers);
 2047                cx.notify();
 2048            })
 2049            .ok();
 2050        });
 2051    }
 2052
 2053    fn new_internal(
 2054        mode: EditorMode,
 2055        multi_buffer: Entity<MultiBuffer>,
 2056        project: Option<Entity<Project>>,
 2057        display_map: Option<Entity<DisplayMap>>,
 2058        window: &mut Window,
 2059        cx: &mut Context<Self>,
 2060    ) -> Self {
 2061        debug_assert!(
 2062            display_map.is_none() || mode.is_minimap(),
 2063            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2064        );
 2065
 2066        let full_mode = mode.is_full();
 2067        let is_minimap = mode.is_minimap();
 2068        let diagnostics_max_severity = if full_mode {
 2069            EditorSettings::get_global(cx)
 2070                .diagnostics_max_severity
 2071                .unwrap_or(DiagnosticSeverity::Hint)
 2072        } else {
 2073            DiagnosticSeverity::Off
 2074        };
 2075        let style = window.text_style();
 2076        let font_size = style.font_size.to_pixels(window.rem_size());
 2077        let editor = cx.entity().downgrade();
 2078        let fold_placeholder = FoldPlaceholder {
 2079            constrain_width: false,
 2080            render: Arc::new(move |fold_id, fold_range, cx| {
 2081                let editor = editor.clone();
 2082                FoldPlaceholder::fold_element(fold_id, cx)
 2083                    .cursor_pointer()
 2084                    .child("")
 2085                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2086                    .on_click(move |_, _window, cx| {
 2087                        editor
 2088                            .update(cx, |editor, cx| {
 2089                                editor.unfold_ranges(
 2090                                    &[fold_range.start..fold_range.end],
 2091                                    true,
 2092                                    false,
 2093                                    cx,
 2094                                );
 2095                                cx.stop_propagation();
 2096                            })
 2097                            .ok();
 2098                    })
 2099                    .into_any()
 2100            }),
 2101            merge_adjacent: true,
 2102            ..FoldPlaceholder::default()
 2103        };
 2104        let display_map = display_map.unwrap_or_else(|| {
 2105            cx.new(|cx| {
 2106                DisplayMap::new(
 2107                    multi_buffer.clone(),
 2108                    style.font(),
 2109                    font_size,
 2110                    None,
 2111                    FILE_HEADER_HEIGHT,
 2112                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2113                    fold_placeholder,
 2114                    diagnostics_max_severity,
 2115                    cx,
 2116                )
 2117            })
 2118        });
 2119
 2120        let selections = SelectionsCollection::new();
 2121
 2122        let blink_manager = cx.new(|cx| {
 2123            let mut blink_manager = BlinkManager::new(
 2124                CURSOR_BLINK_INTERVAL,
 2125                |cx| EditorSettings::get_global(cx).cursor_blink,
 2126                cx,
 2127            );
 2128            if is_minimap {
 2129                blink_manager.disable(cx);
 2130            }
 2131            blink_manager
 2132        });
 2133
 2134        let soft_wrap_mode_override =
 2135            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2136
 2137        let mut project_subscriptions = Vec::new();
 2138        if full_mode && let Some(project) = project.as_ref() {
 2139            project_subscriptions.push(cx.subscribe_in(
 2140                project,
 2141                window,
 2142                |editor, _, event, window, cx| match event {
 2143                    project::Event::RefreshCodeLens => {
 2144                        // we always query lens with actions, without storing them, always refreshing them
 2145                    }
 2146                    project::Event::RefreshInlayHints {
 2147                        server_id,
 2148                        request_id,
 2149                    } => {
 2150                        editor.refresh_inlay_hints(
 2151                            InlayHintRefreshReason::RefreshRequested {
 2152                                server_id: *server_id,
 2153                                request_id: *request_id,
 2154                            },
 2155                            cx,
 2156                        );
 2157                    }
 2158                    project::Event::RefreshSemanticTokens {
 2159                        server_id,
 2160                        request_id,
 2161                    } => {
 2162                        editor.refresh_semantic_tokens(
 2163                            None,
 2164                            Some(RefreshForServer {
 2165                                server_id: *server_id,
 2166                                request_id: *request_id,
 2167                            }),
 2168                            cx,
 2169                        );
 2170                    }
 2171                    project::Event::LanguageServerRemoved(_) => {
 2172                        editor.registered_buffers.clear();
 2173                        editor.register_visible_buffers(cx);
 2174                        editor.invalidate_semantic_tokens(None);
 2175                        editor.refresh_runnables(None, window, cx);
 2176                        editor.update_lsp_data(None, window, cx);
 2177                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2178                    }
 2179                    project::Event::SnippetEdit(id, snippet_edits) => {
 2180                        // todo(lw): Non singletons
 2181                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2182                            let snapshot = buffer.read(cx).snapshot();
 2183                            let focus_handle = editor.focus_handle(cx);
 2184                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2185                                for (range, snippet) in snippet_edits {
 2186                                    let buffer_range =
 2187                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2188                                    editor
 2189                                        .insert_snippet(
 2190                                            &[MultiBufferOffset(buffer_range.start)
 2191                                                ..MultiBufferOffset(buffer_range.end)],
 2192                                            snippet.clone(),
 2193                                            window,
 2194                                            cx,
 2195                                        )
 2196                                        .ok();
 2197                                }
 2198                            }
 2199                        }
 2200                    }
 2201                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2202                        let buffer_id = *buffer_id;
 2203                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2204                            editor.register_buffer(buffer_id, cx);
 2205                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2206                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2207                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2208                            refresh_linked_ranges(editor, window, cx);
 2209                            editor.refresh_code_actions(window, cx);
 2210                            editor.refresh_document_highlights(cx);
 2211                        }
 2212                    }
 2213
 2214                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2215                        let Some(workspace) = editor.workspace() else {
 2216                            return;
 2217                        };
 2218                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2219                        else {
 2220                            return;
 2221                        };
 2222
 2223                        if active_editor.entity_id() == cx.entity_id() {
 2224                            let entity_id = cx.entity_id();
 2225                            workspace.update(cx, |this, cx| {
 2226                                this.panes_mut()
 2227                                    .iter_mut()
 2228                                    .filter(|pane| pane.entity_id() != entity_id)
 2229                                    .for_each(|p| {
 2230                                        p.update(cx, |pane, _| {
 2231                                            pane.nav_history_mut().rename_item(
 2232                                                entity_id,
 2233                                                project_path.clone(),
 2234                                                abs_path.clone().into(),
 2235                                            );
 2236                                        })
 2237                                    });
 2238                            });
 2239
 2240                            Self::open_transaction_for_hidden_buffers(
 2241                                workspace,
 2242                                transaction.clone(),
 2243                                "Rename".to_string(),
 2244                                window,
 2245                                cx,
 2246                            );
 2247                        }
 2248                    }
 2249
 2250                    project::Event::WorkspaceEditApplied(transaction) => {
 2251                        let Some(workspace) = editor.workspace() else {
 2252                            return;
 2253                        };
 2254                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2255                        else {
 2256                            return;
 2257                        };
 2258
 2259                        if active_editor.entity_id() == cx.entity_id() {
 2260                            Self::open_transaction_for_hidden_buffers(
 2261                                workspace,
 2262                                transaction.clone(),
 2263                                "LSP Edit".to_string(),
 2264                                window,
 2265                                cx,
 2266                            );
 2267                        }
 2268                    }
 2269
 2270                    _ => {}
 2271                },
 2272            ));
 2273            if let Some(task_inventory) = project
 2274                .read(cx)
 2275                .task_store()
 2276                .read(cx)
 2277                .task_inventory()
 2278                .cloned()
 2279            {
 2280                project_subscriptions.push(cx.observe_in(
 2281                    &task_inventory,
 2282                    window,
 2283                    |editor, _, window, cx| {
 2284                        editor.refresh_runnables(None, window, cx);
 2285                    },
 2286                ));
 2287            };
 2288
 2289            project_subscriptions.push(cx.subscribe_in(
 2290                &project.read(cx).breakpoint_store(),
 2291                window,
 2292                |editor, _, event, window, cx| match event {
 2293                    BreakpointStoreEvent::ClearDebugLines => {
 2294                        editor.clear_row_highlights::<ActiveDebugLine>();
 2295                        editor.refresh_inline_values(cx);
 2296                    }
 2297                    BreakpointStoreEvent::SetDebugLine => {
 2298                        if editor.go_to_active_debug_line(window, cx) {
 2299                            cx.stop_propagation();
 2300                        }
 2301
 2302                        editor.refresh_inline_values(cx);
 2303                    }
 2304                    _ => {}
 2305                },
 2306            ));
 2307            let git_store = project.read(cx).git_store().clone();
 2308            let project = project.clone();
 2309            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2310                if let GitStoreEvent::RepositoryAdded = event {
 2311                    this.load_diff_task = Some(
 2312                        update_uncommitted_diff_for_buffer(
 2313                            cx.entity(),
 2314                            &project,
 2315                            this.buffer.read(cx).all_buffers(),
 2316                            this.buffer.clone(),
 2317                            cx,
 2318                        )
 2319                        .shared(),
 2320                    );
 2321                }
 2322            }));
 2323        }
 2324
 2325        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2326
 2327        let inlay_hint_settings =
 2328            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2329        let focus_handle = cx.focus_handle();
 2330        if !is_minimap {
 2331            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2332                .detach();
 2333            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2334                .detach();
 2335            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2336                .detach();
 2337            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2338                .detach();
 2339            cx.observe_pending_input(window, Self::observe_pending_input)
 2340                .detach();
 2341        }
 2342
 2343        let show_indent_guides =
 2344            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2345                Some(false)
 2346            } else {
 2347                None
 2348            };
 2349
 2350        let breakpoint_store = match (&mode, project.as_ref()) {
 2351            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2352            _ => None,
 2353        };
 2354
 2355        let mut code_action_providers = Vec::new();
 2356        let mut load_uncommitted_diff = None;
 2357        if let Some(project) = project.clone() {
 2358            load_uncommitted_diff = Some(
 2359                update_uncommitted_diff_for_buffer(
 2360                    cx.entity(),
 2361                    &project,
 2362                    multi_buffer.read(cx).all_buffers(),
 2363                    multi_buffer.clone(),
 2364                    cx,
 2365                )
 2366                .shared(),
 2367            );
 2368            code_action_providers.push(Rc::new(project) as Rc<_>);
 2369        }
 2370
 2371        let mut editor = Self {
 2372            focus_handle,
 2373            show_cursor_when_unfocused: false,
 2374            last_focused_descendant: None,
 2375            buffer: multi_buffer.clone(),
 2376            display_map: display_map.clone(),
 2377            placeholder_display_map: None,
 2378            selections,
 2379            scroll_manager: ScrollManager::new(cx),
 2380            columnar_selection_state: None,
 2381            add_selections_state: None,
 2382            select_next_state: None,
 2383            select_prev_state: None,
 2384            selection_history: SelectionHistory::default(),
 2385            defer_selection_effects: false,
 2386            deferred_selection_effects_state: None,
 2387            autoclose_regions: Vec::new(),
 2388            snippet_stack: InvalidationStack::default(),
 2389            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2390            ime_transaction: None,
 2391            active_diagnostics: ActiveDiagnostic::None,
 2392            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2393            inline_diagnostics_update: Task::ready(()),
 2394            inline_diagnostics: Vec::new(),
 2395            soft_wrap_mode_override,
 2396            diagnostics_max_severity,
 2397            hard_wrap: None,
 2398            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2399            semantics_provider: project
 2400                .as_ref()
 2401                .map(|project| Rc::new(project.downgrade()) as _),
 2402            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2403            project,
 2404            blink_manager: blink_manager.clone(),
 2405            show_local_selections: true,
 2406            show_scrollbars: ScrollbarAxes {
 2407                horizontal: full_mode,
 2408                vertical: full_mode,
 2409            },
 2410            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2411            offset_content: !matches!(mode, EditorMode::SingleLine),
 2412            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2413            show_gutter: full_mode,
 2414            show_line_numbers: (!full_mode).then_some(false),
 2415            use_relative_line_numbers: None,
 2416            disable_expand_excerpt_buttons: !full_mode,
 2417            delegate_expand_excerpts: false,
 2418            delegate_stage_and_restore: false,
 2419            delegate_open_excerpts: false,
 2420            enable_lsp_data: true,
 2421            enable_runnables: true,
 2422            show_git_diff_gutter: None,
 2423            show_code_actions: None,
 2424            show_runnables: None,
 2425            show_breakpoints: None,
 2426            show_diff_review_button: false,
 2427            show_wrap_guides: None,
 2428            show_indent_guides,
 2429            buffers_with_disabled_indent_guides: HashSet::default(),
 2430            highlight_order: 0,
 2431            highlighted_rows: HashMap::default(),
 2432            background_highlights: HashMap::default(),
 2433            gutter_highlights: HashMap::default(),
 2434            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2435            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2436            nav_history: None,
 2437            context_menu: RefCell::new(None),
 2438            context_menu_options: None,
 2439            mouse_context_menu: None,
 2440            completion_tasks: Vec::new(),
 2441            inline_blame_popover: None,
 2442            inline_blame_popover_show_task: None,
 2443            signature_help_state: SignatureHelpState::default(),
 2444            auto_signature_help: None,
 2445            find_all_references_task_sources: Vec::new(),
 2446            next_completion_id: 0,
 2447            next_inlay_id: 0,
 2448            code_action_providers,
 2449            available_code_actions: None,
 2450            code_actions_task: None,
 2451            quick_selection_highlight_task: None,
 2452            debounced_selection_highlight_task: None,
 2453            debounced_selection_highlight_complete: false,
 2454            document_highlights_task: None,
 2455            linked_editing_range_task: None,
 2456            pending_rename: None,
 2457            searchable: !is_minimap,
 2458            cursor_shape: EditorSettings::get_global(cx)
 2459                .cursor_shape
 2460                .unwrap_or_default(),
 2461            cursor_offset_on_selection: false,
 2462            current_line_highlight: None,
 2463            autoindent_mode: Some(AutoindentMode::EachLine),
 2464            collapse_matches: false,
 2465            workspace: None,
 2466            input_enabled: !is_minimap,
 2467            expects_character_input: !is_minimap,
 2468            use_modal_editing: full_mode,
 2469            read_only: is_minimap,
 2470            use_autoclose: true,
 2471            use_auto_surround: true,
 2472            use_selection_highlight: true,
 2473            auto_replace_emoji_shortcode: false,
 2474            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2475            leader_id: None,
 2476            remote_id: None,
 2477            hover_state: HoverState::default(),
 2478            pending_mouse_down: None,
 2479            prev_pressure_stage: None,
 2480            hovered_link_state: None,
 2481            edit_prediction_provider: None,
 2482            active_edit_prediction: None,
 2483            stale_edit_prediction_in_menu: None,
 2484            edit_prediction_preview: EditPredictionPreview::Inactive {
 2485                released_too_fast: false,
 2486            },
 2487            inline_diagnostics_enabled: full_mode,
 2488            diagnostics_enabled: full_mode,
 2489            word_completions_enabled: full_mode,
 2490            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2491            gutter_hovered: false,
 2492            pixel_position_of_newest_cursor: None,
 2493            last_bounds: None,
 2494            last_position_map: None,
 2495            expect_bounds_change: None,
 2496            gutter_dimensions: GutterDimensions::default(),
 2497            style: None,
 2498            show_cursor_names: false,
 2499            hovered_cursors: HashMap::default(),
 2500            next_editor_action_id: EditorActionId::default(),
 2501            editor_actions: Rc::default(),
 2502            edit_predictions_hidden_for_vim_mode: false,
 2503            show_edit_predictions_override: None,
 2504            show_completions_on_input_override: None,
 2505            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2506            edit_prediction_settings: EditPredictionSettings::Disabled,
 2507            in_leading_whitespace: false,
 2508            custom_context_menu: None,
 2509            show_git_blame_gutter: false,
 2510            show_git_blame_inline: false,
 2511            show_selection_menu: None,
 2512            show_git_blame_inline_delay_task: None,
 2513            git_blame_inline_enabled: full_mode
 2514                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2515            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2516            buffer_serialization: is_minimap.not().then(|| {
 2517                BufferSerialization::new(
 2518                    ProjectSettings::get_global(cx)
 2519                        .session
 2520                        .restore_unsaved_buffers,
 2521                )
 2522            }),
 2523            blame: None,
 2524            blame_subscription: None,
 2525
 2526            breakpoint_store,
 2527            gutter_breakpoint_indicator: (None, None),
 2528            gutter_diff_review_indicator: (None, None),
 2529            diff_review_drag_state: None,
 2530            diff_review_overlays: Vec::new(),
 2531            stored_review_comments: Vec::new(),
 2532            next_review_comment_id: 0,
 2533            hovered_diff_hunk_row: None,
 2534            _subscriptions: (!is_minimap)
 2535                .then(|| {
 2536                    vec![
 2537                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2538                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2539                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2540                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2541                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2542                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2543                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2544                        cx.observe_window_activation(window, |editor, window, cx| {
 2545                            let active = window.is_window_active();
 2546                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2547                                if active {
 2548                                    blink_manager.enable(cx);
 2549                                } else {
 2550                                    blink_manager.disable(cx);
 2551                                }
 2552                            });
 2553                            if active {
 2554                                editor.show_mouse_cursor(cx);
 2555                            }
 2556                        }),
 2557                    ]
 2558                })
 2559                .unwrap_or_default(),
 2560            runnables: RunnableData::new(),
 2561            pull_diagnostics_task: Task::ready(()),
 2562            colors: None,
 2563            refresh_colors_task: Task::ready(()),
 2564            use_document_folding_ranges: false,
 2565            refresh_folding_ranges_task: Task::ready(()),
 2566            inlay_hints: None,
 2567            next_color_inlay_id: 0,
 2568            post_scroll_update: Task::ready(()),
 2569            linked_edit_ranges: Default::default(),
 2570            in_project_search: false,
 2571            previous_search_ranges: None,
 2572            breadcrumb_header: None,
 2573            focused_block: None,
 2574            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2575            addons: HashMap::default(),
 2576            registered_buffers: HashMap::default(),
 2577            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2578            selection_mark_mode: false,
 2579            toggle_fold_multiple_buffers: Task::ready(()),
 2580            serialize_selections: Task::ready(()),
 2581            serialize_folds: Task::ready(()),
 2582            text_style_refinement: None,
 2583            load_diff_task: load_uncommitted_diff,
 2584            temporary_diff_override: false,
 2585            mouse_cursor_hidden: false,
 2586            minimap: None,
 2587            hide_mouse_mode: EditorSettings::get_global(cx)
 2588                .hide_mouse
 2589                .unwrap_or_default(),
 2590            change_list: ChangeList::new(),
 2591            mode,
 2592            selection_drag_state: SelectionDragState::None,
 2593            folding_newlines: Task::ready(()),
 2594            lookup_key: None,
 2595            select_next_is_case_sensitive: None,
 2596            on_local_selections_changed: None,
 2597            suppress_selection_callback: false,
 2598            applicable_language_settings: HashMap::default(),
 2599            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2600            accent_data: None,
 2601            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2602            number_deleted_lines: false,
 2603            refresh_matching_bracket_highlights_task: Task::ready(()),
 2604            refresh_document_symbols_task: Task::ready(()).shared(),
 2605            lsp_document_symbols: HashMap::default(),
 2606            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2607            outline_symbols_at_cursor: None,
 2608            sticky_headers_task: Task::ready(()),
 2609            sticky_headers: None,
 2610            colorize_brackets_task: Task::ready(()),
 2611        };
 2612
 2613        if is_minimap {
 2614            return editor;
 2615        }
 2616
 2617        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2618        editor.accent_data = editor.fetch_accent_data(cx);
 2619
 2620        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2621            editor
 2622                ._subscriptions
 2623                .push(cx.observe(breakpoints, |_, _, cx| {
 2624                    cx.notify();
 2625                }));
 2626        }
 2627        editor._subscriptions.extend(project_subscriptions);
 2628
 2629        editor._subscriptions.push(cx.subscribe_in(
 2630            &cx.entity(),
 2631            window,
 2632            |editor, _, e: &EditorEvent, window, cx| match e {
 2633                EditorEvent::ScrollPositionChanged { local, .. } => {
 2634                    if *local {
 2635                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2636                        editor.inline_blame_popover.take();
 2637                        let snapshot = editor.snapshot(window, cx);
 2638                        let new_anchor = editor
 2639                            .scroll_manager
 2640                            .native_anchor(&snapshot.display_snapshot, cx);
 2641                        editor.update_restoration_data(cx, move |data| {
 2642                            data.scroll_position = (
 2643                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2644                                new_anchor.offset,
 2645                            );
 2646                        });
 2647
 2648                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2649                            cx.background_executor()
 2650                                .timer(Duration::from_millis(50))
 2651                                .await;
 2652                            editor
 2653                                .update_in(cx, |editor, window, cx| {
 2654                                    editor.update_data_on_scroll(window, cx)
 2655                                })
 2656                                .ok();
 2657                        });
 2658                    }
 2659                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2660                }
 2661                EditorEvent::Edited { .. } => {
 2662                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2663                        .map(|vim_mode| vim_mode.0)
 2664                        .unwrap_or(false);
 2665                    if !vim_mode {
 2666                        let display_map = editor.display_snapshot(cx);
 2667                        let selections = editor.selections.all_adjusted_display(&display_map);
 2668                        let pop_state = editor
 2669                            .change_list
 2670                            .last()
 2671                            .map(|previous| {
 2672                                previous.len() == selections.len()
 2673                                    && previous.iter().enumerate().all(|(ix, p)| {
 2674                                        p.to_display_point(&display_map).row()
 2675                                            == selections[ix].head().row()
 2676                                    })
 2677                            })
 2678                            .unwrap_or(false);
 2679                        let new_positions = selections
 2680                            .into_iter()
 2681                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2682                            .collect();
 2683                        editor
 2684                            .change_list
 2685                            .push_to_change_list(pop_state, new_positions);
 2686                    }
 2687                }
 2688                _ => (),
 2689            },
 2690        ));
 2691
 2692        if let Some(dap_store) = editor
 2693            .project
 2694            .as_ref()
 2695            .map(|project| project.read(cx).dap_store())
 2696        {
 2697            let weak_editor = cx.weak_entity();
 2698
 2699            editor
 2700                ._subscriptions
 2701                .push(
 2702                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2703                        let session_entity = cx.entity();
 2704                        weak_editor
 2705                            .update(cx, |editor, cx| {
 2706                                editor._subscriptions.push(
 2707                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2708                                );
 2709                            })
 2710                            .ok();
 2711                    }),
 2712                );
 2713
 2714            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2715                editor
 2716                    ._subscriptions
 2717                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2718            }
 2719        }
 2720
 2721        // skip adding the initial selection to selection history
 2722        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2723        editor.end_selection(window, cx);
 2724        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2725
 2726        editor.scroll_manager.show_scrollbars(window, cx);
 2727        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2728
 2729        if full_mode {
 2730            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2731            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2732
 2733            if editor.git_blame_inline_enabled {
 2734                editor.start_git_blame_inline(false, window, cx);
 2735            }
 2736
 2737            editor.go_to_active_debug_line(window, cx);
 2738
 2739            editor.minimap =
 2740                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2741            editor.colors = Some(LspColorData::new(cx));
 2742            editor.use_document_folding_ranges = true;
 2743            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2744
 2745            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2746                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2747            }
 2748            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2749        }
 2750
 2751        editor
 2752    }
 2753
 2754    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2755        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2756    }
 2757
 2758    pub fn deploy_mouse_context_menu(
 2759        &mut self,
 2760        position: gpui::Point<Pixels>,
 2761        context_menu: Entity<ContextMenu>,
 2762        window: &mut Window,
 2763        cx: &mut Context<Self>,
 2764    ) {
 2765        self.mouse_context_menu = Some(MouseContextMenu::new(
 2766            self,
 2767            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2768            context_menu,
 2769            window,
 2770            cx,
 2771        ));
 2772    }
 2773
 2774    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2775        self.mouse_context_menu
 2776            .as_ref()
 2777            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2778    }
 2779
 2780    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2781        if self
 2782            .selections
 2783            .pending_anchor()
 2784            .is_some_and(|pending_selection| {
 2785                let snapshot = self.buffer().read(cx).snapshot(cx);
 2786                pending_selection.range().includes(range, &snapshot)
 2787            })
 2788        {
 2789            return true;
 2790        }
 2791
 2792        self.selections
 2793            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2794            .into_iter()
 2795            .any(|selection| {
 2796                // This is needed to cover a corner case, if we just check for an existing
 2797                // selection in the fold range, having a cursor at the start of the fold
 2798                // marks it as selected. Non-empty selections don't cause this.
 2799                let length = selection.end - selection.start;
 2800                length > 0
 2801            })
 2802    }
 2803
 2804    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2805        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2806    }
 2807
 2808    fn key_context_internal(
 2809        &self,
 2810        has_active_edit_prediction: bool,
 2811        window: &mut Window,
 2812        cx: &mut App,
 2813    ) -> KeyContext {
 2814        let mut key_context = KeyContext::new_with_defaults();
 2815        key_context.add("Editor");
 2816        let mode = match self.mode {
 2817            EditorMode::SingleLine => "single_line",
 2818            EditorMode::AutoHeight { .. } => "auto_height",
 2819            EditorMode::Minimap { .. } => "minimap",
 2820            EditorMode::Full { .. } => "full",
 2821        };
 2822
 2823        if EditorSettings::jupyter_enabled(cx) {
 2824            key_context.add("jupyter");
 2825        }
 2826
 2827        key_context.set("mode", mode);
 2828        if self.pending_rename.is_some() {
 2829            key_context.add("renaming");
 2830        }
 2831
 2832        if let Some(snippet_stack) = self.snippet_stack.last() {
 2833            key_context.add("in_snippet");
 2834
 2835            if snippet_stack.active_index > 0 {
 2836                key_context.add("has_previous_tabstop");
 2837            }
 2838
 2839            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2840                key_context.add("has_next_tabstop");
 2841            }
 2842        }
 2843
 2844        match self.context_menu.borrow().as_ref() {
 2845            Some(CodeContextMenu::Completions(menu)) => {
 2846                if menu.visible() {
 2847                    key_context.add("menu");
 2848                    key_context.add("showing_completions");
 2849                }
 2850            }
 2851            Some(CodeContextMenu::CodeActions(menu)) => {
 2852                if menu.visible() {
 2853                    key_context.add("menu");
 2854                    key_context.add("showing_code_actions")
 2855                }
 2856            }
 2857            None => {}
 2858        }
 2859
 2860        if self.signature_help_state.has_multiple_signatures() {
 2861            key_context.add("showing_signature_help");
 2862        }
 2863
 2864        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2865        if !self.focus_handle(cx).contains_focused(window, cx)
 2866            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2867        {
 2868            for addon in self.addons.values() {
 2869                addon.extend_key_context(&mut key_context, cx)
 2870            }
 2871        }
 2872
 2873        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2874            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2875                Some(
 2876                    file.full_path(cx)
 2877                        .extension()?
 2878                        .to_string_lossy()
 2879                        .to_lowercase(),
 2880                )
 2881            }) {
 2882                key_context.set("extension", extension);
 2883            }
 2884        } else {
 2885            key_context.add("multibuffer");
 2886        }
 2887
 2888        if has_active_edit_prediction {
 2889            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2890            key_context.add("copilot_suggestion");
 2891        }
 2892
 2893        if self.in_leading_whitespace {
 2894            key_context.add("in_leading_whitespace");
 2895        }
 2896        if self.edit_prediction_requires_modifier() {
 2897            key_context.set("edit_prediction_mode", "subtle")
 2898        } else {
 2899            key_context.set("edit_prediction_mode", "eager");
 2900        }
 2901
 2902        if self.selection_mark_mode {
 2903            key_context.add("selection_mode");
 2904        }
 2905
 2906        let disjoint = self.selections.disjoint_anchors();
 2907        if matches!(
 2908            &self.mode,
 2909            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2910        ) && let [selection] = disjoint
 2911            && selection.start == selection.end
 2912        {
 2913            let snapshot = self.snapshot(window, cx);
 2914            let snapshot = snapshot.buffer_snapshot();
 2915            let caret_offset = selection.end.to_offset(snapshot);
 2916
 2917            if caret_offset == MultiBufferOffset(0) {
 2918                key_context.add("start_of_input");
 2919            }
 2920
 2921            if caret_offset == snapshot.len() {
 2922                key_context.add("end_of_input");
 2923            }
 2924        }
 2925
 2926        if self.has_any_expanded_diff_hunks(cx) {
 2927            key_context.add("diffs_expanded");
 2928        }
 2929
 2930        key_context
 2931    }
 2932
 2933    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2934        self.last_bounds.as_ref()
 2935    }
 2936
 2937    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2938        if self.mouse_cursor_hidden {
 2939            self.mouse_cursor_hidden = false;
 2940            cx.notify();
 2941        }
 2942    }
 2943
 2944    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2945        let hide_mouse_cursor = match origin {
 2946            HideMouseCursorOrigin::TypingAction => {
 2947                matches!(
 2948                    self.hide_mouse_mode,
 2949                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2950                )
 2951            }
 2952            HideMouseCursorOrigin::MovementAction => {
 2953                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2954            }
 2955        };
 2956        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2957            self.mouse_cursor_hidden = hide_mouse_cursor;
 2958            cx.notify();
 2959        }
 2960    }
 2961
 2962    fn accept_edit_prediction_keystroke(
 2963        &self,
 2964        granularity: EditPredictionGranularity,
 2965        window: &mut Window,
 2966        cx: &mut App,
 2967    ) -> Option<gpui::KeybindingKeystroke> {
 2968        let key_context = self.key_context_internal(true, window, cx);
 2969
 2970        let bindings =
 2971            match granularity {
 2972                EditPredictionGranularity::Word => window
 2973                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2974                EditPredictionGranularity::Line => window
 2975                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2976                EditPredictionGranularity::Full => {
 2977                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2978                }
 2979            };
 2980
 2981        bindings
 2982            .into_iter()
 2983            .rev()
 2984            .find_map(|binding| match binding.keystrokes() {
 2985                [keystroke, ..] => Some(keystroke.clone()),
 2986                _ => None,
 2987            })
 2988    }
 2989
 2990    fn preview_edit_prediction_keystroke(
 2991        &self,
 2992        window: &mut Window,
 2993        cx: &mut App,
 2994    ) -> Option<gpui::KeybindingKeystroke> {
 2995        let key_context = self.key_context_internal(true, window, cx);
 2996        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 2997        bindings
 2998            .into_iter()
 2999            .rev()
 3000            .find_map(|binding| match binding.keystrokes() {
 3001                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 3002                _ => None,
 3003            })
 3004    }
 3005
 3006    fn edit_prediction_preview_modifiers_held(
 3007        &self,
 3008        modifiers: &Modifiers,
 3009        window: &mut Window,
 3010        cx: &mut App,
 3011    ) -> bool {
 3012        let key_context = self.key_context_internal(true, window, cx);
 3013        let actions: [&dyn Action; 3] = [
 3014            &AcceptEditPrediction,
 3015            &AcceptNextWordEditPrediction,
 3016            &AcceptNextLineEditPrediction,
 3017        ];
 3018
 3019        actions.into_iter().any(|action| {
 3020            window
 3021                .bindings_for_action_in_context(action, key_context.clone())
 3022                .into_iter()
 3023                .rev()
 3024                .any(|binding| {
 3025                    binding.keystrokes().first().is_some_and(|keystroke| {
 3026                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3027                    })
 3028                })
 3029        })
 3030    }
 3031
 3032    fn edit_prediction_cursor_popover_prefers_preview(
 3033        &self,
 3034        completion: &EditPredictionState,
 3035        cx: &App,
 3036    ) -> bool {
 3037        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 3038
 3039        match &completion.completion {
 3040            EditPrediction::Edit {
 3041                edits, snapshot, ..
 3042            } => {
 3043                let mut start_row: Option<u32> = None;
 3044                let mut end_row: Option<u32> = None;
 3045
 3046                for (range, text) in edits {
 3047                    let Some((_, range)) =
 3048                        multibuffer_snapshot.anchor_range_to_buffer_anchor_range(range.clone())
 3049                    else {
 3050                        continue;
 3051                    };
 3052                    let edit_start_row = range.start.to_point(snapshot).row;
 3053                    let old_end_row = range.end.to_point(snapshot).row;
 3054                    let inserted_newline_count = text
 3055                        .as_ref()
 3056                        .chars()
 3057                        .filter(|character| *character == '\n')
 3058                        .count() as u32;
 3059                    let deleted_newline_count = old_end_row - edit_start_row;
 3060                    let preview_end_row = edit_start_row + inserted_newline_count;
 3061
 3062                    start_row =
 3063                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3064                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3065
 3066                    if deleted_newline_count > 1 {
 3067                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3068                    }
 3069                }
 3070
 3071                start_row
 3072                    .zip(end_row)
 3073                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3074            }
 3075            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3076        }
 3077    }
 3078
 3079    fn edit_prediction_keybind_display(
 3080        &self,
 3081        surface: EditPredictionKeybindSurface,
 3082        window: &mut Window,
 3083        cx: &mut App,
 3084    ) -> EditPredictionKeybindDisplay {
 3085        let accept_keystroke =
 3086            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3087        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3088
 3089        let action = match surface {
 3090            EditPredictionKeybindSurface::Inline
 3091            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3092                if self.edit_prediction_requires_modifier() {
 3093                    EditPredictionKeybindAction::Preview
 3094                } else {
 3095                    EditPredictionKeybindAction::Accept
 3096                }
 3097            }
 3098            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3099                .active_edit_prediction
 3100                .as_ref()
 3101                .filter(|completion| {
 3102                    self.edit_prediction_cursor_popover_prefers_preview(completion, cx)
 3103                })
 3104                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3105                    EditPredictionKeybindAction::Preview
 3106                }),
 3107        };
 3108        #[cfg(test)]
 3109        let preview_copy = preview_keystroke.clone();
 3110        #[cfg(test)]
 3111        let accept_copy = accept_keystroke.clone();
 3112
 3113        let displayed_keystroke = match surface {
 3114            EditPredictionKeybindSurface::Inline => match action {
 3115                EditPredictionKeybindAction::Accept => accept_keystroke,
 3116                EditPredictionKeybindAction::Preview => preview_keystroke,
 3117            },
 3118            EditPredictionKeybindSurface::CursorPopoverCompact
 3119            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3120                EditPredictionKeybindAction::Accept => accept_keystroke,
 3121                EditPredictionKeybindAction::Preview => {
 3122                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3123                }
 3124            },
 3125        };
 3126
 3127        let missing_accept_keystroke = displayed_keystroke.is_none();
 3128
 3129        EditPredictionKeybindDisplay {
 3130            #[cfg(test)]
 3131            accept_keystroke: accept_copy,
 3132            #[cfg(test)]
 3133            preview_keystroke: preview_copy,
 3134            displayed_keystroke,
 3135            action,
 3136            missing_accept_keystroke,
 3137            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3138                && self.edit_prediction_preview.released_too_fast(),
 3139        }
 3140    }
 3141
 3142    pub fn new_file(
 3143        workspace: &mut Workspace,
 3144        _: &workspace::NewFile,
 3145        window: &mut Window,
 3146        cx: &mut Context<Workspace>,
 3147    ) {
 3148        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3149            "Failed to create buffer",
 3150            window,
 3151            cx,
 3152            |e, _, _| match e.error_code() {
 3153                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3154                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3155                e.error_tag("required").unwrap_or("the latest version")
 3156            )),
 3157                _ => None,
 3158            },
 3159        );
 3160    }
 3161
 3162    pub fn new_in_workspace(
 3163        workspace: &mut Workspace,
 3164        window: &mut Window,
 3165        cx: &mut Context<Workspace>,
 3166    ) -> Task<Result<Entity<Editor>>> {
 3167        let project = workspace.project().clone();
 3168        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3169
 3170        cx.spawn_in(window, async move |workspace, cx| {
 3171            let buffer = create.await?;
 3172            workspace.update_in(cx, |workspace, window, cx| {
 3173                let editor =
 3174                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3175                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3176                editor
 3177            })
 3178        })
 3179    }
 3180
 3181    fn new_file_vertical(
 3182        workspace: &mut Workspace,
 3183        _: &workspace::NewFileSplitVertical,
 3184        window: &mut Window,
 3185        cx: &mut Context<Workspace>,
 3186    ) {
 3187        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3188    }
 3189
 3190    fn new_file_horizontal(
 3191        workspace: &mut Workspace,
 3192        _: &workspace::NewFileSplitHorizontal,
 3193        window: &mut Window,
 3194        cx: &mut Context<Workspace>,
 3195    ) {
 3196        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3197    }
 3198
 3199    fn new_file_split(
 3200        workspace: &mut Workspace,
 3201        action: &workspace::NewFileSplit,
 3202        window: &mut Window,
 3203        cx: &mut Context<Workspace>,
 3204    ) {
 3205        Self::new_file_in_direction(workspace, action.0, window, cx)
 3206    }
 3207
 3208    fn new_file_in_direction(
 3209        workspace: &mut Workspace,
 3210        direction: SplitDirection,
 3211        window: &mut Window,
 3212        cx: &mut Context<Workspace>,
 3213    ) {
 3214        let project = workspace.project().clone();
 3215        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3216
 3217        cx.spawn_in(window, async move |workspace, cx| {
 3218            let buffer = create.await?;
 3219            workspace.update_in(cx, move |workspace, window, cx| {
 3220                workspace.split_item(
 3221                    direction,
 3222                    Box::new(
 3223                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3224                    ),
 3225                    window,
 3226                    cx,
 3227                )
 3228            })?;
 3229            anyhow::Ok(())
 3230        })
 3231        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3232            match e.error_code() {
 3233                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3234                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3235                e.error_tag("required").unwrap_or("the latest version")
 3236            )),
 3237                _ => None,
 3238            }
 3239        });
 3240    }
 3241
 3242    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3243        self.leader_id
 3244    }
 3245
 3246    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3247        &self.buffer
 3248    }
 3249
 3250    pub fn project(&self) -> Option<&Entity<Project>> {
 3251        self.project.as_ref()
 3252    }
 3253
 3254    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3255        self.workspace.as_ref()?.0.upgrade()
 3256    }
 3257
 3258    /// Detaches a task and shows an error notification in the workspace if available,
 3259    /// otherwise just logs the error.
 3260    pub fn detach_and_notify_err<R, E>(
 3261        &self,
 3262        task: Task<Result<R, E>>,
 3263        window: &mut Window,
 3264        cx: &mut App,
 3265    ) where
 3266        E: std::fmt::Debug + std::fmt::Display + 'static,
 3267        R: 'static,
 3268    {
 3269        if let Some(workspace) = self.workspace() {
 3270            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3271        } else {
 3272            task.detach_and_log_err(cx);
 3273        }
 3274    }
 3275
 3276    /// Returns the workspace serialization ID if this editor should be serialized.
 3277    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3278        self.workspace
 3279            .as_ref()
 3280            .filter(|_| self.should_serialize_buffer())
 3281            .and_then(|workspace| workspace.1)
 3282    }
 3283
 3284    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3285        self.buffer().read(cx).title(cx)
 3286    }
 3287
 3288    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3289        let git_blame_gutter_max_author_length = self
 3290            .render_git_blame_gutter(cx)
 3291            .then(|| {
 3292                if let Some(blame) = self.blame.as_ref() {
 3293                    let max_author_length =
 3294                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3295                    Some(max_author_length)
 3296                } else {
 3297                    None
 3298                }
 3299            })
 3300            .flatten();
 3301
 3302        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3303
 3304        EditorSnapshot {
 3305            mode: self.mode.clone(),
 3306            show_gutter: self.show_gutter,
 3307            offset_content: self.offset_content,
 3308            show_line_numbers: self.show_line_numbers,
 3309            number_deleted_lines: self.number_deleted_lines,
 3310            show_git_diff_gutter: self.show_git_diff_gutter,
 3311            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3312            show_code_actions: self.show_code_actions,
 3313            show_runnables: self.show_runnables,
 3314            show_breakpoints: self.show_breakpoints,
 3315            git_blame_gutter_max_author_length,
 3316            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3317            display_snapshot,
 3318            placeholder_display_snapshot: self
 3319                .placeholder_display_map
 3320                .as_ref()
 3321                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3322            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3323            is_focused: self.focus_handle.is_focused(window),
 3324            current_line_highlight: self
 3325                .current_line_highlight
 3326                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3327            gutter_hovered: self.gutter_hovered,
 3328        }
 3329    }
 3330
 3331    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3332        self.buffer.read(cx).language_at(point, cx)
 3333    }
 3334
 3335    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3336        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3337    }
 3338
 3339    pub fn active_buffer(&self, cx: &App) -> Option<Entity<Buffer>> {
 3340        let multibuffer = self.buffer.read(cx);
 3341        let snapshot = multibuffer.snapshot(cx);
 3342        let (anchor, _) =
 3343            snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())?;
 3344        multibuffer.buffer(anchor.buffer_id)
 3345    }
 3346
 3347    pub fn mode(&self) -> &EditorMode {
 3348        &self.mode
 3349    }
 3350
 3351    pub fn set_mode(&mut self, mode: EditorMode) {
 3352        self.mode = mode;
 3353    }
 3354
 3355    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3356        self.collaboration_hub.as_deref()
 3357    }
 3358
 3359    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3360        self.collaboration_hub = Some(hub);
 3361    }
 3362
 3363    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3364        self.in_project_search = in_project_search;
 3365    }
 3366
 3367    pub fn set_custom_context_menu(
 3368        &mut self,
 3369        f: impl 'static
 3370        + Fn(
 3371            &mut Self,
 3372            DisplayPoint,
 3373            &mut Window,
 3374            &mut Context<Self>,
 3375        ) -> Option<Entity<ui::ContextMenu>>,
 3376    ) {
 3377        self.custom_context_menu = Some(Box::new(f))
 3378    }
 3379
 3380    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3381        self.completion_provider = provider;
 3382    }
 3383
 3384    #[cfg(any(test, feature = "test-support"))]
 3385    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3386        self.completion_provider.clone()
 3387    }
 3388
 3389    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3390        self.semantics_provider.clone()
 3391    }
 3392
 3393    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3394        self.semantics_provider = provider;
 3395    }
 3396
 3397    pub fn set_edit_prediction_provider<T>(
 3398        &mut self,
 3399        provider: Option<Entity<T>>,
 3400        window: &mut Window,
 3401        cx: &mut Context<Self>,
 3402    ) where
 3403        T: EditPredictionDelegate,
 3404    {
 3405        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3406            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3407                if this.focus_handle.is_focused(window) {
 3408                    this.update_visible_edit_prediction(window, cx);
 3409                }
 3410            }),
 3411            provider: Arc::new(provider),
 3412        });
 3413        self.update_edit_prediction_settings(cx);
 3414        self.refresh_edit_prediction(false, false, window, cx);
 3415    }
 3416
 3417    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3418        self.placeholder_display_map
 3419            .as_ref()
 3420            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3421    }
 3422
 3423    pub fn set_placeholder_text(
 3424        &mut self,
 3425        placeholder_text: &str,
 3426        window: &mut Window,
 3427        cx: &mut Context<Self>,
 3428    ) {
 3429        let multibuffer = cx
 3430            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3431
 3432        let style = window.text_style();
 3433
 3434        self.placeholder_display_map = Some(cx.new(|cx| {
 3435            DisplayMap::new(
 3436                multibuffer,
 3437                style.font(),
 3438                style.font_size.to_pixels(window.rem_size()),
 3439                None,
 3440                FILE_HEADER_HEIGHT,
 3441                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3442                Default::default(),
 3443                DiagnosticSeverity::Off,
 3444                cx,
 3445            )
 3446        }));
 3447        cx.notify();
 3448    }
 3449
 3450    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3451        self.cursor_shape = cursor_shape;
 3452
 3453        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3454        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3455
 3456        cx.notify();
 3457    }
 3458
 3459    pub fn cursor_shape(&self) -> CursorShape {
 3460        self.cursor_shape
 3461    }
 3462
 3463    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3464        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3465    }
 3466
 3467    pub fn set_current_line_highlight(
 3468        &mut self,
 3469        current_line_highlight: Option<CurrentLineHighlight>,
 3470    ) {
 3471        self.current_line_highlight = current_line_highlight;
 3472    }
 3473
 3474    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3475        self.collapse_matches = collapse_matches;
 3476    }
 3477
 3478    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3479        if self.collapse_matches {
 3480            return range.start..range.start;
 3481        }
 3482        range.clone()
 3483    }
 3484
 3485    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3486        self.display_map.read(cx).clip_at_line_ends
 3487    }
 3488
 3489    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3490        if self.display_map.read(cx).clip_at_line_ends != clip {
 3491            self.display_map
 3492                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3493        }
 3494    }
 3495
 3496    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3497        self.input_enabled = input_enabled;
 3498    }
 3499
 3500    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3501        self.expects_character_input = expects_character_input;
 3502    }
 3503
 3504    pub fn set_edit_predictions_hidden_for_vim_mode(
 3505        &mut self,
 3506        hidden: bool,
 3507        window: &mut Window,
 3508        cx: &mut Context<Self>,
 3509    ) {
 3510        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3511            self.edit_predictions_hidden_for_vim_mode = hidden;
 3512            if hidden {
 3513                self.update_visible_edit_prediction(window, cx);
 3514            } else {
 3515                self.refresh_edit_prediction(true, false, window, cx);
 3516            }
 3517        }
 3518    }
 3519
 3520    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3521        self.menu_edit_predictions_policy = value;
 3522    }
 3523
 3524    pub fn set_autoindent(&mut self, autoindent: bool) {
 3525        if autoindent {
 3526            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3527        } else {
 3528            self.autoindent_mode = None;
 3529        }
 3530    }
 3531
 3532    pub fn capability(&self, cx: &App) -> Capability {
 3533        if self.read_only {
 3534            Capability::ReadOnly
 3535        } else {
 3536            self.buffer.read(cx).capability()
 3537        }
 3538    }
 3539
 3540    pub fn read_only(&self, cx: &App) -> bool {
 3541        self.read_only || self.buffer.read(cx).read_only()
 3542    }
 3543
 3544    pub fn set_read_only(&mut self, read_only: bool) {
 3545        self.read_only = read_only;
 3546    }
 3547
 3548    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3549        self.use_autoclose = autoclose;
 3550    }
 3551
 3552    pub fn set_use_selection_highlight(&mut self, highlight: bool) {
 3553        self.use_selection_highlight = highlight;
 3554    }
 3555
 3556    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3557        self.use_auto_surround = auto_surround;
 3558    }
 3559
 3560    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3561        self.auto_replace_emoji_shortcode = auto_replace;
 3562    }
 3563
 3564    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3565        self.buffer_serialization = should_serialize.then(|| {
 3566            BufferSerialization::new(
 3567                ProjectSettings::get_global(cx)
 3568                    .session
 3569                    .restore_unsaved_buffers,
 3570            )
 3571        })
 3572    }
 3573
 3574    fn should_serialize_buffer(&self) -> bool {
 3575        self.buffer_serialization.is_some()
 3576    }
 3577
 3578    pub fn toggle_edit_predictions(
 3579        &mut self,
 3580        _: &ToggleEditPrediction,
 3581        window: &mut Window,
 3582        cx: &mut Context<Self>,
 3583    ) {
 3584        if self.show_edit_predictions_override.is_some() {
 3585            self.set_show_edit_predictions(None, window, cx);
 3586        } else {
 3587            let show_edit_predictions = !self.edit_predictions_enabled();
 3588            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3589        }
 3590    }
 3591
 3592    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3593        self.show_completions_on_input_override = show_completions_on_input;
 3594    }
 3595
 3596    pub fn set_show_edit_predictions(
 3597        &mut self,
 3598        show_edit_predictions: Option<bool>,
 3599        window: &mut Window,
 3600        cx: &mut Context<Self>,
 3601    ) {
 3602        self.show_edit_predictions_override = show_edit_predictions;
 3603        self.update_edit_prediction_settings(cx);
 3604
 3605        if let Some(false) = show_edit_predictions {
 3606            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3607        } else {
 3608            self.refresh_edit_prediction(false, true, window, cx);
 3609        }
 3610    }
 3611
 3612    fn edit_predictions_disabled_in_scope(
 3613        &self,
 3614        buffer: &Entity<Buffer>,
 3615        buffer_position: language::Anchor,
 3616        cx: &App,
 3617    ) -> bool {
 3618        let snapshot = buffer.read(cx).snapshot();
 3619        let settings = snapshot.settings_at(buffer_position, cx);
 3620
 3621        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3622            return false;
 3623        };
 3624
 3625        scope.override_name().is_some_and(|scope_name| {
 3626            settings
 3627                .edit_predictions_disabled_in
 3628                .iter()
 3629                .any(|s| s == scope_name)
 3630        })
 3631    }
 3632
 3633    pub fn set_use_modal_editing(&mut self, to: bool) {
 3634        self.use_modal_editing = to;
 3635    }
 3636
 3637    pub fn use_modal_editing(&self) -> bool {
 3638        self.use_modal_editing
 3639    }
 3640
 3641    fn selections_did_change(
 3642        &mut self,
 3643        local: bool,
 3644        old_cursor_position: &Anchor,
 3645        effects: SelectionEffects,
 3646        window: &mut Window,
 3647        cx: &mut Context<Self>,
 3648    ) {
 3649        window.invalidate_character_coordinates();
 3650
 3651        // Copy selections to primary selection buffer
 3652        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3653        if local {
 3654            let selections = self
 3655                .selections
 3656                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3657            let buffer_handle = self.buffer.read(cx).read(cx);
 3658
 3659            let mut text = String::new();
 3660            for (index, selection) in selections.iter().enumerate() {
 3661                let text_for_selection = buffer_handle
 3662                    .text_for_range(selection.start..selection.end)
 3663                    .collect::<String>();
 3664
 3665                text.push_str(&text_for_selection);
 3666                if index != selections.len() - 1 {
 3667                    text.push('\n');
 3668                }
 3669            }
 3670
 3671            if !text.is_empty() {
 3672                cx.write_to_primary(ClipboardItem::new_string(text));
 3673            }
 3674        }
 3675
 3676        let selection_anchors = self.selections.disjoint_anchors_arc();
 3677
 3678        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3679            self.buffer.update(cx, |buffer, cx| {
 3680                buffer.set_active_selections(
 3681                    &selection_anchors,
 3682                    self.selections.line_mode(),
 3683                    self.cursor_shape,
 3684                    cx,
 3685                )
 3686            });
 3687        }
 3688        let display_map = self
 3689            .display_map
 3690            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3691        let buffer = display_map.buffer_snapshot();
 3692        if self.selections.count() == 1 {
 3693            self.add_selections_state = None;
 3694        }
 3695        self.select_next_state = None;
 3696        self.select_prev_state = None;
 3697        self.select_syntax_node_history.try_clear();
 3698        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3699        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3700        self.take_rename(false, window, cx);
 3701
 3702        let newest_selection = self.selections.newest_anchor();
 3703        let new_cursor_position = newest_selection.head();
 3704        let selection_start = newest_selection.start;
 3705
 3706        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3707            self.push_to_nav_history(
 3708                *old_cursor_position,
 3709                Some(new_cursor_position.to_point(buffer)),
 3710                false,
 3711                effects.nav_history == Some(true),
 3712                cx,
 3713            );
 3714        }
 3715
 3716        if local {
 3717            if let Some((anchor, _)) = buffer.anchor_to_buffer_anchor(new_cursor_position) {
 3718                self.register_buffer(anchor.buffer_id, cx);
 3719            }
 3720
 3721            let mut context_menu = self.context_menu.borrow_mut();
 3722            let completion_menu = match context_menu.as_ref() {
 3723                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3724                Some(CodeContextMenu::CodeActions(_)) => {
 3725                    *context_menu = None;
 3726                    None
 3727                }
 3728                None => None,
 3729            };
 3730            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3731            drop(context_menu);
 3732
 3733            if effects.completions
 3734                && let Some(completion_position) = completion_position
 3735            {
 3736                let start_offset = selection_start.to_offset(buffer);
 3737                let position_matches = start_offset == completion_position.to_offset(buffer);
 3738                let continue_showing = if let Some((snap, ..)) =
 3739                    buffer.point_to_buffer_offset(completion_position)
 3740                    && !snap.capability.editable()
 3741                {
 3742                    false
 3743                } else if position_matches {
 3744                    if self.snippet_stack.is_empty() {
 3745                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3746                            == Some(CharKind::Word)
 3747                    } else {
 3748                        // Snippet choices can be shown even when the cursor is in whitespace.
 3749                        // Dismissing the menu with actions like backspace is handled by
 3750                        // invalidation regions.
 3751                        true
 3752                    }
 3753                } else {
 3754                    false
 3755                };
 3756
 3757                if continue_showing {
 3758                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3759                } else {
 3760                    self.hide_context_menu(window, cx);
 3761                }
 3762            }
 3763
 3764            hide_hover(self, cx);
 3765
 3766            if old_cursor_position.to_display_point(&display_map).row()
 3767                != new_cursor_position.to_display_point(&display_map).row()
 3768            {
 3769                self.available_code_actions.take();
 3770            }
 3771            self.refresh_code_actions(window, cx);
 3772            self.refresh_document_highlights(cx);
 3773            refresh_linked_ranges(self, window, cx);
 3774
 3775            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3776            self.refresh_matching_bracket_highlights(&display_map, cx);
 3777            self.refresh_outline_symbols_at_cursor(cx);
 3778            self.update_visible_edit_prediction(window, cx);
 3779            self.inline_blame_popover.take();
 3780            if self.git_blame_inline_enabled {
 3781                self.start_inline_blame_timer(window, cx);
 3782            }
 3783        }
 3784
 3785        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3786
 3787        if local && !self.suppress_selection_callback {
 3788            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3789                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3790                callback(cursor_position, window, cx);
 3791            }
 3792        }
 3793
 3794        cx.emit(EditorEvent::SelectionsChanged { local });
 3795
 3796        let selections = &self.selections.disjoint_anchors_arc();
 3797        if selections.len() == 1 {
 3798            cx.emit(SearchEvent::ActiveMatchChanged)
 3799        }
 3800        if local && let Some(buffer_snapshot) = buffer.as_singleton() {
 3801            let inmemory_selections = selections
 3802                .iter()
 3803                .map(|s| {
 3804                    let start = s.range().start.text_anchor_in(buffer_snapshot);
 3805                    let end = s.range().end.text_anchor_in(buffer_snapshot);
 3806                    (start..end).to_point(buffer_snapshot)
 3807                })
 3808                .collect();
 3809            self.update_restoration_data(cx, |data| {
 3810                data.selections = inmemory_selections;
 3811            });
 3812
 3813            if WorkspaceSettings::get(None, cx).restore_on_startup
 3814                != RestoreOnStartupBehavior::EmptyTab
 3815                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3816            {
 3817                let snapshot = self.buffer().read(cx).snapshot(cx);
 3818                let selections = selections.clone();
 3819                let background_executor = cx.background_executor().clone();
 3820                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3821                let db = EditorDb::global(cx);
 3822                self.serialize_selections = cx.background_spawn(async move {
 3823                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3824                    let db_selections = selections
 3825                        .iter()
 3826                        .map(|selection| {
 3827                            (
 3828                                selection.start.to_offset(&snapshot).0,
 3829                                selection.end.to_offset(&snapshot).0,
 3830                            )
 3831                        })
 3832                        .collect();
 3833
 3834                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3835                        .await
 3836                        .with_context(|| {
 3837                            format!(
 3838                                "persisting editor selections for editor {editor_id}, \
 3839                                workspace {workspace_id:?}"
 3840                            )
 3841                        })
 3842                        .log_err();
 3843                });
 3844            }
 3845        }
 3846
 3847        cx.notify();
 3848    }
 3849
 3850    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3851        use text::ToOffset as _;
 3852
 3853        if self.mode.is_minimap()
 3854            || WorkspaceSettings::get(None, cx).restore_on_startup
 3855                == RestoreOnStartupBehavior::EmptyTab
 3856        {
 3857            return;
 3858        }
 3859
 3860        let display_snapshot = self
 3861            .display_map
 3862            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3863        let Some(buffer_snapshot) = display_snapshot.buffer_snapshot().as_singleton() else {
 3864            return;
 3865        };
 3866        let inmemory_folds = display_snapshot
 3867            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3868            .map(|fold| {
 3869                let start = fold.range.start.text_anchor_in(buffer_snapshot);
 3870                let end = fold.range.end.text_anchor_in(buffer_snapshot);
 3871                (start..end).to_point(buffer_snapshot)
 3872            })
 3873            .collect();
 3874        self.update_restoration_data(cx, |data| {
 3875            data.folds = inmemory_folds;
 3876        });
 3877
 3878        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3879            return;
 3880        };
 3881
 3882        // Get file path for path-based fold storage (survives tab close)
 3883        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3884            project::File::from_dyn(buffer.read(cx).file())
 3885                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3886        }) else {
 3887            return;
 3888        };
 3889
 3890        let background_executor = cx.background_executor().clone();
 3891        const FINGERPRINT_LEN: usize = 32;
 3892        let db_folds = display_snapshot
 3893            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3894            .map(|fold| {
 3895                let start = fold
 3896                    .range
 3897                    .start
 3898                    .text_anchor_in(buffer_snapshot)
 3899                    .to_offset(buffer_snapshot);
 3900                let end = fold
 3901                    .range
 3902                    .end
 3903                    .text_anchor_in(buffer_snapshot)
 3904                    .to_offset(buffer_snapshot);
 3905
 3906                // Extract fingerprints - content at fold boundaries for validation on restore
 3907                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3908                // content that might change independently.
 3909                // start_fp: first min(32, fold_len) bytes of fold content
 3910                // end_fp: last min(32, fold_len) bytes of fold content
 3911                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3912                let fold_len = end - start;
 3913                let start_fp_end = buffer_snapshot
 3914                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3915                let start_fp: String = buffer_snapshot
 3916                    .text_for_range(start..start_fp_end)
 3917                    .collect();
 3918                let end_fp_start = buffer_snapshot
 3919                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3920                let end_fp: String = buffer_snapshot.text_for_range(end_fp_start..end).collect();
 3921
 3922                (start, end, start_fp, end_fp)
 3923            })
 3924            .collect::<Vec<_>>();
 3925        let db = EditorDb::global(cx);
 3926        self.serialize_folds = cx.background_spawn(async move {
 3927            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3928            if db_folds.is_empty() {
 3929                // No folds - delete any persisted folds for this file
 3930                db.delete_file_folds(workspace_id, file_path)
 3931                    .await
 3932                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3933                    .log_err();
 3934            } else {
 3935                db.save_file_folds(workspace_id, file_path, db_folds)
 3936                    .await
 3937                    .with_context(|| {
 3938                        format!("persisting file folds for workspace {workspace_id:?}")
 3939                    })
 3940                    .log_err();
 3941            }
 3942        });
 3943    }
 3944
 3945    pub fn sync_selections(
 3946        &mut self,
 3947        other: Entity<Editor>,
 3948        cx: &mut Context<Self>,
 3949    ) -> gpui::Subscription {
 3950        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3951        if !other_selections.is_empty() {
 3952            self.selections
 3953                .change_with(&self.display_snapshot(cx), |selections| {
 3954                    selections.select_anchors(other_selections);
 3955                });
 3956        }
 3957
 3958        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3959            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3960                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3961                if other_selections.is_empty() {
 3962                    return;
 3963                }
 3964                let snapshot = this.display_snapshot(cx);
 3965                this.selections.change_with(&snapshot, |selections| {
 3966                    selections.select_anchors(other_selections);
 3967                });
 3968            }
 3969        });
 3970
 3971        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3972            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3973                let these_selections = this.selections.disjoint_anchors().to_vec();
 3974                if these_selections.is_empty() {
 3975                    return;
 3976                }
 3977                other.update(cx, |other_editor, cx| {
 3978                    let snapshot = other_editor.display_snapshot(cx);
 3979                    other_editor
 3980                        .selections
 3981                        .change_with(&snapshot, |selections| {
 3982                            selections.select_anchors(these_selections);
 3983                        })
 3984                });
 3985            }
 3986        });
 3987
 3988        Subscription::join(other_subscription, this_subscription)
 3989    }
 3990
 3991    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3992        if self.buffer().read(cx).is_singleton() {
 3993            return;
 3994        }
 3995        let snapshot = self.buffer.read(cx).snapshot(cx);
 3996        let buffer_ids: HashSet<BufferId> = self
 3997            .selections
 3998            .disjoint_anchor_ranges()
 3999            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 4000            .collect();
 4001        for buffer_id in buffer_ids {
 4002            self.unfold_buffer(buffer_id, cx);
 4003        }
 4004    }
 4005
 4006    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 4007    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 4008    /// effects of selection change occur at the end of the transaction.
 4009    pub fn change_selections<R>(
 4010        &mut self,
 4011        effects: SelectionEffects,
 4012        window: &mut Window,
 4013        cx: &mut Context<Self>,
 4014        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 4015    ) -> R {
 4016        let snapshot = self.display_snapshot(cx);
 4017        if let Some(state) = &mut self.deferred_selection_effects_state {
 4018            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 4019            state.effects.completions = effects.completions;
 4020            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 4021            let (changed, result) = self.selections.change_with(&snapshot, change);
 4022            state.changed |= changed;
 4023            return result;
 4024        }
 4025        let mut state = DeferredSelectionEffectsState {
 4026            changed: false,
 4027            effects,
 4028            old_cursor_position: self.selections.newest_anchor().head(),
 4029            history_entry: SelectionHistoryEntry {
 4030                selections: self.selections.disjoint_anchors_arc(),
 4031                select_next_state: self.select_next_state.clone(),
 4032                select_prev_state: self.select_prev_state.clone(),
 4033                add_selections_state: self.add_selections_state.clone(),
 4034            },
 4035        };
 4036        let (changed, result) = self.selections.change_with(&snapshot, change);
 4037        state.changed = state.changed || changed;
 4038        if self.defer_selection_effects {
 4039            self.deferred_selection_effects_state = Some(state);
 4040        } else {
 4041            self.apply_selection_effects(state, window, cx);
 4042        }
 4043        result
 4044    }
 4045
 4046    /// Defers the effects of selection change, so that the effects of multiple calls to
 4047    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4048    /// to selection history and the state of popovers based on selection position aren't
 4049    /// erroneously updated.
 4050    pub fn with_selection_effects_deferred<R>(
 4051        &mut self,
 4052        window: &mut Window,
 4053        cx: &mut Context<Self>,
 4054        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4055    ) -> R {
 4056        let already_deferred = self.defer_selection_effects;
 4057        self.defer_selection_effects = true;
 4058        let result = update(self, window, cx);
 4059        if !already_deferred {
 4060            self.defer_selection_effects = false;
 4061            if let Some(state) = self.deferred_selection_effects_state.take() {
 4062                self.apply_selection_effects(state, window, cx);
 4063            }
 4064        }
 4065        result
 4066    }
 4067
 4068    fn apply_selection_effects(
 4069        &mut self,
 4070        state: DeferredSelectionEffectsState,
 4071        window: &mut Window,
 4072        cx: &mut Context<Self>,
 4073    ) {
 4074        if state.changed {
 4075            self.selection_history.push(state.history_entry);
 4076
 4077            if let Some(autoscroll) = state.effects.scroll {
 4078                self.request_autoscroll(autoscroll, cx);
 4079            }
 4080
 4081            let old_cursor_position = &state.old_cursor_position;
 4082
 4083            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4084
 4085            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4086                self.show_signature_help_auto(window, cx);
 4087            }
 4088        }
 4089    }
 4090
 4091    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4092    where
 4093        I: IntoIterator<Item = (Range<S>, T)>,
 4094        S: ToOffset,
 4095        T: Into<Arc<str>>,
 4096    {
 4097        if self.read_only(cx) {
 4098            return;
 4099        }
 4100
 4101        self.buffer
 4102            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4103    }
 4104
 4105    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4106    where
 4107        I: IntoIterator<Item = (Range<S>, T)>,
 4108        S: ToOffset,
 4109        T: Into<Arc<str>>,
 4110    {
 4111        if self.read_only(cx) {
 4112            return;
 4113        }
 4114
 4115        self.buffer.update(cx, |buffer, cx| {
 4116            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4117        });
 4118    }
 4119
 4120    pub fn edit_with_block_indent<I, S, T>(
 4121        &mut self,
 4122        edits: I,
 4123        original_indent_columns: Vec<Option<u32>>,
 4124        cx: &mut Context<Self>,
 4125    ) where
 4126        I: IntoIterator<Item = (Range<S>, T)>,
 4127        S: ToOffset,
 4128        T: Into<Arc<str>>,
 4129    {
 4130        if self.read_only(cx) {
 4131            return;
 4132        }
 4133
 4134        self.buffer.update(cx, |buffer, cx| {
 4135            buffer.edit(
 4136                edits,
 4137                Some(AutoindentMode::Block {
 4138                    original_indent_columns,
 4139                }),
 4140                cx,
 4141            )
 4142        });
 4143    }
 4144
 4145    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4146        self.hide_context_menu(window, cx);
 4147
 4148        match phase {
 4149            SelectPhase::Begin {
 4150                position,
 4151                add,
 4152                click_count,
 4153            } => self.begin_selection(position, add, click_count, window, cx),
 4154            SelectPhase::BeginColumnar {
 4155                position,
 4156                goal_column,
 4157                reset,
 4158                mode,
 4159            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4160            SelectPhase::Extend {
 4161                position,
 4162                click_count,
 4163            } => self.extend_selection(position, click_count, window, cx),
 4164            SelectPhase::Update {
 4165                position,
 4166                goal_column,
 4167                scroll_delta,
 4168            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4169            SelectPhase::End => self.end_selection(window, cx),
 4170        }
 4171    }
 4172
 4173    fn extend_selection(
 4174        &mut self,
 4175        position: DisplayPoint,
 4176        click_count: usize,
 4177        window: &mut Window,
 4178        cx: &mut Context<Self>,
 4179    ) {
 4180        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4181        let tail = self
 4182            .selections
 4183            .newest::<MultiBufferOffset>(&display_map)
 4184            .tail();
 4185        let click_count = click_count.max(match self.selections.select_mode() {
 4186            SelectMode::Character => 1,
 4187            SelectMode::Word(_) => 2,
 4188            SelectMode::Line(_) => 3,
 4189            SelectMode::All => 4,
 4190        });
 4191        self.begin_selection(position, false, click_count, window, cx);
 4192
 4193        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4194
 4195        let current_selection = match self.selections.select_mode() {
 4196            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4197            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4198        };
 4199
 4200        let mut pending_selection = self
 4201            .selections
 4202            .pending_anchor()
 4203            .cloned()
 4204            .expect("extend_selection not called with pending selection");
 4205
 4206        if pending_selection
 4207            .start
 4208            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4209            == Ordering::Greater
 4210        {
 4211            pending_selection.start = current_selection.start;
 4212        }
 4213        if pending_selection
 4214            .end
 4215            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4216            == Ordering::Less
 4217        {
 4218            pending_selection.end = current_selection.end;
 4219            pending_selection.reversed = true;
 4220        }
 4221
 4222        let mut pending_mode = self.selections.pending_mode().unwrap();
 4223        match &mut pending_mode {
 4224            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4225            _ => {}
 4226        }
 4227
 4228        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4229            SelectionEffects::scroll(Autoscroll::fit())
 4230        } else {
 4231            SelectionEffects::no_scroll()
 4232        };
 4233
 4234        self.change_selections(effects, window, cx, |s| {
 4235            s.set_pending(pending_selection.clone(), pending_mode);
 4236            s.set_is_extending(true);
 4237        });
 4238    }
 4239
 4240    fn begin_selection(
 4241        &mut self,
 4242        position: DisplayPoint,
 4243        add: bool,
 4244        click_count: usize,
 4245        window: &mut Window,
 4246        cx: &mut Context<Self>,
 4247    ) {
 4248        if !self.focus_handle.is_focused(window) {
 4249            self.last_focused_descendant = None;
 4250            window.focus(&self.focus_handle, cx);
 4251        }
 4252
 4253        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4254        let buffer = display_map.buffer_snapshot();
 4255        let position = display_map.clip_point(position, Bias::Left);
 4256
 4257        let start;
 4258        let end;
 4259        let mode;
 4260        let mut auto_scroll;
 4261        match click_count {
 4262            1 => {
 4263                start = buffer.anchor_before(position.to_point(&display_map));
 4264                end = start;
 4265                mode = SelectMode::Character;
 4266                auto_scroll = true;
 4267            }
 4268            2 => {
 4269                let position = display_map
 4270                    .clip_point(position, Bias::Left)
 4271                    .to_offset(&display_map, Bias::Left);
 4272                let (range, _) = buffer.surrounding_word(position, None);
 4273                start = buffer.anchor_before(range.start);
 4274                end = buffer.anchor_before(range.end);
 4275                mode = SelectMode::Word(start..end);
 4276                auto_scroll = true;
 4277            }
 4278            3 => {
 4279                let position = display_map
 4280                    .clip_point(position, Bias::Left)
 4281                    .to_point(&display_map);
 4282                let line_start = display_map.prev_line_boundary(position).0;
 4283                let next_line_start = buffer.clip_point(
 4284                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4285                    Bias::Left,
 4286                );
 4287                start = buffer.anchor_before(line_start);
 4288                end = buffer.anchor_before(next_line_start);
 4289                mode = SelectMode::Line(start..end);
 4290                auto_scroll = true;
 4291            }
 4292            _ => {
 4293                start = buffer.anchor_before(MultiBufferOffset(0));
 4294                end = buffer.anchor_before(buffer.len());
 4295                mode = SelectMode::All;
 4296                auto_scroll = false;
 4297            }
 4298        }
 4299        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4300
 4301        let point_to_delete: Option<usize> = {
 4302            let selected_points: Vec<Selection<Point>> =
 4303                self.selections.disjoint_in_range(start..end, &display_map);
 4304
 4305            if !add || click_count > 1 {
 4306                None
 4307            } else if !selected_points.is_empty() {
 4308                Some(selected_points[0].id)
 4309            } else {
 4310                let clicked_point_already_selected =
 4311                    self.selections.disjoint_anchors().iter().find(|selection| {
 4312                        selection.start.to_point(buffer) == start.to_point(buffer)
 4313                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4314                    });
 4315
 4316                clicked_point_already_selected.map(|selection| selection.id)
 4317            }
 4318        };
 4319
 4320        let selections_count = self.selections.count();
 4321        let effects = if auto_scroll {
 4322            SelectionEffects::default()
 4323        } else {
 4324            SelectionEffects::no_scroll()
 4325        };
 4326
 4327        self.change_selections(effects, window, cx, |s| {
 4328            if let Some(point_to_delete) = point_to_delete {
 4329                s.delete(point_to_delete);
 4330
 4331                if selections_count == 1 {
 4332                    s.set_pending_anchor_range(start..end, mode);
 4333                }
 4334            } else {
 4335                if !add {
 4336                    s.clear_disjoint();
 4337                }
 4338
 4339                s.set_pending_anchor_range(start..end, mode);
 4340            }
 4341        });
 4342    }
 4343
 4344    fn begin_columnar_selection(
 4345        &mut self,
 4346        position: DisplayPoint,
 4347        goal_column: u32,
 4348        reset: bool,
 4349        mode: ColumnarMode,
 4350        window: &mut Window,
 4351        cx: &mut Context<Self>,
 4352    ) {
 4353        if !self.focus_handle.is_focused(window) {
 4354            self.last_focused_descendant = None;
 4355            window.focus(&self.focus_handle, cx);
 4356        }
 4357
 4358        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4359
 4360        if reset {
 4361            let pointer_position = display_map
 4362                .buffer_snapshot()
 4363                .anchor_before(position.to_point(&display_map));
 4364
 4365            self.change_selections(
 4366                SelectionEffects::scroll(Autoscroll::newest()),
 4367                window,
 4368                cx,
 4369                |s| {
 4370                    s.clear_disjoint();
 4371                    s.set_pending_anchor_range(
 4372                        pointer_position..pointer_position,
 4373                        SelectMode::Character,
 4374                    );
 4375                },
 4376            );
 4377        };
 4378
 4379        let tail = self.selections.newest::<Point>(&display_map).tail();
 4380        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4381        self.columnar_selection_state = match mode {
 4382            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4383                selection_tail: selection_anchor,
 4384                display_point: if reset {
 4385                    if position.column() != goal_column {
 4386                        Some(DisplayPoint::new(position.row(), goal_column))
 4387                    } else {
 4388                        None
 4389                    }
 4390                } else {
 4391                    None
 4392                },
 4393            }),
 4394            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4395                selection_tail: selection_anchor,
 4396            }),
 4397        };
 4398
 4399        if !reset {
 4400            self.select_columns(position, goal_column, &display_map, window, cx);
 4401        }
 4402    }
 4403
 4404    fn update_selection(
 4405        &mut self,
 4406        position: DisplayPoint,
 4407        goal_column: u32,
 4408        scroll_delta: gpui::Point<f32>,
 4409        window: &mut Window,
 4410        cx: &mut Context<Self>,
 4411    ) {
 4412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4413
 4414        if self.columnar_selection_state.is_some() {
 4415            self.select_columns(position, goal_column, &display_map, window, cx);
 4416        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4417            let buffer = display_map.buffer_snapshot();
 4418            let head;
 4419            let tail;
 4420            let mode = self.selections.pending_mode().unwrap();
 4421            match &mode {
 4422                SelectMode::Character => {
 4423                    head = position.to_point(&display_map);
 4424                    tail = pending.tail().to_point(buffer);
 4425                }
 4426                SelectMode::Word(original_range) => {
 4427                    let offset = display_map
 4428                        .clip_point(position, Bias::Left)
 4429                        .to_offset(&display_map, Bias::Left);
 4430                    let original_range = original_range.to_offset(buffer);
 4431
 4432                    let head_offset = if buffer.is_inside_word(offset, None)
 4433                        || original_range.contains(&offset)
 4434                    {
 4435                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4436                        if word_range.start < original_range.start {
 4437                            word_range.start
 4438                        } else {
 4439                            word_range.end
 4440                        }
 4441                    } else {
 4442                        offset
 4443                    };
 4444
 4445                    head = head_offset.to_point(buffer);
 4446                    if head_offset <= original_range.start {
 4447                        tail = original_range.end.to_point(buffer);
 4448                    } else {
 4449                        tail = original_range.start.to_point(buffer);
 4450                    }
 4451                }
 4452                SelectMode::Line(original_range) => {
 4453                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4454
 4455                    let position = display_map
 4456                        .clip_point(position, Bias::Left)
 4457                        .to_point(&display_map);
 4458                    let line_start = display_map.prev_line_boundary(position).0;
 4459                    let next_line_start = buffer.clip_point(
 4460                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4461                        Bias::Left,
 4462                    );
 4463
 4464                    if line_start < original_range.start {
 4465                        head = line_start
 4466                    } else {
 4467                        head = next_line_start
 4468                    }
 4469
 4470                    if head <= original_range.start {
 4471                        tail = original_range.end;
 4472                    } else {
 4473                        tail = original_range.start;
 4474                    }
 4475                }
 4476                SelectMode::All => {
 4477                    return;
 4478                }
 4479            };
 4480
 4481            if head < tail {
 4482                pending.start = buffer.anchor_before(head);
 4483                pending.end = buffer.anchor_before(tail);
 4484                pending.reversed = true;
 4485            } else {
 4486                pending.start = buffer.anchor_before(tail);
 4487                pending.end = buffer.anchor_before(head);
 4488                pending.reversed = false;
 4489            }
 4490
 4491            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4492                s.set_pending(pending.clone(), mode);
 4493            });
 4494        } else {
 4495            log::error!("update_selection dispatched with no pending selection");
 4496            return;
 4497        }
 4498
 4499        self.apply_scroll_delta(scroll_delta, window, cx);
 4500        cx.notify();
 4501    }
 4502
 4503    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4504        self.columnar_selection_state.take();
 4505        if let Some(pending_mode) = self.selections.pending_mode() {
 4506            let selections = self
 4507                .selections
 4508                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4509            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4510                s.select(selections);
 4511                s.clear_pending();
 4512                if s.is_extending() {
 4513                    s.set_is_extending(false);
 4514                } else {
 4515                    s.set_select_mode(pending_mode);
 4516                }
 4517            });
 4518        }
 4519    }
 4520
 4521    fn select_columns(
 4522        &mut self,
 4523        head: DisplayPoint,
 4524        goal_column: u32,
 4525        display_map: &DisplaySnapshot,
 4526        window: &mut Window,
 4527        cx: &mut Context<Self>,
 4528    ) {
 4529        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4530            return;
 4531        };
 4532
 4533        let tail = match columnar_state {
 4534            ColumnarSelectionState::FromMouse {
 4535                selection_tail,
 4536                display_point,
 4537            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4538            ColumnarSelectionState::FromSelection { selection_tail } => {
 4539                selection_tail.to_display_point(display_map)
 4540            }
 4541        };
 4542
 4543        let start_row = cmp::min(tail.row(), head.row());
 4544        let end_row = cmp::max(tail.row(), head.row());
 4545        let start_column = cmp::min(tail.column(), goal_column);
 4546        let end_column = cmp::max(tail.column(), goal_column);
 4547        let reversed = start_column < tail.column();
 4548
 4549        let selection_ranges = (start_row.0..=end_row.0)
 4550            .map(DisplayRow)
 4551            .filter_map(|row| {
 4552                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4553                    || start_column <= display_map.line_len(row))
 4554                    && !display_map.is_block_line(row)
 4555                {
 4556                    let start = display_map
 4557                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4558                        .to_point(display_map);
 4559                    let end = display_map
 4560                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4561                        .to_point(display_map);
 4562                    if reversed {
 4563                        Some(end..start)
 4564                    } else {
 4565                        Some(start..end)
 4566                    }
 4567                } else {
 4568                    None
 4569                }
 4570            })
 4571            .collect::<Vec<_>>();
 4572        if selection_ranges.is_empty() {
 4573            return;
 4574        }
 4575
 4576        let ranges = match columnar_state {
 4577            ColumnarSelectionState::FromMouse { .. } => {
 4578                let mut non_empty_ranges = selection_ranges
 4579                    .iter()
 4580                    .filter(|selection_range| selection_range.start != selection_range.end)
 4581                    .peekable();
 4582                if non_empty_ranges.peek().is_some() {
 4583                    non_empty_ranges.cloned().collect()
 4584                } else {
 4585                    selection_ranges
 4586                }
 4587            }
 4588            _ => selection_ranges,
 4589        };
 4590
 4591        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4592            s.select_ranges(ranges);
 4593        });
 4594        cx.notify();
 4595    }
 4596
 4597    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4598        self.selections
 4599            .all_adjusted(snapshot)
 4600            .iter()
 4601            .any(|selection| !selection.is_empty())
 4602    }
 4603
 4604    pub fn has_pending_nonempty_selection(&self) -> bool {
 4605        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4606            Some(Selection { start, end, .. }) => start != end,
 4607            None => false,
 4608        };
 4609
 4610        pending_nonempty_selection
 4611            || (self.columnar_selection_state.is_some()
 4612                && self.selections.disjoint_anchors().len() > 1)
 4613    }
 4614
 4615    pub fn has_pending_selection(&self) -> bool {
 4616        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4617    }
 4618
 4619    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4620        self.selection_mark_mode = false;
 4621        self.selection_drag_state = SelectionDragState::None;
 4622
 4623        if self.dismiss_menus_and_popups(true, window, cx) {
 4624            cx.notify();
 4625            return;
 4626        }
 4627        if self.clear_expanded_diff_hunks(cx) {
 4628            cx.notify();
 4629            return;
 4630        }
 4631        if self.show_git_blame_gutter {
 4632            self.show_git_blame_gutter = false;
 4633            cx.notify();
 4634            return;
 4635        }
 4636
 4637        if self.mode.is_full()
 4638            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4639        {
 4640            cx.notify();
 4641            return;
 4642        }
 4643
 4644        cx.propagate();
 4645    }
 4646
 4647    pub fn dismiss_menus_and_popups(
 4648        &mut self,
 4649        is_user_requested: bool,
 4650        window: &mut Window,
 4651        cx: &mut Context<Self>,
 4652    ) -> bool {
 4653        let mut dismissed = false;
 4654
 4655        dismissed |= self.take_rename(false, window, cx).is_some();
 4656        dismissed |= self.hide_blame_popover(true, cx);
 4657        dismissed |= hide_hover(self, cx);
 4658        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4659        dismissed |= self.hide_context_menu(window, cx).is_some();
 4660        dismissed |= self.mouse_context_menu.take().is_some();
 4661        dismissed |= is_user_requested
 4662            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4663        dismissed |= self.snippet_stack.pop().is_some();
 4664        if self.diff_review_drag_state.is_some() {
 4665            self.cancel_diff_review_drag(cx);
 4666            dismissed = true;
 4667        }
 4668        if !self.diff_review_overlays.is_empty() {
 4669            self.dismiss_all_diff_review_overlays(cx);
 4670            dismissed = true;
 4671        }
 4672
 4673        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4674            self.dismiss_diagnostics(cx);
 4675            dismissed = true;
 4676        }
 4677
 4678        dismissed
 4679    }
 4680
 4681    fn linked_editing_ranges_for(
 4682        &self,
 4683        query_range: Range<text::Anchor>,
 4684        cx: &App,
 4685    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4686        use text::ToOffset as TO;
 4687
 4688        if self.linked_edit_ranges.is_empty() {
 4689            return None;
 4690        }
 4691        if query_range.start.buffer_id != query_range.end.buffer_id {
 4692            return None;
 4693        };
 4694        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 4695        let buffer = self.buffer.read(cx).buffer(query_range.end.buffer_id)?;
 4696        let buffer_snapshot = buffer.read(cx).snapshot();
 4697        let (base_range, linked_ranges) = self.linked_edit_ranges.get(
 4698            buffer_snapshot.remote_id(),
 4699            query_range.clone(),
 4700            &buffer_snapshot,
 4701        )?;
 4702        // find offset from the start of current range to current cursor position
 4703        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4704
 4705        let start_offset = TO::to_offset(&query_range.start, &buffer_snapshot);
 4706        let start_difference = start_offset - start_byte_offset;
 4707        let end_offset = TO::to_offset(&query_range.end, &buffer_snapshot);
 4708        let end_difference = end_offset - start_byte_offset;
 4709
 4710        // Current range has associated linked ranges.
 4711        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4712        for range in linked_ranges.iter() {
 4713            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4714            let end_offset = start_offset + end_difference;
 4715            let start_offset = start_offset + start_difference;
 4716            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4717                continue;
 4718            }
 4719            if self.selections.disjoint_anchor_ranges().any(|s| {
 4720                let Some((selection_start, _)) =
 4721                    multibuffer_snapshot.anchor_to_buffer_anchor(s.start)
 4722                else {
 4723                    return false;
 4724                };
 4725                let Some((selection_end, _)) = multibuffer_snapshot.anchor_to_buffer_anchor(s.end)
 4726                else {
 4727                    return false;
 4728                };
 4729                if selection_start.buffer_id != query_range.start.buffer_id
 4730                    || selection_end.buffer_id != query_range.end.buffer_id
 4731                {
 4732                    return false;
 4733                }
 4734                TO::to_offset(&selection_start, &buffer_snapshot) <= end_offset
 4735                    && TO::to_offset(&selection_end, &buffer_snapshot) >= start_offset
 4736            }) {
 4737                continue;
 4738            }
 4739            let start = buffer_snapshot.anchor_after(start_offset);
 4740            let end = buffer_snapshot.anchor_after(end_offset);
 4741            linked_edits
 4742                .entry(buffer.clone())
 4743                .or_default()
 4744                .push(start..end);
 4745        }
 4746        Some(linked_edits)
 4747    }
 4748
 4749    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4750        let text: Arc<str> = text.into();
 4751
 4752        if self.read_only(cx) {
 4753            return;
 4754        }
 4755
 4756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4757
 4758        self.unfold_buffers_with_selections(cx);
 4759
 4760        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4761        let mut bracket_inserted = false;
 4762        let mut edits = Vec::new();
 4763        let mut linked_edits = LinkedEdits::new();
 4764        let mut new_selections = Vec::with_capacity(selections.len());
 4765        let mut new_autoclose_regions = Vec::new();
 4766        let snapshot = self.buffer.read(cx).read(cx);
 4767        let mut clear_linked_edit_ranges = false;
 4768        let mut all_selections_read_only = true;
 4769        let mut has_adjacent_edits = false;
 4770        let mut in_adjacent_group = false;
 4771
 4772        let mut regions = self
 4773            .selections_with_autoclose_regions(selections, &snapshot)
 4774            .peekable();
 4775
 4776        while let Some((selection, autoclose_region)) = regions.next() {
 4777            if snapshot
 4778                .point_to_buffer_point(selection.head())
 4779                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4780            {
 4781                continue;
 4782            }
 4783            if snapshot
 4784                .point_to_buffer_point(selection.tail())
 4785                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4786            {
 4787                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4788                continue;
 4789            }
 4790            all_selections_read_only = false;
 4791
 4792            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4793                // Determine if the inserted text matches the opening or closing
 4794                // bracket of any of this language's bracket pairs.
 4795                let mut bracket_pair = None;
 4796                let mut is_bracket_pair_start = false;
 4797                let mut is_bracket_pair_end = false;
 4798                if !text.is_empty() {
 4799                    let mut bracket_pair_matching_end = None;
 4800                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4801                    //  and they are removing the character that triggered IME popup.
 4802                    for (pair, enabled) in scope.brackets() {
 4803                        if !pair.close && !pair.surround {
 4804                            continue;
 4805                        }
 4806
 4807                        if enabled && pair.start.ends_with(text.as_ref()) {
 4808                            let prefix_len = pair.start.len() - text.len();
 4809                            let preceding_text_matches_prefix = prefix_len == 0
 4810                                || (selection.start.column >= (prefix_len as u32)
 4811                                    && snapshot.contains_str_at(
 4812                                        Point::new(
 4813                                            selection.start.row,
 4814                                            selection.start.column - (prefix_len as u32),
 4815                                        ),
 4816                                        &pair.start[..prefix_len],
 4817                                    ));
 4818                            if preceding_text_matches_prefix {
 4819                                bracket_pair = Some(pair.clone());
 4820                                is_bracket_pair_start = true;
 4821                                break;
 4822                            }
 4823                        }
 4824                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4825                        {
 4826                            // take first bracket pair matching end, but don't break in case a later bracket
 4827                            // pair matches start
 4828                            bracket_pair_matching_end = Some(pair.clone());
 4829                        }
 4830                    }
 4831                    if let Some(end) = bracket_pair_matching_end
 4832                        && bracket_pair.is_none()
 4833                    {
 4834                        bracket_pair = Some(end);
 4835                        is_bracket_pair_end = true;
 4836                    }
 4837                }
 4838
 4839                if let Some(bracket_pair) = bracket_pair {
 4840                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4841                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4842                    let auto_surround =
 4843                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4844                    if selection.is_empty() {
 4845                        if is_bracket_pair_start {
 4846                            // If the inserted text is a suffix of an opening bracket and the
 4847                            // selection is preceded by the rest of the opening bracket, then
 4848                            // insert the closing bracket.
 4849                            let following_text_allows_autoclose = snapshot
 4850                                .chars_at(selection.start)
 4851                                .next()
 4852                                .is_none_or(|c| scope.should_autoclose_before(c));
 4853
 4854                            let preceding_text_allows_autoclose = selection.start.column == 0
 4855                                || snapshot
 4856                                    .reversed_chars_at(selection.start)
 4857                                    .next()
 4858                                    .is_none_or(|c| {
 4859                                        bracket_pair.start != bracket_pair.end
 4860                                            || !snapshot
 4861                                                .char_classifier_at(selection.start)
 4862                                                .is_word(c)
 4863                                    });
 4864
 4865                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4866                                && bracket_pair.start.len() == 1
 4867                            {
 4868                                let target = bracket_pair.start.chars().next().unwrap();
 4869                                let mut byte_offset = 0u32;
 4870                                let current_line_count = snapshot
 4871                                    .reversed_chars_at(selection.start)
 4872                                    .take_while(|&c| c != '\n')
 4873                                    .filter(|c| {
 4874                                        byte_offset += c.len_utf8() as u32;
 4875                                        if *c != target {
 4876                                            return false;
 4877                                        }
 4878
 4879                                        let point = Point::new(
 4880                                            selection.start.row,
 4881                                            selection.start.column.saturating_sub(byte_offset),
 4882                                        );
 4883
 4884                                        let is_enabled = snapshot
 4885                                            .language_scope_at(point)
 4886                                            .and_then(|scope| {
 4887                                                scope
 4888                                                    .brackets()
 4889                                                    .find(|(pair, _)| {
 4890                                                        pair.start == bracket_pair.start
 4891                                                    })
 4892                                                    .map(|(_, enabled)| enabled)
 4893                                            })
 4894                                            .unwrap_or(true);
 4895
 4896                                        let is_delimiter = snapshot
 4897                                            .language_scope_at(Point::new(
 4898                                                point.row,
 4899                                                point.column + 1,
 4900                                            ))
 4901                                            .and_then(|scope| {
 4902                                                scope
 4903                                                    .brackets()
 4904                                                    .find(|(pair, _)| {
 4905                                                        pair.start == bracket_pair.start
 4906                                                    })
 4907                                                    .map(|(_, enabled)| !enabled)
 4908                                            })
 4909                                            .unwrap_or(false);
 4910
 4911                                        is_enabled && !is_delimiter
 4912                                    })
 4913                                    .count();
 4914                                current_line_count % 2 == 1
 4915                            } else {
 4916                                false
 4917                            };
 4918
 4919                            if autoclose
 4920                                && bracket_pair.close
 4921                                && following_text_allows_autoclose
 4922                                && preceding_text_allows_autoclose
 4923                                && !is_closing_quote
 4924                            {
 4925                                let anchor = snapshot.anchor_before(selection.end);
 4926                                new_selections.push((selection.map(|_| anchor), text.len()));
 4927                                new_autoclose_regions.push((
 4928                                    anchor,
 4929                                    text.len(),
 4930                                    selection.id,
 4931                                    bracket_pair.clone(),
 4932                                ));
 4933                                edits.push((
 4934                                    selection.range(),
 4935                                    format!("{}{}", text, bracket_pair.end).into(),
 4936                                ));
 4937                                bracket_inserted = true;
 4938                                continue;
 4939                            }
 4940                        }
 4941
 4942                        if let Some(region) = autoclose_region {
 4943                            // If the selection is followed by an auto-inserted closing bracket,
 4944                            // then don't insert that closing bracket again; just move the selection
 4945                            // past the closing bracket.
 4946                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4947                                && text.as_ref() == region.pair.end.as_str()
 4948                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4949                            if should_skip {
 4950                                let anchor = snapshot.anchor_after(selection.end);
 4951                                new_selections
 4952                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4953                                continue;
 4954                            }
 4955                        }
 4956
 4957                        let always_treat_brackets_as_autoclosed = snapshot
 4958                            .language_settings_at(selection.start, cx)
 4959                            .always_treat_brackets_as_autoclosed;
 4960                        if always_treat_brackets_as_autoclosed
 4961                            && is_bracket_pair_end
 4962                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4963                        {
 4964                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4965                            // and the inserted text is a closing bracket and the selection is followed
 4966                            // by the closing bracket then move the selection past the closing bracket.
 4967                            let anchor = snapshot.anchor_after(selection.end);
 4968                            new_selections.push((selection.map(|_| anchor), text.len()));
 4969                            continue;
 4970                        }
 4971                    }
 4972                    // If an opening bracket is 1 character long and is typed while
 4973                    // text is selected, then surround that text with the bracket pair.
 4974                    else if auto_surround
 4975                        && bracket_pair.surround
 4976                        && is_bracket_pair_start
 4977                        && bracket_pair.start.chars().count() == 1
 4978                    {
 4979                        edits.push((selection.start..selection.start, text.clone()));
 4980                        edits.push((
 4981                            selection.end..selection.end,
 4982                            bracket_pair.end.as_str().into(),
 4983                        ));
 4984                        bracket_inserted = true;
 4985                        new_selections.push((
 4986                            Selection {
 4987                                id: selection.id,
 4988                                start: snapshot.anchor_after(selection.start),
 4989                                end: snapshot.anchor_before(selection.end),
 4990                                reversed: selection.reversed,
 4991                                goal: selection.goal,
 4992                            },
 4993                            0,
 4994                        ));
 4995                        continue;
 4996                    }
 4997                }
 4998            }
 4999
 5000            if self.auto_replace_emoji_shortcode
 5001                && selection.is_empty()
 5002                && text.as_ref().ends_with(':')
 5003                && let Some(possible_emoji_short_code) =
 5004                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 5005                && !possible_emoji_short_code.is_empty()
 5006                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 5007            {
 5008                let emoji_shortcode_start = Point::new(
 5009                    selection.start.row,
 5010                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 5011                );
 5012
 5013                // Remove shortcode from buffer
 5014                edits.push((
 5015                    emoji_shortcode_start..selection.start,
 5016                    "".to_string().into(),
 5017                ));
 5018                new_selections.push((
 5019                    Selection {
 5020                        id: selection.id,
 5021                        start: snapshot.anchor_after(emoji_shortcode_start),
 5022                        end: snapshot.anchor_before(selection.start),
 5023                        reversed: selection.reversed,
 5024                        goal: selection.goal,
 5025                    },
 5026                    0,
 5027                ));
 5028
 5029                // Insert emoji
 5030                let selection_start_anchor = snapshot.anchor_after(selection.start);
 5031                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 5032                edits.push((selection.start..selection.end, emoji.to_string().into()));
 5033
 5034                continue;
 5035            }
 5036
 5037            let next_is_adjacent = regions
 5038                .peek()
 5039                .is_some_and(|(next, _)| selection.end == next.start);
 5040
 5041            // If not handling any auto-close operation, then just replace the selected
 5042            // text with the given input and move the selection to the end of the
 5043            // newly inserted text.
 5044            let anchor = if in_adjacent_group || next_is_adjacent {
 5045                // After edits the right bias would shift those anchor to the next visible fragment
 5046                // but we want to resolve to the previous one
 5047                snapshot.anchor_before(selection.end)
 5048            } else {
 5049                snapshot.anchor_after(selection.end)
 5050            };
 5051
 5052            if !self.linked_edit_ranges.is_empty() {
 5053                let start_anchor = snapshot.anchor_before(selection.start);
 5054                let classifier = snapshot
 5055                    .char_classifier_at(start_anchor)
 5056                    .scope_context(Some(CharScopeContext::LinkedEdit));
 5057
 5058                if let Some((_, anchor_range)) =
 5059                    snapshot.anchor_range_to_buffer_anchor_range(start_anchor..anchor)
 5060                {
 5061                    let is_word_char = text
 5062                        .chars()
 5063                        .next()
 5064                        .is_none_or(|char| classifier.is_word(char));
 5065
 5066                    let is_dot = text.as_ref() == ".";
 5067                    let should_apply_linked_edit = is_word_char || is_dot;
 5068
 5069                    if should_apply_linked_edit {
 5070                        linked_edits.push(&self, anchor_range, text.clone(), cx);
 5071                    } else {
 5072                        clear_linked_edit_ranges = true;
 5073                    }
 5074                }
 5075            }
 5076
 5077            new_selections.push((selection.map(|_| anchor), 0));
 5078            edits.push((selection.start..selection.end, text.clone()));
 5079
 5080            has_adjacent_edits |= next_is_adjacent;
 5081            in_adjacent_group = next_is_adjacent;
 5082        }
 5083
 5084        if all_selections_read_only {
 5085            return;
 5086        }
 5087
 5088        drop(regions);
 5089        drop(snapshot);
 5090
 5091        self.transact(window, cx, |this, window, cx| {
 5092            if clear_linked_edit_ranges {
 5093                this.linked_edit_ranges.clear();
 5094            }
 5095            let initial_buffer_versions =
 5096                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5097
 5098            this.buffer.update(cx, |buffer, cx| {
 5099                if has_adjacent_edits {
 5100                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5101                } else {
 5102                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5103                }
 5104            });
 5105            linked_edits.apply(cx);
 5106            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5107            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5108            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5109            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5110                new_anchor_selections,
 5111                &map,
 5112            )
 5113            .zip(new_selection_deltas)
 5114            .map(|(selection, delta)| Selection {
 5115                id: selection.id,
 5116                start: selection.start + delta,
 5117                end: selection.end + delta,
 5118                reversed: selection.reversed,
 5119                goal: SelectionGoal::None,
 5120            })
 5121            .collect::<Vec<_>>();
 5122
 5123            let mut i = 0;
 5124            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5125                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5126                let start = map.buffer_snapshot().anchor_before(position);
 5127                let end = map.buffer_snapshot().anchor_after(position);
 5128                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5129                    match existing_state
 5130                        .range
 5131                        .start
 5132                        .cmp(&start, map.buffer_snapshot())
 5133                    {
 5134                        Ordering::Less => i += 1,
 5135                        Ordering::Greater => break,
 5136                        Ordering::Equal => {
 5137                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5138                                Ordering::Less => i += 1,
 5139                                Ordering::Equal => break,
 5140                                Ordering::Greater => break,
 5141                            }
 5142                        }
 5143                    }
 5144                }
 5145                this.autoclose_regions.insert(
 5146                    i,
 5147                    AutocloseRegion {
 5148                        selection_id,
 5149                        range: start..end,
 5150                        pair,
 5151                    },
 5152                );
 5153            }
 5154
 5155            let had_active_edit_prediction = this.has_active_edit_prediction();
 5156            this.change_selections(
 5157                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5158                window,
 5159                cx,
 5160                |s| s.select(new_selections),
 5161            );
 5162
 5163            if !bracket_inserted
 5164                && let Some(on_type_format_task) =
 5165                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5166            {
 5167                on_type_format_task.detach_and_log_err(cx);
 5168            }
 5169
 5170            let editor_settings = EditorSettings::get_global(cx);
 5171            if bracket_inserted
 5172                && (editor_settings.auto_signature_help
 5173                    || editor_settings.show_signature_help_after_edits)
 5174            {
 5175                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5176            }
 5177
 5178            let trigger_in_words =
 5179                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5180            if this.hard_wrap.is_some() {
 5181                let latest: Range<Point> = this.selections.newest(&map).range();
 5182                if latest.is_empty()
 5183                    && this
 5184                        .buffer()
 5185                        .read(cx)
 5186                        .snapshot(cx)
 5187                        .line_len(MultiBufferRow(latest.start.row))
 5188                        == latest.start.column
 5189                {
 5190                    this.rewrap_impl(
 5191                        RewrapOptions {
 5192                            override_language_settings: true,
 5193                            preserve_existing_whitespace: true,
 5194                            line_length: None,
 5195                        },
 5196                        cx,
 5197                    )
 5198                }
 5199            }
 5200            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5201            refresh_linked_ranges(this, window, cx);
 5202            this.refresh_edit_prediction(true, false, window, cx);
 5203            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5204        });
 5205    }
 5206
 5207    fn find_possible_emoji_shortcode_at_position(
 5208        snapshot: &MultiBufferSnapshot,
 5209        position: Point,
 5210    ) -> Option<String> {
 5211        let mut chars = Vec::new();
 5212        let mut found_colon = false;
 5213        for char in snapshot.reversed_chars_at(position).take(100) {
 5214            // Found a possible emoji shortcode in the middle of the buffer
 5215            if found_colon {
 5216                if char.is_whitespace() {
 5217                    chars.reverse();
 5218                    return Some(chars.iter().collect());
 5219                }
 5220                // If the previous character is not a whitespace, we are in the middle of a word
 5221                // and we only want to complete the shortcode if the word is made up of other emojis
 5222                let mut containing_word = String::new();
 5223                for ch in snapshot
 5224                    .reversed_chars_at(position)
 5225                    .skip(chars.len() + 1)
 5226                    .take(100)
 5227                {
 5228                    if ch.is_whitespace() {
 5229                        break;
 5230                    }
 5231                    containing_word.push(ch);
 5232                }
 5233                let containing_word = containing_word.chars().rev().collect::<String>();
 5234                if util::word_consists_of_emojis(containing_word.as_str()) {
 5235                    chars.reverse();
 5236                    return Some(chars.iter().collect());
 5237                }
 5238            }
 5239
 5240            if char.is_whitespace() || !char.is_ascii() {
 5241                return None;
 5242            }
 5243            if char == ':' {
 5244                found_colon = true;
 5245            } else {
 5246                chars.push(char);
 5247            }
 5248        }
 5249        // Found a possible emoji shortcode at the beginning of the buffer
 5250        chars.reverse();
 5251        Some(chars.iter().collect())
 5252    }
 5253
 5254    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5255        if self.read_only(cx) {
 5256            return;
 5257        }
 5258
 5259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5260        self.transact(window, cx, |this, window, cx| {
 5261            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5262                let selections = this
 5263                    .selections
 5264                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5265                let multi_buffer = this.buffer.read(cx);
 5266                let buffer = multi_buffer.snapshot(cx);
 5267                selections
 5268                    .iter()
 5269                    .map(|selection| {
 5270                        let start_point = selection.start.to_point(&buffer);
 5271                        let mut existing_indent =
 5272                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5273                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5274                        let start = selection.start;
 5275                        let end = selection.end;
 5276                        let selection_is_empty = start == end;
 5277                        let language_scope = buffer.language_scope_at(start);
 5278                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5279                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5280                                &buffer,
 5281                                start..end,
 5282                                language,
 5283                            )
 5284                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5285                                    &buffer,
 5286                                    start..end,
 5287                                );
 5288
 5289                            let mut newline_config = NewlineConfig::Newline {
 5290                                additional_indent: IndentSize::spaces(0),
 5291                                extra_line_additional_indent: if needs_extra_newline {
 5292                                    Some(IndentSize::spaces(0))
 5293                                } else {
 5294                                    None
 5295                                },
 5296                                prevent_auto_indent: false,
 5297                            };
 5298
 5299                            let comment_delimiter = maybe!({
 5300                                if !selection_is_empty {
 5301                                    return None;
 5302                                }
 5303
 5304                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5305                                    return None;
 5306                                }
 5307
 5308                                return comment_delimiter_for_newline(
 5309                                    &start_point,
 5310                                    &buffer,
 5311                                    language,
 5312                                );
 5313                            });
 5314
 5315                            let doc_delimiter = maybe!({
 5316                                if !selection_is_empty {
 5317                                    return None;
 5318                                }
 5319
 5320                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5321                                    return None;
 5322                                }
 5323
 5324                                return documentation_delimiter_for_newline(
 5325                                    &start_point,
 5326                                    &buffer,
 5327                                    language,
 5328                                    &mut newline_config,
 5329                                );
 5330                            });
 5331
 5332                            let list_delimiter = maybe!({
 5333                                if !selection_is_empty {
 5334                                    return None;
 5335                                }
 5336
 5337                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5338                                    return None;
 5339                                }
 5340
 5341                                return list_delimiter_for_newline(
 5342                                    &start_point,
 5343                                    &buffer,
 5344                                    language,
 5345                                    &mut newline_config,
 5346                                );
 5347                            });
 5348
 5349                            (
 5350                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5351                                newline_config,
 5352                            )
 5353                        } else {
 5354                            (
 5355                                None,
 5356                                NewlineConfig::Newline {
 5357                                    additional_indent: IndentSize::spaces(0),
 5358                                    extra_line_additional_indent: None,
 5359                                    prevent_auto_indent: false,
 5360                                },
 5361                            )
 5362                        };
 5363
 5364                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5365                            NewlineConfig::ClearCurrentLine => {
 5366                                let row_start =
 5367                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5368                                (row_start, String::new(), false)
 5369                            }
 5370                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5371                                let row_start =
 5372                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5373                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5374                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5375                                let reduced_indent =
 5376                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5377                                let mut new_text = String::new();
 5378                                new_text.extend(reduced_indent.chars());
 5379                                new_text.push_str(continuation);
 5380                                (row_start, new_text, true)
 5381                            }
 5382                            NewlineConfig::Newline {
 5383                                additional_indent,
 5384                                extra_line_additional_indent,
 5385                                prevent_auto_indent,
 5386                            } => {
 5387                                let auto_indent_mode =
 5388                                    buffer.language_settings_at(start, cx).auto_indent;
 5389                                let preserve_indent =
 5390                                    auto_indent_mode != language::AutoIndentMode::None;
 5391                                let apply_syntax_indent =
 5392                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5393                                let capacity_for_delimiter =
 5394                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5395                                let existing_indent_len = if preserve_indent {
 5396                                    existing_indent.len as usize
 5397                                } else {
 5398                                    0
 5399                                };
 5400                                let extra_line_len = extra_line_additional_indent
 5401                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5402                                    .unwrap_or(0);
 5403                                let mut new_text = String::with_capacity(
 5404                                    1 + capacity_for_delimiter
 5405                                        + existing_indent_len
 5406                                        + additional_indent.len as usize
 5407                                        + extra_line_len,
 5408                                );
 5409                                new_text.push('\n');
 5410                                if preserve_indent {
 5411                                    new_text.extend(existing_indent.chars());
 5412                                }
 5413                                new_text.extend(additional_indent.chars());
 5414                                if let Some(delimiter) = &delimiter {
 5415                                    new_text.push_str(delimiter);
 5416                                }
 5417                                if let Some(extra_indent) = extra_line_additional_indent {
 5418                                    new_text.push('\n');
 5419                                    if preserve_indent {
 5420                                        new_text.extend(existing_indent.chars());
 5421                                    }
 5422                                    new_text.extend(extra_indent.chars());
 5423                                }
 5424                                (
 5425                                    start,
 5426                                    new_text,
 5427                                    *prevent_auto_indent || !apply_syntax_indent,
 5428                                )
 5429                            }
 5430                        };
 5431
 5432                        let anchor = buffer.anchor_after(end);
 5433                        let new_selection = selection.map(|_| anchor);
 5434                        (
 5435                            ((edit_start..end, new_text), prevent_auto_indent),
 5436                            (newline_config.has_extra_line(), new_selection),
 5437                        )
 5438                    })
 5439                    .unzip()
 5440            };
 5441
 5442            let mut auto_indent_edits = Vec::new();
 5443            let mut edits = Vec::new();
 5444            for (edit, prevent_auto_indent) in edits_with_flags {
 5445                if prevent_auto_indent {
 5446                    edits.push(edit);
 5447                } else {
 5448                    auto_indent_edits.push(edit);
 5449                }
 5450            }
 5451            if !edits.is_empty() {
 5452                this.edit(edits, cx);
 5453            }
 5454            if !auto_indent_edits.is_empty() {
 5455                this.edit_with_autoindent(auto_indent_edits, cx);
 5456            }
 5457
 5458            let buffer = this.buffer.read(cx).snapshot(cx);
 5459            let new_selections = selection_info
 5460                .into_iter()
 5461                .map(|(extra_newline_inserted, new_selection)| {
 5462                    let mut cursor = new_selection.end.to_point(&buffer);
 5463                    if extra_newline_inserted {
 5464                        cursor.row -= 1;
 5465                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5466                    }
 5467                    new_selection.map(|_| cursor)
 5468                })
 5469                .collect();
 5470
 5471            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5472            this.refresh_edit_prediction(true, false, window, cx);
 5473            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5474                task.detach_and_log_err(cx);
 5475            }
 5476        });
 5477    }
 5478
 5479    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5480        if self.read_only(cx) {
 5481            return;
 5482        }
 5483
 5484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5485
 5486        let buffer = self.buffer.read(cx);
 5487        let snapshot = buffer.snapshot(cx);
 5488
 5489        let mut edits = Vec::new();
 5490        let mut rows = Vec::new();
 5491
 5492        for (rows_inserted, selection) in self
 5493            .selections
 5494            .all_adjusted(&self.display_snapshot(cx))
 5495            .into_iter()
 5496            .enumerate()
 5497        {
 5498            let cursor = selection.head();
 5499            let row = cursor.row;
 5500
 5501            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5502
 5503            let newline = "\n".to_string();
 5504            edits.push((start_of_line..start_of_line, newline));
 5505
 5506            rows.push(row + rows_inserted as u32);
 5507        }
 5508
 5509        self.transact(window, cx, |editor, window, cx| {
 5510            editor.edit(edits, cx);
 5511
 5512            editor.change_selections(Default::default(), window, cx, |s| {
 5513                let mut index = 0;
 5514                s.move_cursors_with(&mut |map, _, _| {
 5515                    let row = rows[index];
 5516                    index += 1;
 5517
 5518                    let point = Point::new(row, 0);
 5519                    let boundary = map.next_line_boundary(point).1;
 5520                    let clipped = map.clip_point(boundary, Bias::Left);
 5521
 5522                    (clipped, SelectionGoal::None)
 5523                });
 5524            });
 5525
 5526            let mut indent_edits = Vec::new();
 5527            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5528            for row in rows {
 5529                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5530                for (row, indent) in indents {
 5531                    if indent.len == 0 {
 5532                        continue;
 5533                    }
 5534
 5535                    let text = match indent.kind {
 5536                        IndentKind::Space => " ".repeat(indent.len as usize),
 5537                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5538                    };
 5539                    let point = Point::new(row.0, 0);
 5540                    indent_edits.push((point..point, text));
 5541                }
 5542            }
 5543            editor.edit(indent_edits, cx);
 5544            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5545                format.detach_and_log_err(cx);
 5546            }
 5547        });
 5548    }
 5549
 5550    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5551        if self.read_only(cx) {
 5552            return;
 5553        }
 5554
 5555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5556
 5557        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5558        let mut rows = Vec::new();
 5559        let mut rows_inserted = 0;
 5560
 5561        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5562            let cursor = selection.head();
 5563            let row = cursor.row;
 5564
 5565            let point = Point::new(row, 0);
 5566            let Some((buffer_handle, buffer_point)) =
 5567                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5568            else {
 5569                continue;
 5570            };
 5571
 5572            buffer_edits
 5573                .entry(buffer_handle.entity_id())
 5574                .or_insert_with(|| (buffer_handle, Vec::new()))
 5575                .1
 5576                .push(buffer_point);
 5577
 5578            rows_inserted += 1;
 5579            rows.push(row + rows_inserted);
 5580        }
 5581
 5582        self.transact(window, cx, |editor, window, cx| {
 5583            for (_, (buffer_handle, points)) in &buffer_edits {
 5584                buffer_handle.update(cx, |buffer, cx| {
 5585                    let edits: Vec<_> = points
 5586                        .iter()
 5587                        .map(|point| {
 5588                            let target = Point::new(point.row + 1, 0);
 5589                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5590                            (start_of_line..start_of_line, "\n")
 5591                        })
 5592                        .collect();
 5593                    buffer.edit(edits, None, cx);
 5594                });
 5595            }
 5596
 5597            editor.change_selections(Default::default(), window, cx, |s| {
 5598                let mut index = 0;
 5599                s.move_cursors_with(&mut |map, _, _| {
 5600                    let row = rows[index];
 5601                    index += 1;
 5602
 5603                    let point = Point::new(row, 0);
 5604                    let boundary = map.next_line_boundary(point).1;
 5605                    let clipped = map.clip_point(boundary, Bias::Left);
 5606
 5607                    (clipped, SelectionGoal::None)
 5608                });
 5609            });
 5610
 5611            let mut indent_edits = Vec::new();
 5612            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5613            for row in rows {
 5614                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5615                for (row, indent) in indents {
 5616                    if indent.len == 0 {
 5617                        continue;
 5618                    }
 5619
 5620                    let text = match indent.kind {
 5621                        IndentKind::Space => " ".repeat(indent.len as usize),
 5622                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5623                    };
 5624                    let point = Point::new(row.0, 0);
 5625                    indent_edits.push((point..point, text));
 5626                }
 5627            }
 5628            editor.edit(indent_edits, cx);
 5629            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5630                format.detach_and_log_err(cx);
 5631            }
 5632        });
 5633    }
 5634
 5635    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5636        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5637            original_indent_columns: Vec::new(),
 5638        });
 5639        self.replace_selections(text, autoindent, window, cx, false);
 5640    }
 5641
 5642    /// Replaces the editor's selections with the provided `text`, applying the
 5643    /// given `autoindent_mode` (`None` will skip autoindentation).
 5644    ///
 5645    /// Early returns if the editor is in read-only mode, without applying any
 5646    /// edits.
 5647    fn replace_selections(
 5648        &mut self,
 5649        text: &str,
 5650        autoindent_mode: Option<AutoindentMode>,
 5651        window: &mut Window,
 5652        cx: &mut Context<Self>,
 5653        apply_linked_edits: bool,
 5654    ) {
 5655        if self.read_only(cx) {
 5656            return;
 5657        }
 5658
 5659        let text: Arc<str> = text.into();
 5660        self.transact(window, cx, |this, window, cx| {
 5661            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5662            let linked_edits = if apply_linked_edits {
 5663                this.linked_edits_for_selections(text.clone(), cx)
 5664            } else {
 5665                LinkedEdits::new()
 5666            };
 5667
 5668            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5669                let anchors = {
 5670                    let snapshot = buffer.read(cx);
 5671                    old_selections
 5672                        .iter()
 5673                        .map(|s| {
 5674                            let anchor = snapshot.anchor_after(s.head());
 5675                            s.map(|_| anchor)
 5676                        })
 5677                        .collect::<Vec<_>>()
 5678                };
 5679                buffer.edit(
 5680                    old_selections
 5681                        .iter()
 5682                        .map(|s| (s.start..s.end, text.clone())),
 5683                    autoindent_mode,
 5684                    cx,
 5685                );
 5686                anchors
 5687            });
 5688
 5689            linked_edits.apply(cx);
 5690
 5691            this.change_selections(Default::default(), window, cx, |s| {
 5692                s.select_anchors(selection_anchors);
 5693            });
 5694
 5695            if apply_linked_edits {
 5696                refresh_linked_ranges(this, window, cx);
 5697            }
 5698
 5699            cx.notify();
 5700        });
 5701    }
 5702
 5703    /// Collects linked edits for the current selections, pairing each linked
 5704    /// range with `text`.
 5705    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5706        let multibuffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5707        let mut linked_edits = LinkedEdits::new();
 5708        if !self.linked_edit_ranges.is_empty() {
 5709            for selection in self.selections.disjoint_anchors() {
 5710                let Some((_, range)) =
 5711                    multibuffer_snapshot.anchor_range_to_buffer_anchor_range(selection.range())
 5712                else {
 5713                    continue;
 5714                };
 5715                linked_edits.push(self, range, text.clone(), cx);
 5716            }
 5717        }
 5718        linked_edits
 5719    }
 5720
 5721    /// Deletes the content covered by the current selections and applies
 5722    /// linked edits.
 5723    pub fn delete_selections_with_linked_edits(
 5724        &mut self,
 5725        window: &mut Window,
 5726        cx: &mut Context<Self>,
 5727    ) {
 5728        self.replace_selections("", None, window, cx, true);
 5729    }
 5730
 5731    #[cfg(any(test, feature = "test-support"))]
 5732    pub fn set_linked_edit_ranges_for_testing(
 5733        &mut self,
 5734        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5735        cx: &mut Context<Self>,
 5736    ) -> Option<()> {
 5737        let Some((buffer, _)) = self
 5738            .buffer
 5739            .read(cx)
 5740            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5741        else {
 5742            return None;
 5743        };
 5744        let buffer = buffer.read(cx);
 5745        let buffer_id = buffer.remote_id();
 5746        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5747        for (base_range, linked_ranges_points) in ranges {
 5748            let base_anchor =
 5749                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5750            let linked_anchors = linked_ranges_points
 5751                .into_iter()
 5752                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5753                .collect();
 5754            linked_ranges.push((base_anchor, linked_anchors));
 5755        }
 5756        let mut map = HashMap::default();
 5757        map.insert(buffer_id, linked_ranges);
 5758        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5759        Some(())
 5760    }
 5761
 5762    fn trigger_completion_on_input(
 5763        &mut self,
 5764        text: &str,
 5765        trigger_in_words: bool,
 5766        window: &mut Window,
 5767        cx: &mut Context<Self>,
 5768    ) {
 5769        let completions_source = self
 5770            .context_menu
 5771            .borrow()
 5772            .as_ref()
 5773            .and_then(|menu| match menu {
 5774                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5775                CodeContextMenu::CodeActions(_) => None,
 5776            });
 5777
 5778        match completions_source {
 5779            Some(CompletionsMenuSource::Words { .. }) => {
 5780                self.open_or_update_completions_menu(
 5781                    Some(CompletionsMenuSource::Words {
 5782                        ignore_threshold: false,
 5783                    }),
 5784                    None,
 5785                    trigger_in_words,
 5786                    window,
 5787                    cx,
 5788                );
 5789            }
 5790            _ => self.open_or_update_completions_menu(
 5791                None,
 5792                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5793                true,
 5794                window,
 5795                cx,
 5796            ),
 5797        }
 5798    }
 5799
 5800    /// If any empty selections is touching the start of its innermost containing autoclose
 5801    /// region, expand it to select the brackets.
 5802    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5803        let selections = self
 5804            .selections
 5805            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5806        let buffer = self.buffer.read(cx).read(cx);
 5807        let new_selections = self
 5808            .selections_with_autoclose_regions(selections, &buffer)
 5809            .map(|(mut selection, region)| {
 5810                if !selection.is_empty() {
 5811                    return selection;
 5812                }
 5813
 5814                if let Some(region) = region {
 5815                    let mut range = region.range.to_offset(&buffer);
 5816                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5817                        range.start -= region.pair.start.len();
 5818                        if buffer.contains_str_at(range.start, &region.pair.start)
 5819                            && buffer.contains_str_at(range.end, &region.pair.end)
 5820                        {
 5821                            range.end += region.pair.end.len();
 5822                            selection.start = range.start;
 5823                            selection.end = range.end;
 5824
 5825                            return selection;
 5826                        }
 5827                    }
 5828                }
 5829
 5830                let always_treat_brackets_as_autoclosed = buffer
 5831                    .language_settings_at(selection.start, cx)
 5832                    .always_treat_brackets_as_autoclosed;
 5833
 5834                if !always_treat_brackets_as_autoclosed {
 5835                    return selection;
 5836                }
 5837
 5838                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5839                    for (pair, enabled) in scope.brackets() {
 5840                        if !enabled || !pair.close {
 5841                            continue;
 5842                        }
 5843
 5844                        if buffer.contains_str_at(selection.start, &pair.end) {
 5845                            let pair_start_len = pair.start.len();
 5846                            if buffer.contains_str_at(
 5847                                selection.start.saturating_sub_usize(pair_start_len),
 5848                                &pair.start,
 5849                            ) {
 5850                                selection.start -= pair_start_len;
 5851                                selection.end += pair.end.len();
 5852
 5853                                return selection;
 5854                            }
 5855                        }
 5856                    }
 5857                }
 5858
 5859                selection
 5860            })
 5861            .collect();
 5862
 5863        drop(buffer);
 5864        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5865            selections.select(new_selections)
 5866        });
 5867    }
 5868
 5869    /// Iterate the given selections, and for each one, find the smallest surrounding
 5870    /// autoclose region. This uses the ordering of the selections and the autoclose
 5871    /// regions to avoid repeated comparisons.
 5872    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5873        &'a self,
 5874        selections: impl IntoIterator<Item = Selection<D>>,
 5875        buffer: &'a MultiBufferSnapshot,
 5876    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5877        let mut i = 0;
 5878        let mut regions = self.autoclose_regions.as_slice();
 5879        selections.into_iter().map(move |selection| {
 5880            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5881
 5882            let mut enclosing = None;
 5883            while let Some(pair_state) = regions.get(i) {
 5884                if pair_state.range.end.to_offset(buffer) < range.start {
 5885                    regions = &regions[i + 1..];
 5886                    i = 0;
 5887                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5888                    break;
 5889                } else {
 5890                    if pair_state.selection_id == selection.id {
 5891                        enclosing = Some(pair_state);
 5892                    }
 5893                    i += 1;
 5894                }
 5895            }
 5896
 5897            (selection, enclosing)
 5898        })
 5899    }
 5900
 5901    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5902    fn invalidate_autoclose_regions(
 5903        &mut self,
 5904        mut selections: &[Selection<Anchor>],
 5905        buffer: &MultiBufferSnapshot,
 5906    ) {
 5907        self.autoclose_regions.retain(|state| {
 5908            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5909                return false;
 5910            }
 5911
 5912            let mut i = 0;
 5913            while let Some(selection) = selections.get(i) {
 5914                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5915                    selections = &selections[1..];
 5916                    continue;
 5917                }
 5918                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5919                    break;
 5920                }
 5921                if selection.id == state.selection_id {
 5922                    return true;
 5923                } else {
 5924                    i += 1;
 5925                }
 5926            }
 5927            false
 5928        });
 5929    }
 5930
 5931    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5932        let offset = position.to_offset(buffer);
 5933        let (word_range, kind) =
 5934            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5935        if offset > word_range.start && kind == Some(CharKind::Word) {
 5936            Some(
 5937                buffer
 5938                    .text_for_range(word_range.start..offset)
 5939                    .collect::<String>(),
 5940            )
 5941        } else {
 5942            None
 5943        }
 5944    }
 5945
 5946    pub fn is_lsp_relevant(&self, file: Option<&Arc<dyn language::File>>, cx: &App) -> bool {
 5947        let Some(project) = self.project() else {
 5948            return false;
 5949        };
 5950        let Some(buffer_file) = project::File::from_dyn(file) else {
 5951            return false;
 5952        };
 5953        let Some(entry_id) = buffer_file.project_entry_id() else {
 5954            return false;
 5955        };
 5956        let project = project.read(cx);
 5957        let Some(buffer_worktree) = project.worktree_for_id(buffer_file.worktree_id(cx), cx) else {
 5958            return false;
 5959        };
 5960        let Some(worktree_entry) = buffer_worktree.read(cx).entry_for_id(entry_id) else {
 5961            return false;
 5962        };
 5963        !worktree_entry.is_ignored
 5964    }
 5965
 5966    pub fn visible_buffers(&self, cx: &mut Context<Editor>) -> Vec<Entity<Buffer>> {
 5967        let display_snapshot = self.display_snapshot(cx);
 5968        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5969        let multi_buffer = self.buffer().read(cx);
 5970        display_snapshot
 5971            .buffer_snapshot()
 5972            .range_to_buffer_ranges(visible_range)
 5973            .into_iter()
 5974            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5975            .filter_map(|(buffer_snapshot, _, _)| multi_buffer.buffer(buffer_snapshot.remote_id()))
 5976            .collect()
 5977    }
 5978
 5979    pub fn visible_buffer_ranges(
 5980        &self,
 5981        cx: &mut Context<Editor>,
 5982    ) -> Vec<(
 5983        BufferSnapshot,
 5984        Range<BufferOffset>,
 5985        ExcerptRange<text::Anchor>,
 5986    )> {
 5987        let display_snapshot = self.display_snapshot(cx);
 5988        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5989        display_snapshot
 5990            .buffer_snapshot()
 5991            .range_to_buffer_ranges(visible_range)
 5992            .into_iter()
 5993            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5994            .collect()
 5995    }
 5996
 5997    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5998        TextLayoutDetails {
 5999            text_system: window.text_system().clone(),
 6000            editor_style: self.style.clone().unwrap(),
 6001            rem_size: window.rem_size(),
 6002            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 6003            visible_rows: self.visible_line_count(),
 6004            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 6005        }
 6006    }
 6007
 6008    fn trigger_on_type_formatting(
 6009        &self,
 6010        input: String,
 6011        window: &mut Window,
 6012        cx: &mut Context<Self>,
 6013    ) -> Option<Task<Result<()>>> {
 6014        if input.chars().count() != 1 {
 6015            return None;
 6016        }
 6017
 6018        let project = self.project()?;
 6019        let position = self.selections.newest_anchor().head();
 6020        let (buffer, buffer_position) = self
 6021            .buffer
 6022            .read(cx)
 6023            .text_anchor_for_position(position, cx)?;
 6024
 6025        let settings = LanguageSettings::for_buffer_at(&buffer.read(cx), buffer_position, cx);
 6026        if !settings.use_on_type_format {
 6027            return None;
 6028        }
 6029
 6030        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 6031        // hence we do LSP request & edit on host side only — add formats to host's history.
 6032        let push_to_lsp_host_history = true;
 6033        // If this is not the host, append its history with new edits.
 6034        let push_to_client_history = project.read(cx).is_via_collab();
 6035
 6036        let on_type_formatting = project.update(cx, |project, cx| {
 6037            project.on_type_format(
 6038                buffer.clone(),
 6039                buffer_position,
 6040                input,
 6041                push_to_lsp_host_history,
 6042                cx,
 6043            )
 6044        });
 6045        Some(cx.spawn_in(window, async move |editor, cx| {
 6046            if let Some(transaction) = on_type_formatting.await? {
 6047                if push_to_client_history {
 6048                    buffer.update(cx, |buffer, _| {
 6049                        buffer.push_transaction(transaction, Instant::now());
 6050                        buffer.finalize_last_transaction();
 6051                    });
 6052                }
 6053                editor.update(cx, |editor, cx| {
 6054                    editor.refresh_document_highlights(cx);
 6055                })?;
 6056            }
 6057            Ok(())
 6058        }))
 6059    }
 6060
 6061    pub fn show_word_completions(
 6062        &mut self,
 6063        _: &ShowWordCompletions,
 6064        window: &mut Window,
 6065        cx: &mut Context<Self>,
 6066    ) {
 6067        self.open_or_update_completions_menu(
 6068            Some(CompletionsMenuSource::Words {
 6069                ignore_threshold: true,
 6070            }),
 6071            None,
 6072            false,
 6073            window,
 6074            cx,
 6075        );
 6076    }
 6077
 6078    pub fn show_completions(
 6079        &mut self,
 6080        _: &ShowCompletions,
 6081        window: &mut Window,
 6082        cx: &mut Context<Self>,
 6083    ) {
 6084        self.open_or_update_completions_menu(None, None, false, window, cx);
 6085    }
 6086
 6087    fn open_or_update_completions_menu(
 6088        &mut self,
 6089        requested_source: Option<CompletionsMenuSource>,
 6090        trigger: Option<String>,
 6091        trigger_in_words: bool,
 6092        window: &mut Window,
 6093        cx: &mut Context<Self>,
 6094    ) {
 6095        if self.pending_rename.is_some() {
 6096            return;
 6097        }
 6098
 6099        let completions_source = self
 6100            .context_menu
 6101            .borrow()
 6102            .as_ref()
 6103            .and_then(|menu| match menu {
 6104                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6105                CodeContextMenu::CodeActions(_) => None,
 6106            });
 6107
 6108        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6109
 6110        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6111        // inserted and selected. To handle that case, the start of the selection is used so that
 6112        // the menu starts with all choices.
 6113        let position = self
 6114            .selections
 6115            .newest_anchor()
 6116            .start
 6117            .bias_right(&multibuffer_snapshot);
 6118
 6119        if position.diff_base_anchor().is_some() {
 6120            return;
 6121        }
 6122        let multibuffer_position = multibuffer_snapshot.anchor_before(position);
 6123        let Some((buffer_position, _)) =
 6124            multibuffer_snapshot.anchor_to_buffer_anchor(multibuffer_position)
 6125        else {
 6126            return;
 6127        };
 6128        let Some(buffer) = self.buffer.read(cx).buffer(buffer_position.buffer_id) else {
 6129            return;
 6130        };
 6131        let buffer_snapshot = buffer.read(cx).snapshot();
 6132
 6133        let menu_is_open = matches!(
 6134            self.context_menu.borrow().as_ref(),
 6135            Some(CodeContextMenu::Completions(_))
 6136        );
 6137
 6138        let language = buffer_snapshot
 6139            .language_at(buffer_position)
 6140            .map(|language| language.name());
 6141        let language_settings = multibuffer_snapshot.language_settings_at(multibuffer_position, cx);
 6142        let completion_settings = language_settings.completions.clone();
 6143
 6144        let show_completions_on_input = self
 6145            .show_completions_on_input_override
 6146            .unwrap_or(language_settings.show_completions_on_input);
 6147        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6148            return;
 6149        }
 6150
 6151        let query: Option<Arc<String>> =
 6152            Self::completion_query(&multibuffer_snapshot, multibuffer_position)
 6153                .map(|query| query.into());
 6154
 6155        drop(multibuffer_snapshot);
 6156
 6157        // Hide the current completions menu when query is empty. Without this, cached
 6158        // completions from before the trigger char may be reused (#32774).
 6159        if query.is_none() && menu_is_open {
 6160            self.hide_context_menu(window, cx);
 6161        }
 6162
 6163        let mut ignore_word_threshold = false;
 6164        let provider = match requested_source {
 6165            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6166            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6167                ignore_word_threshold = ignore_threshold;
 6168                None
 6169            }
 6170            Some(CompletionsMenuSource::SnippetChoices)
 6171            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6172                log::error!("bug: SnippetChoices requested_source is not handled");
 6173                None
 6174            }
 6175        };
 6176
 6177        let sort_completions = provider
 6178            .as_ref()
 6179            .is_some_and(|provider| provider.sort_completions());
 6180
 6181        let filter_completions = provider
 6182            .as_ref()
 6183            .is_none_or(|provider| provider.filter_completions());
 6184
 6185        let was_snippets_only = matches!(
 6186            completions_source,
 6187            Some(CompletionsMenuSource::SnippetsOnly)
 6188        );
 6189
 6190        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6191            if filter_completions {
 6192                menu.filter(
 6193                    query.clone().unwrap_or_default(),
 6194                    buffer_position,
 6195                    &buffer,
 6196                    provider.clone(),
 6197                    window,
 6198                    cx,
 6199                );
 6200            }
 6201            // When `is_incomplete` is false, no need to re-query completions when the current query
 6202            // is a suffix of the initial query.
 6203            let was_complete = !menu.is_incomplete;
 6204            if was_complete && !was_snippets_only {
 6205                // If the new query is a suffix of the old query (typing more characters) and
 6206                // the previous result was complete, the existing completions can be filtered.
 6207                //
 6208                // Note that snippet completions are always complete.
 6209                let query_matches = match (&menu.initial_query, &query) {
 6210                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6211                    (None, _) => true,
 6212                    _ => false,
 6213                };
 6214                if query_matches {
 6215                    let position_matches = if menu.initial_position == position {
 6216                        true
 6217                    } else {
 6218                        let snapshot = self.buffer.read(cx).read(cx);
 6219                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6220                    };
 6221                    if position_matches {
 6222                        return;
 6223                    }
 6224                }
 6225            }
 6226        };
 6227
 6228        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6229            buffer_snapshot.surrounding_word(buffer_position, None)
 6230        {
 6231            let word_to_exclude = buffer_snapshot
 6232                .text_for_range(word_range.clone())
 6233                .collect::<String>();
 6234            (
 6235                buffer_snapshot.anchor_before(word_range.start)
 6236                    ..buffer_snapshot.anchor_after(buffer_position),
 6237                Some(word_to_exclude),
 6238            )
 6239        } else {
 6240            (buffer_position..buffer_position, None)
 6241        };
 6242
 6243        let show_completion_documentation = buffer_snapshot
 6244            .settings_at(buffer_position, cx)
 6245            .show_completion_documentation;
 6246
 6247        // The document can be large, so stay in reasonable bounds when searching for words,
 6248        // otherwise completion pop-up might be slow to appear.
 6249        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6250        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6251        let min_word_search = buffer_snapshot.clip_point(
 6252            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6253            Bias::Left,
 6254        );
 6255        let max_word_search = buffer_snapshot.clip_point(
 6256            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6257            Bias::Right,
 6258        );
 6259        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6260            ..buffer_snapshot.point_to_offset(max_word_search);
 6261
 6262        let skip_digits = query
 6263            .as_ref()
 6264            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6265
 6266        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6267            trigger.as_ref().is_none_or(|trigger| {
 6268                provider.is_completion_trigger(
 6269                    &buffer,
 6270                    buffer_position,
 6271                    trigger,
 6272                    trigger_in_words,
 6273                    cx,
 6274                )
 6275            })
 6276        });
 6277
 6278        let provider_responses = if let Some(provider) = &provider
 6279            && load_provider_completions
 6280        {
 6281            let trigger_character =
 6282                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6283            let completion_context = CompletionContext {
 6284                trigger_kind: match &trigger_character {
 6285                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6286                    None => CompletionTriggerKind::INVOKED,
 6287                },
 6288                trigger_character,
 6289            };
 6290
 6291            provider.completions(&buffer, buffer_position, completion_context, window, cx)
 6292        } else {
 6293            Task::ready(Ok(Vec::new()))
 6294        };
 6295
 6296        let load_word_completions = if !self.word_completions_enabled {
 6297            false
 6298        } else if requested_source
 6299            == Some(CompletionsMenuSource::Words {
 6300                ignore_threshold: true,
 6301            })
 6302        {
 6303            true
 6304        } else {
 6305            load_provider_completions
 6306                && completion_settings.words != WordsCompletionMode::Disabled
 6307                && (ignore_word_threshold || {
 6308                    let words_min_length = completion_settings.words_min_length;
 6309                    // check whether word has at least `words_min_length` characters
 6310                    let query_chars = query.iter().flat_map(|q| q.chars());
 6311                    query_chars.take(words_min_length).count() == words_min_length
 6312                })
 6313        };
 6314
 6315        let mut words = if load_word_completions {
 6316            cx.background_spawn({
 6317                let buffer_snapshot = buffer_snapshot.clone();
 6318                async move {
 6319                    buffer_snapshot.words_in_range(WordsQuery {
 6320                        fuzzy_contents: None,
 6321                        range: word_search_range,
 6322                        skip_digits,
 6323                    })
 6324                }
 6325            })
 6326        } else {
 6327            Task::ready(BTreeMap::default())
 6328        };
 6329
 6330        let snippets = if let Some(provider) = &provider
 6331            && provider.show_snippets()
 6332            && let Some(project) = self.project()
 6333        {
 6334            let char_classifier = buffer_snapshot
 6335                .char_classifier_at(buffer_position)
 6336                .scope_context(Some(CharScopeContext::Completion));
 6337            project.update(cx, |project, cx| {
 6338                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6339            })
 6340        } else {
 6341            Task::ready(Ok(CompletionResponse {
 6342                completions: Vec::new(),
 6343                display_options: Default::default(),
 6344                is_incomplete: false,
 6345            }))
 6346        };
 6347
 6348        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6349
 6350        let id = post_inc(&mut self.next_completion_id);
 6351        let task = cx.spawn_in(window, async move |editor, cx| {
 6352            let Ok(()) = editor.update(cx, |this, _| {
 6353                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6354            }) else {
 6355                return;
 6356            };
 6357
 6358            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6359            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6360            let mut completions = Vec::new();
 6361            let mut is_incomplete = false;
 6362            let mut display_options: Option<CompletionDisplayOptions> = None;
 6363            if let Some(provider_responses) = provider_responses.await.log_err()
 6364                && !provider_responses.is_empty()
 6365            {
 6366                for response in provider_responses {
 6367                    completions.extend(response.completions);
 6368                    is_incomplete = is_incomplete || response.is_incomplete;
 6369                    match display_options.as_mut() {
 6370                        None => {
 6371                            display_options = Some(response.display_options);
 6372                        }
 6373                        Some(options) => options.merge(&response.display_options),
 6374                    }
 6375                }
 6376                if completion_settings.words == WordsCompletionMode::Fallback {
 6377                    words = Task::ready(BTreeMap::default());
 6378                }
 6379            }
 6380            let display_options = display_options.unwrap_or_default();
 6381
 6382            let mut words = words.await;
 6383            if let Some(word_to_exclude) = &word_to_exclude {
 6384                words.remove(word_to_exclude);
 6385            }
 6386            for lsp_completion in &completions {
 6387                words.remove(&lsp_completion.new_text);
 6388            }
 6389            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6390                replace_range: word_replace_range.clone(),
 6391                new_text: word.clone(),
 6392                label: CodeLabel::plain(word, None),
 6393                match_start: None,
 6394                snippet_deduplication_key: None,
 6395                icon_path: None,
 6396                documentation: None,
 6397                source: CompletionSource::BufferWord {
 6398                    word_range,
 6399                    resolved: false,
 6400                },
 6401                insert_text_mode: Some(InsertTextMode::AS_IS),
 6402                confirm: None,
 6403            }));
 6404
 6405            completions.extend(
 6406                snippets
 6407                    .await
 6408                    .into_iter()
 6409                    .flat_map(|response| response.completions),
 6410            );
 6411
 6412            let menu = if completions.is_empty() {
 6413                None
 6414            } else {
 6415                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6416                    let languages = editor
 6417                        .workspace
 6418                        .as_ref()
 6419                        .and_then(|(workspace, _)| workspace.upgrade())
 6420                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6421                    let menu = CompletionsMenu::new(
 6422                        id,
 6423                        requested_source.unwrap_or(if load_provider_completions {
 6424                            CompletionsMenuSource::Normal
 6425                        } else {
 6426                            CompletionsMenuSource::SnippetsOnly
 6427                        }),
 6428                        sort_completions,
 6429                        show_completion_documentation,
 6430                        position,
 6431                        query.clone(),
 6432                        is_incomplete,
 6433                        buffer.clone(),
 6434                        completions.into(),
 6435                        editor
 6436                            .context_menu()
 6437                            .borrow_mut()
 6438                            .as_ref()
 6439                            .map(|menu| menu.primary_scroll_handle()),
 6440                        display_options,
 6441                        snippet_sort_order,
 6442                        languages,
 6443                        language,
 6444                        cx,
 6445                    );
 6446
 6447                    let query = if filter_completions { query } else { None };
 6448                    let matches_task = menu.do_async_filtering(
 6449                        query.unwrap_or_default(),
 6450                        buffer_position,
 6451                        &buffer,
 6452                        cx,
 6453                    );
 6454                    (menu, matches_task)
 6455                }) else {
 6456                    return;
 6457                };
 6458
 6459                let matches = matches_task.await;
 6460
 6461                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6462                    // Newer menu already set, so exit.
 6463                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6464                        editor.context_menu.borrow().as_ref()
 6465                        && prev_menu.id > id
 6466                    {
 6467                        return;
 6468                    };
 6469
 6470                    // Only valid to take prev_menu because either the new menu is immediately set
 6471                    // below, or the menu is hidden.
 6472                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6473                        editor.context_menu.borrow_mut().take()
 6474                    {
 6475                        let position_matches =
 6476                            if prev_menu.initial_position == menu.initial_position {
 6477                                true
 6478                            } else {
 6479                                let snapshot = editor.buffer.read(cx).read(cx);
 6480                                prev_menu.initial_position.to_offset(&snapshot)
 6481                                    == menu.initial_position.to_offset(&snapshot)
 6482                            };
 6483                        if position_matches {
 6484                            // Preserve markdown cache before `set_filter_results` because it will
 6485                            // try to populate the documentation cache.
 6486                            menu.preserve_markdown_cache(prev_menu);
 6487                        }
 6488                    };
 6489
 6490                    menu.set_filter_results(matches, provider, window, cx);
 6491                }) else {
 6492                    return;
 6493                };
 6494
 6495                menu.visible().then_some(menu)
 6496            };
 6497
 6498            editor
 6499                .update_in(cx, |editor, window, cx| {
 6500                    if editor.focus_handle.is_focused(window)
 6501                        && let Some(menu) = menu
 6502                    {
 6503                        *editor.context_menu.borrow_mut() =
 6504                            Some(CodeContextMenu::Completions(menu));
 6505
 6506                        crate::hover_popover::hide_hover(editor, cx);
 6507                        if editor.show_edit_predictions_in_menu() {
 6508                            editor.update_visible_edit_prediction(window, cx);
 6509                        } else {
 6510                            editor
 6511                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6512                        }
 6513
 6514                        cx.notify();
 6515                        return;
 6516                    }
 6517
 6518                    if editor.completion_tasks.len() <= 1 {
 6519                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6520                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6521                        // If it was already hidden and we don't show edit predictions in the menu,
 6522                        // we should also show the edit prediction when available.
 6523                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6524                            editor.update_visible_edit_prediction(window, cx);
 6525                        }
 6526                    }
 6527                })
 6528                .ok();
 6529        });
 6530
 6531        self.completion_tasks.push((id, task));
 6532    }
 6533
 6534    #[cfg(any(test, feature = "test-support"))]
 6535    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6536        let menu = self.context_menu.borrow();
 6537        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6538            let completions = menu.completions.borrow();
 6539            Some(completions.to_vec())
 6540        } else {
 6541            None
 6542        }
 6543    }
 6544
 6545    pub fn with_completions_menu_matching_id<R>(
 6546        &self,
 6547        id: CompletionId,
 6548        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6549    ) -> R {
 6550        let mut context_menu = self.context_menu.borrow_mut();
 6551        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6552            return f(None);
 6553        };
 6554        if completions_menu.id != id {
 6555            return f(None);
 6556        }
 6557        f(Some(completions_menu))
 6558    }
 6559
 6560    pub fn confirm_completion(
 6561        &mut self,
 6562        action: &ConfirmCompletion,
 6563        window: &mut Window,
 6564        cx: &mut Context<Self>,
 6565    ) -> Option<Task<Result<()>>> {
 6566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6567        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6568    }
 6569
 6570    pub fn confirm_completion_insert(
 6571        &mut self,
 6572        _: &ConfirmCompletionInsert,
 6573        window: &mut Window,
 6574        cx: &mut Context<Self>,
 6575    ) -> Option<Task<Result<()>>> {
 6576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6577        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6578    }
 6579
 6580    pub fn confirm_completion_replace(
 6581        &mut self,
 6582        _: &ConfirmCompletionReplace,
 6583        window: &mut Window,
 6584        cx: &mut Context<Self>,
 6585    ) -> Option<Task<Result<()>>> {
 6586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6587        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6588    }
 6589
 6590    pub fn compose_completion(
 6591        &mut self,
 6592        action: &ComposeCompletion,
 6593        window: &mut Window,
 6594        cx: &mut Context<Self>,
 6595    ) -> Option<Task<Result<()>>> {
 6596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6597        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6598    }
 6599
 6600    fn do_completion(
 6601        &mut self,
 6602        item_ix: Option<usize>,
 6603        intent: CompletionIntent,
 6604        window: &mut Window,
 6605        cx: &mut Context<Editor>,
 6606    ) -> Option<Task<Result<()>>> {
 6607        use language::ToOffset as _;
 6608
 6609        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6610        else {
 6611            return None;
 6612        };
 6613
 6614        let candidate_id = {
 6615            let entries = completions_menu.entries.borrow();
 6616            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6617            if self.show_edit_predictions_in_menu() {
 6618                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6619            }
 6620            mat.candidate_id
 6621        };
 6622
 6623        let completion = completions_menu
 6624            .completions
 6625            .borrow()
 6626            .get(candidate_id)?
 6627            .clone();
 6628        cx.stop_propagation();
 6629
 6630        let buffer_handle = completions_menu.buffer.clone();
 6631        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6632        let (initial_position, _) =
 6633            multibuffer_snapshot.anchor_to_buffer_anchor(completions_menu.initial_position)?;
 6634
 6635        let CompletionEdit {
 6636            new_text,
 6637            snippet,
 6638            replace_range,
 6639        } = process_completion_for_edit(&completion, intent, &buffer_handle, &initial_position, cx);
 6640
 6641        let buffer = buffer_handle.read(cx).snapshot();
 6642        let newest_selection = self.selections.newest_anchor();
 6643
 6644        let Some(replace_range_multibuffer) =
 6645            multibuffer_snapshot.buffer_anchor_range_to_anchor_range(replace_range.clone())
 6646        else {
 6647            return None;
 6648        };
 6649
 6650        let Some((buffer_snapshot, newest_range_buffer)) =
 6651            multibuffer_snapshot.anchor_range_to_buffer_anchor_range(newest_selection.range())
 6652        else {
 6653            return None;
 6654        };
 6655
 6656        let old_text = buffer
 6657            .text_for_range(replace_range.clone())
 6658            .collect::<String>();
 6659        let lookbehind = newest_range_buffer
 6660            .start
 6661            .to_offset(buffer_snapshot)
 6662            .saturating_sub(replace_range.start.to_offset(&buffer_snapshot));
 6663        let lookahead = replace_range
 6664            .end
 6665            .to_offset(&buffer_snapshot)
 6666            .saturating_sub(newest_range_buffer.end.to_offset(&buffer));
 6667        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6668        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6669
 6670        let selections = self
 6671            .selections
 6672            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6673        let mut ranges = Vec::new();
 6674        let mut all_commit_ranges = Vec::new();
 6675        let mut linked_edits = LinkedEdits::new();
 6676
 6677        let text: Arc<str> = new_text.clone().into();
 6678        for selection in &selections {
 6679            let range = if selection.id == newest_selection.id {
 6680                replace_range_multibuffer.clone()
 6681            } else {
 6682                let mut range = selection.range();
 6683
 6684                // if prefix is present, don't duplicate it
 6685                if multibuffer_snapshot
 6686                    .contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix)
 6687                {
 6688                    range.start = range.start.saturating_sub_usize(lookbehind);
 6689
 6690                    // if suffix is also present, mimic the newest cursor and replace it
 6691                    if selection.id != newest_selection.id
 6692                        && multibuffer_snapshot.contains_str_at(range.end, suffix)
 6693                    {
 6694                        range.end += lookahead;
 6695                    }
 6696                }
 6697                range.to_anchors(&multibuffer_snapshot)
 6698            };
 6699
 6700            ranges.push(range.clone());
 6701
 6702            let start_anchor = multibuffer_snapshot.anchor_before(range.start);
 6703            let end_anchor = multibuffer_snapshot.anchor_after(range.end);
 6704
 6705            if let Some((buffer_snapshot_2, anchor_range)) =
 6706                multibuffer_snapshot.anchor_range_to_buffer_anchor_range(start_anchor..end_anchor)
 6707                && buffer_snapshot_2.remote_id() == buffer_snapshot.remote_id()
 6708            {
 6709                all_commit_ranges.push(anchor_range.clone());
 6710                if !self.linked_edit_ranges.is_empty() {
 6711                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 6712                }
 6713            }
 6714        }
 6715
 6716        let common_prefix_len = old_text
 6717            .chars()
 6718            .zip(new_text.chars())
 6719            .take_while(|(a, b)| a == b)
 6720            .map(|(a, _)| a.len_utf8())
 6721            .sum::<usize>();
 6722
 6723        cx.emit(EditorEvent::InputHandled {
 6724            utf16_range_to_replace: None,
 6725            text: new_text[common_prefix_len..].into(),
 6726        });
 6727
 6728        let tx_id = self.transact(window, cx, |editor, window, cx| {
 6729            if let Some(mut snippet) = snippet {
 6730                snippet.text = new_text.to_string();
 6731                let offset_ranges = ranges
 6732                    .iter()
 6733                    .map(|range| range.to_offset(&multibuffer_snapshot))
 6734                    .collect::<Vec<_>>();
 6735                editor
 6736                    .insert_snippet(&offset_ranges, snippet, window, cx)
 6737                    .log_err();
 6738            } else {
 6739                editor.buffer.update(cx, |multi_buffer, cx| {
 6740                    let auto_indent = match completion.insert_text_mode {
 6741                        Some(InsertTextMode::AS_IS) => None,
 6742                        _ => editor.autoindent_mode.clone(),
 6743                    };
 6744                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6745                    multi_buffer.edit(edits, auto_indent, cx);
 6746                });
 6747            }
 6748            linked_edits.apply(cx);
 6749            editor.refresh_edit_prediction(true, false, window, cx);
 6750        });
 6751        self.invalidate_autoclose_regions(
 6752            &self.selections.disjoint_anchors_arc(),
 6753            &multibuffer_snapshot,
 6754        );
 6755
 6756        let show_new_completions_on_confirm = completion
 6757            .confirm
 6758            .as_ref()
 6759            .is_some_and(|confirm| confirm(intent, window, cx));
 6760        if show_new_completions_on_confirm {
 6761            self.open_or_update_completions_menu(None, None, false, window, cx);
 6762        }
 6763
 6764        let provider = self.completion_provider.as_ref()?;
 6765
 6766        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6767        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6768            let CompletionSource::Lsp {
 6769                lsp_completion,
 6770                server_id,
 6771                ..
 6772            } = &completion.source
 6773            else {
 6774                return None;
 6775            };
 6776            let lsp_command = lsp_completion.command.as_ref()?;
 6777            let available_commands = lsp_store
 6778                .read(cx)
 6779                .lsp_server_capabilities
 6780                .get(server_id)
 6781                .and_then(|server_capabilities| {
 6782                    server_capabilities
 6783                        .execute_command_provider
 6784                        .as_ref()
 6785                        .map(|options| options.commands.as_slice())
 6786                })?;
 6787            if available_commands.contains(&lsp_command.command) {
 6788                Some(CodeAction {
 6789                    server_id: *server_id,
 6790                    range: language::Anchor::min_min_range_for_buffer(buffer.remote_id()),
 6791                    lsp_action: LspAction::Command(lsp_command.clone()),
 6792                    resolved: false,
 6793                })
 6794            } else {
 6795                None
 6796            }
 6797        });
 6798
 6799        drop(completion);
 6800        let apply_edits = provider.apply_additional_edits_for_completion(
 6801            buffer_handle.clone(),
 6802            completions_menu.completions.clone(),
 6803            candidate_id,
 6804            true,
 6805            all_commit_ranges,
 6806            cx,
 6807        );
 6808
 6809        let editor_settings = EditorSettings::get_global(cx);
 6810        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6811            // After the code completion is finished, users often want to know what signatures are needed.
 6812            // so we should automatically call signature_help
 6813            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6814        }
 6815
 6816        Some(cx.spawn_in(window, async move |editor, cx| {
 6817            let additional_edits_tx = apply_edits.await?;
 6818
 6819            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6820                let title = command.lsp_action.title().to_owned();
 6821                let project_transaction = lsp_store
 6822                    .update(cx, |lsp_store, cx| {
 6823                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6824                    })
 6825                    .await
 6826                    .context("applying post-completion command")?;
 6827                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6828                    Self::open_project_transaction(
 6829                        &editor,
 6830                        workspace.downgrade(),
 6831                        project_transaction,
 6832                        title,
 6833                        cx,
 6834                    )
 6835                    .await?;
 6836                }
 6837            }
 6838
 6839            if let Some(tx_id) = tx_id
 6840                && let Some(additional_edits_tx) = additional_edits_tx
 6841            {
 6842                editor
 6843                    .update(cx, |editor, cx| {
 6844                        editor.buffer.update(cx, |buffer, cx| {
 6845                            buffer.merge_transactions(additional_edits_tx.id, tx_id, cx)
 6846                        });
 6847                    })
 6848                    .context("merge transactions")?;
 6849            }
 6850
 6851            Ok(())
 6852        }))
 6853    }
 6854
 6855    pub fn toggle_code_actions(
 6856        &mut self,
 6857        action: &ToggleCodeActions,
 6858        window: &mut Window,
 6859        cx: &mut Context<Self>,
 6860    ) {
 6861        let quick_launch = action.quick_launch;
 6862        let mut context_menu = self.context_menu.borrow_mut();
 6863        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6864            if code_actions.deployed_from == action.deployed_from {
 6865                // Toggle if we're selecting the same one
 6866                *context_menu = None;
 6867                cx.notify();
 6868                return;
 6869            } else {
 6870                // Otherwise, clear it and start a new one
 6871                *context_menu = None;
 6872                cx.notify();
 6873            }
 6874        }
 6875        drop(context_menu);
 6876        let snapshot = self.snapshot(window, cx);
 6877        let deployed_from = action.deployed_from.clone();
 6878        let action = action.clone();
 6879        self.completion_tasks.clear();
 6880        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6881
 6882        let multibuffer_point = match &action.deployed_from {
 6883            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6884                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6885            }
 6886            _ => self
 6887                .selections
 6888                .newest::<Point>(&snapshot.display_snapshot)
 6889                .head(),
 6890        };
 6891        let Some((buffer, buffer_row)) = snapshot
 6892            .buffer_snapshot()
 6893            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6894            .and_then(|(buffer_snapshot, range)| {
 6895                self.buffer()
 6896                    .read(cx)
 6897                    .buffer(buffer_snapshot.remote_id())
 6898                    .map(|buffer| (buffer, range.start.row))
 6899            })
 6900        else {
 6901            return;
 6902        };
 6903        let buffer_id = buffer.read(cx).remote_id();
 6904        let tasks = self
 6905            .runnables
 6906            .runnables((buffer_id, buffer_row))
 6907            .map(|t| Arc::new(t.to_owned()));
 6908
 6909        if !self.focus_handle.is_focused(window) {
 6910            return;
 6911        }
 6912        let project = self.project.clone();
 6913
 6914        let code_actions_task = match deployed_from {
 6915            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6916            _ => self.code_actions(buffer_row, window, cx),
 6917        };
 6918
 6919        let runnable_task = match deployed_from {
 6920            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6921            _ => {
 6922                let mut task_context_task = Task::ready(None);
 6923                if let Some(tasks) = &tasks
 6924                    && let Some(project) = project
 6925                {
 6926                    task_context_task =
 6927                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6928                }
 6929
 6930                cx.spawn_in(window, {
 6931                    let buffer = buffer.clone();
 6932                    async move |editor, cx| {
 6933                        let task_context = task_context_task.await;
 6934
 6935                        let resolved_tasks =
 6936                            tasks
 6937                                .zip(task_context.clone())
 6938                                .map(|(tasks, task_context)| ResolvedTasks {
 6939                                    templates: tasks.resolve(&task_context).collect(),
 6940                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6941                                        multibuffer_point.row,
 6942                                        tasks.column,
 6943                                    )),
 6944                                });
 6945                        let debug_scenarios = editor
 6946                            .update(cx, |editor, cx| {
 6947                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6948                            })?
 6949                            .await;
 6950                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6951                    }
 6952                })
 6953            }
 6954        };
 6955
 6956        cx.spawn_in(window, async move |editor, cx| {
 6957            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6958            let code_actions = code_actions_task.await;
 6959            let spawn_straight_away = quick_launch
 6960                && resolved_tasks
 6961                    .as_ref()
 6962                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6963                && code_actions
 6964                    .as_ref()
 6965                    .is_none_or(|actions| actions.is_empty())
 6966                && debug_scenarios.is_empty();
 6967
 6968            editor.update_in(cx, |editor, window, cx| {
 6969                crate::hover_popover::hide_hover(editor, cx);
 6970                let actions = CodeActionContents::new(
 6971                    resolved_tasks,
 6972                    code_actions,
 6973                    debug_scenarios,
 6974                    task_context.unwrap_or_default(),
 6975                );
 6976
 6977                // Don't show the menu if there are no actions available
 6978                if actions.is_empty() {
 6979                    cx.notify();
 6980                    return Task::ready(Ok(()));
 6981                }
 6982
 6983                *editor.context_menu.borrow_mut() =
 6984                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6985                        buffer,
 6986                        actions,
 6987                        selected_item: Default::default(),
 6988                        scroll_handle: UniformListScrollHandle::default(),
 6989                        deployed_from,
 6990                    }));
 6991                cx.notify();
 6992                if spawn_straight_away
 6993                    && let Some(task) = editor.confirm_code_action(
 6994                        &ConfirmCodeAction { item_ix: Some(0) },
 6995                        window,
 6996                        cx,
 6997                    )
 6998                {
 6999                    return task;
 7000                }
 7001
 7002                Task::ready(Ok(()))
 7003            })
 7004        })
 7005        .detach_and_log_err(cx);
 7006    }
 7007
 7008    fn debug_scenarios(
 7009        &mut self,
 7010        resolved_tasks: &Option<ResolvedTasks>,
 7011        buffer: &Entity<Buffer>,
 7012        cx: &mut App,
 7013    ) -> Task<Vec<task::DebugScenario>> {
 7014        maybe!({
 7015            let project = self.project()?;
 7016            let dap_store = project.read(cx).dap_store();
 7017            let mut scenarios = vec![];
 7018            let resolved_tasks = resolved_tasks.as_ref()?;
 7019            let buffer = buffer.read(cx);
 7020            let language = buffer.language()?;
 7021            let debug_adapter = LanguageSettings::for_buffer(&buffer, cx)
 7022                .debuggers
 7023                .first()
 7024                .map(SharedString::from)
 7025                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 7026
 7027            dap_store.update(cx, |dap_store, cx| {
 7028                for (_, task) in &resolved_tasks.templates {
 7029                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 7030                        task.original_task().clone(),
 7031                        debug_adapter.clone().into(),
 7032                        task.display_label().to_owned().into(),
 7033                        cx,
 7034                    );
 7035                    scenarios.push(maybe_scenario);
 7036                }
 7037            });
 7038            Some(cx.background_spawn(async move {
 7039                futures::future::join_all(scenarios)
 7040                    .await
 7041                    .into_iter()
 7042                    .flatten()
 7043                    .collect::<Vec<_>>()
 7044            }))
 7045        })
 7046        .unwrap_or_else(|| Task::ready(vec![]))
 7047    }
 7048
 7049    fn code_actions(
 7050        &mut self,
 7051        buffer_row: u32,
 7052        window: &mut Window,
 7053        cx: &mut Context<Self>,
 7054    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 7055        let mut task = self.code_actions_task.take();
 7056        cx.spawn_in(window, async move |editor, cx| {
 7057            while let Some(prev_task) = task {
 7058                prev_task.await.log_err();
 7059                task = editor
 7060                    .update(cx, |this, _| this.code_actions_task.take())
 7061                    .ok()?;
 7062            }
 7063
 7064            editor
 7065                .update(cx, |editor, cx| {
 7066                    editor
 7067                        .available_code_actions
 7068                        .clone()
 7069                        .and_then(|(location, code_actions)| {
 7070                            let snapshot = location.buffer.read(cx).snapshot();
 7071                            let point_range = location.range.to_point(&snapshot);
 7072                            let point_range = point_range.start.row..=point_range.end.row;
 7073                            if point_range.contains(&buffer_row) {
 7074                                Some(code_actions)
 7075                            } else {
 7076                                None
 7077                            }
 7078                        })
 7079                })
 7080                .ok()
 7081                .flatten()
 7082        })
 7083    }
 7084
 7085    pub fn confirm_code_action(
 7086        &mut self,
 7087        action: &ConfirmCodeAction,
 7088        window: &mut Window,
 7089        cx: &mut Context<Self>,
 7090    ) -> Option<Task<Result<()>>> {
 7091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7092
 7093        let actions_menu =
 7094            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7095                menu
 7096            } else {
 7097                return None;
 7098            };
 7099
 7100        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7101        let action = actions_menu.actions.get(action_ix)?;
 7102        let title = action.label();
 7103        let buffer = actions_menu.buffer;
 7104        let workspace = self.workspace()?;
 7105
 7106        match action {
 7107            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7108                workspace.update(cx, |workspace, cx| {
 7109                    workspace.schedule_resolved_task(
 7110                        task_source_kind,
 7111                        resolved_task,
 7112                        false,
 7113                        window,
 7114                        cx,
 7115                    );
 7116
 7117                    Some(Task::ready(Ok(())))
 7118                })
 7119            }
 7120            CodeActionsItem::CodeAction { action, provider } => {
 7121                let apply_code_action =
 7122                    provider.apply_code_action(buffer, action, true, window, cx);
 7123                let workspace = workspace.downgrade();
 7124                Some(cx.spawn_in(window, async move |editor, cx| {
 7125                    let project_transaction = apply_code_action.await?;
 7126                    Self::open_project_transaction(
 7127                        &editor,
 7128                        workspace,
 7129                        project_transaction,
 7130                        title,
 7131                        cx,
 7132                    )
 7133                    .await
 7134                }))
 7135            }
 7136            CodeActionsItem::DebugScenario(scenario) => {
 7137                let context = actions_menu.actions.context.into();
 7138
 7139                workspace.update(cx, |workspace, cx| {
 7140                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7141                    workspace.start_debug_session(
 7142                        scenario,
 7143                        context,
 7144                        Some(buffer),
 7145                        None,
 7146                        window,
 7147                        cx,
 7148                    );
 7149                });
 7150                Some(Task::ready(Ok(())))
 7151            }
 7152        }
 7153    }
 7154
 7155    fn open_transaction_for_hidden_buffers(
 7156        workspace: Entity<Workspace>,
 7157        transaction: ProjectTransaction,
 7158        title: String,
 7159        window: &mut Window,
 7160        cx: &mut Context<Self>,
 7161    ) {
 7162        if transaction.0.is_empty() {
 7163            return;
 7164        }
 7165
 7166        let edited_buffers_already_open = {
 7167            let other_editors: Vec<Entity<Editor>> = workspace
 7168                .read(cx)
 7169                .panes()
 7170                .iter()
 7171                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7172                .filter(|editor| editor.entity_id() != cx.entity_id())
 7173                .collect();
 7174
 7175            transaction.0.keys().all(|buffer| {
 7176                other_editors.iter().any(|editor| {
 7177                    let multi_buffer = editor.read(cx).buffer();
 7178                    multi_buffer.read(cx).is_singleton()
 7179                        && multi_buffer
 7180                            .read(cx)
 7181                            .as_singleton()
 7182                            .map_or(false, |singleton| {
 7183                                singleton.entity_id() == buffer.entity_id()
 7184                            })
 7185                })
 7186            })
 7187        };
 7188        if !edited_buffers_already_open {
 7189            let workspace = workspace.downgrade();
 7190            cx.defer_in(window, move |_, window, cx| {
 7191                cx.spawn_in(window, async move |editor, cx| {
 7192                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7193                        .await
 7194                        .ok()
 7195                })
 7196                .detach();
 7197            });
 7198        }
 7199    }
 7200
 7201    pub async fn open_project_transaction(
 7202        editor: &WeakEntity<Editor>,
 7203        workspace: WeakEntity<Workspace>,
 7204        transaction: ProjectTransaction,
 7205        title: String,
 7206        cx: &mut AsyncWindowContext,
 7207    ) -> Result<()> {
 7208        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7209        cx.update(|_, cx| {
 7210            entries.sort_unstable_by_key(|(buffer, _)| {
 7211                buffer.read(cx).file().map(|f| f.path().clone())
 7212            });
 7213        })?;
 7214        if entries.is_empty() {
 7215            return Ok(());
 7216        }
 7217
 7218        // If the project transaction's edits are all contained within this editor, then
 7219        // avoid opening a new editor to display them.
 7220
 7221        if let [(buffer, transaction)] = &*entries {
 7222            let cursor_excerpt = editor.update(cx, |editor, cx| {
 7223                let snapshot = editor.buffer().read(cx).snapshot(cx);
 7224                let head = editor.selections.newest_anchor().head();
 7225                let (buffer_snapshot, excerpt_range) = snapshot.excerpt_containing(head..head)?;
 7226                if buffer_snapshot.remote_id() != buffer.read(cx).remote_id() {
 7227                    return None;
 7228                }
 7229                Some(excerpt_range)
 7230            })?;
 7231
 7232            if let Some(excerpt_range) = cursor_excerpt {
 7233                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7234                    let excerpt_range = excerpt_range.context.to_offset(buffer);
 7235                    buffer
 7236                        .edited_ranges_for_transaction::<usize>(transaction)
 7237                        .all(|range| {
 7238                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7239                        })
 7240                });
 7241
 7242                if all_edits_within_excerpt {
 7243                    return Ok(());
 7244                }
 7245            }
 7246        }
 7247
 7248        let mut ranges_to_highlight = Vec::new();
 7249        let excerpt_buffer = cx.new(|cx| {
 7250            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7251            for (buffer_handle, transaction) in &entries {
 7252                let edited_ranges = buffer_handle
 7253                    .read(cx)
 7254                    .edited_ranges_for_transaction::<Point>(transaction)
 7255                    .collect::<Vec<_>>();
 7256                multibuffer.set_excerpts_for_path(
 7257                    PathKey::for_buffer(buffer_handle, cx),
 7258                    buffer_handle.clone(),
 7259                    edited_ranges.clone(),
 7260                    multibuffer_context_lines(cx),
 7261                    cx,
 7262                );
 7263                let snapshot = multibuffer.snapshot(cx);
 7264                let buffer_snapshot = buffer_handle.read(cx).snapshot();
 7265                ranges_to_highlight.extend(edited_ranges.into_iter().filter_map(|range| {
 7266                    let text_range = buffer_snapshot.anchor_range_inside(range);
 7267                    let start = snapshot.anchor_in_buffer(text_range.start)?;
 7268                    let end = snapshot.anchor_in_buffer(text_range.end)?;
 7269                    Some(start..end)
 7270                }));
 7271            }
 7272            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7273            multibuffer
 7274        });
 7275
 7276        workspace.update_in(cx, |workspace, window, cx| {
 7277            let project = workspace.project().clone();
 7278            let editor =
 7279                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7280            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7281            editor.update(cx, |editor, cx| {
 7282                editor.highlight_background(
 7283                    HighlightKey::Editor,
 7284                    &ranges_to_highlight,
 7285                    |_, theme| theme.colors().editor_highlighted_line_background,
 7286                    cx,
 7287                );
 7288            });
 7289        })?;
 7290
 7291        Ok(())
 7292    }
 7293
 7294    pub fn clear_code_action_providers(&mut self) {
 7295        self.code_action_providers.clear();
 7296        self.available_code_actions.take();
 7297    }
 7298
 7299    pub fn add_code_action_provider(
 7300        &mut self,
 7301        provider: Rc<dyn CodeActionProvider>,
 7302        window: &mut Window,
 7303        cx: &mut Context<Self>,
 7304    ) {
 7305        if self
 7306            .code_action_providers
 7307            .iter()
 7308            .any(|existing_provider| existing_provider.id() == provider.id())
 7309        {
 7310            return;
 7311        }
 7312
 7313        self.code_action_providers.push(provider);
 7314        self.refresh_code_actions(window, cx);
 7315    }
 7316
 7317    pub fn remove_code_action_provider(
 7318        &mut self,
 7319        id: Arc<str>,
 7320        window: &mut Window,
 7321        cx: &mut Context<Self>,
 7322    ) {
 7323        self.code_action_providers
 7324            .retain(|provider| provider.id() != id);
 7325        self.refresh_code_actions(window, cx);
 7326    }
 7327
 7328    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7329        !self.code_action_providers.is_empty()
 7330            && EditorSettings::get_global(cx).toolbar.code_actions
 7331    }
 7332
 7333    pub fn has_available_code_actions(&self) -> bool {
 7334        self.available_code_actions
 7335            .as_ref()
 7336            .is_some_and(|(_, actions)| !actions.is_empty())
 7337    }
 7338
 7339    fn render_inline_code_actions(
 7340        &self,
 7341        icon_size: ui::IconSize,
 7342        display_row: DisplayRow,
 7343        is_active: bool,
 7344        cx: &mut Context<Self>,
 7345    ) -> AnyElement {
 7346        let show_tooltip = !self.context_menu_visible();
 7347        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7348            .icon_size(icon_size)
 7349            .shape(ui::IconButtonShape::Square)
 7350            .icon_color(ui::Color::Hidden)
 7351            .toggle_state(is_active)
 7352            .when(show_tooltip, |this| {
 7353                this.tooltip({
 7354                    let focus_handle = self.focus_handle.clone();
 7355                    move |_window, cx| {
 7356                        Tooltip::for_action_in(
 7357                            "Toggle Code Actions",
 7358                            &ToggleCodeActions {
 7359                                deployed_from: None,
 7360                                quick_launch: false,
 7361                            },
 7362                            &focus_handle,
 7363                            cx,
 7364                        )
 7365                    }
 7366                })
 7367            })
 7368            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7369                window.focus(&editor.focus_handle(cx), cx);
 7370                editor.toggle_code_actions(
 7371                    &crate::actions::ToggleCodeActions {
 7372                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7373                            display_row,
 7374                        )),
 7375                        quick_launch: false,
 7376                    },
 7377                    window,
 7378                    cx,
 7379                );
 7380            }))
 7381            .into_any_element()
 7382    }
 7383
 7384    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7385        &self.context_menu
 7386    }
 7387
 7388    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7389        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7390            cx.background_executor()
 7391                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7392                .await;
 7393
 7394            let (start_buffer, start, _, end, _newest_selection) = this
 7395                .update(cx, |this, cx| {
 7396                    let newest_selection = this.selections.newest_anchor().clone();
 7397                    if newest_selection.head().diff_base_anchor().is_some() {
 7398                        return None;
 7399                    }
 7400                    let display_snapshot = this.display_snapshot(cx);
 7401                    let newest_selection_adjusted =
 7402                        this.selections.newest_adjusted(&display_snapshot);
 7403                    let buffer = this.buffer.read(cx);
 7404
 7405                    let (start_buffer, start) =
 7406                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7407                    let (end_buffer, end) =
 7408                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7409
 7410                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7411                })?
 7412                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7413                .context(
 7414                    "Expected selection to lie in a single buffer when refreshing code actions",
 7415                )?;
 7416            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7417                let providers = this.code_action_providers.clone();
 7418                let tasks = this
 7419                    .code_action_providers
 7420                    .iter()
 7421                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7422                    .collect::<Vec<_>>();
 7423                (providers, tasks)
 7424            })?;
 7425
 7426            let mut actions = Vec::new();
 7427            for (provider, provider_actions) in
 7428                providers.into_iter().zip(future::join_all(tasks).await)
 7429            {
 7430                if let Some(provider_actions) = provider_actions.log_err() {
 7431                    actions.extend(provider_actions.into_iter().map(|action| {
 7432                        AvailableCodeAction {
 7433                            action,
 7434                            provider: provider.clone(),
 7435                        }
 7436                    }));
 7437                }
 7438            }
 7439
 7440            this.update(cx, |this, cx| {
 7441                this.available_code_actions = if actions.is_empty() {
 7442                    None
 7443                } else {
 7444                    Some((
 7445                        Location {
 7446                            buffer: start_buffer,
 7447                            range: start..end,
 7448                        },
 7449                        actions.into(),
 7450                    ))
 7451                };
 7452                cx.notify();
 7453            })
 7454        }));
 7455    }
 7456
 7457    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7458        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7459            self.show_git_blame_inline = false;
 7460
 7461            self.show_git_blame_inline_delay_task =
 7462                Some(cx.spawn_in(window, async move |this, cx| {
 7463                    cx.background_executor().timer(delay).await;
 7464
 7465                    this.update(cx, |this, cx| {
 7466                        this.show_git_blame_inline = true;
 7467                        cx.notify();
 7468                    })
 7469                    .log_err();
 7470                }));
 7471        }
 7472    }
 7473
 7474    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7475        let snapshot = self.snapshot(window, cx);
 7476        let cursor = self
 7477            .selections
 7478            .newest::<Point>(&snapshot.display_snapshot)
 7479            .head();
 7480        let Some((buffer, point)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor) else {
 7481            return;
 7482        };
 7483
 7484        if self.blame.is_none() {
 7485            self.start_git_blame(true, window, cx);
 7486        }
 7487        let Some(blame) = self.blame.as_ref() else {
 7488            return;
 7489        };
 7490
 7491        let row_info = RowInfo {
 7492            buffer_id: Some(buffer.remote_id()),
 7493            buffer_row: Some(point.row),
 7494            ..Default::default()
 7495        };
 7496        let Some((buffer, blame_entry)) = blame
 7497            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7498            .flatten()
 7499        else {
 7500            return;
 7501        };
 7502
 7503        let anchor = self.selections.newest_anchor().head();
 7504        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7505        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7506            self.show_blame_popover(
 7507                buffer,
 7508                &blame_entry,
 7509                position + last_bounds.origin,
 7510                true,
 7511                cx,
 7512            );
 7513        };
 7514    }
 7515
 7516    fn show_blame_popover(
 7517        &mut self,
 7518        buffer: BufferId,
 7519        blame_entry: &BlameEntry,
 7520        position: gpui::Point<Pixels>,
 7521        ignore_timeout: bool,
 7522        cx: &mut Context<Self>,
 7523    ) {
 7524        if let Some(state) = &mut self.inline_blame_popover {
 7525            state.hide_task.take();
 7526        } else {
 7527            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7528            let blame_entry = blame_entry.clone();
 7529            let show_task = cx.spawn(async move |editor, cx| {
 7530                if !ignore_timeout {
 7531                    cx.background_executor()
 7532                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7533                        .await;
 7534                }
 7535                editor
 7536                    .update(cx, |editor, cx| {
 7537                        editor.inline_blame_popover_show_task.take();
 7538                        let Some(blame) = editor.blame.as_ref() else {
 7539                            return;
 7540                        };
 7541                        let blame = blame.read(cx);
 7542                        let details = blame.details_for_entry(buffer, &blame_entry);
 7543                        let markdown = cx.new(|cx| {
 7544                            Markdown::new(
 7545                                details
 7546                                    .as_ref()
 7547                                    .map(|message| message.message.clone())
 7548                                    .unwrap_or_default(),
 7549                                None,
 7550                                None,
 7551                                cx,
 7552                            )
 7553                        });
 7554                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7555                            position,
 7556                            hide_task: None,
 7557                            popover_bounds: None,
 7558                            popover_state: InlineBlamePopoverState {
 7559                                scroll_handle: ScrollHandle::new(),
 7560                                commit_message: details,
 7561                                markdown,
 7562                            },
 7563                            keyboard_grace: ignore_timeout,
 7564                        });
 7565                        cx.notify();
 7566                    })
 7567                    .ok();
 7568            });
 7569            self.inline_blame_popover_show_task = Some(show_task);
 7570        }
 7571    }
 7572
 7573    pub fn has_mouse_context_menu(&self) -> bool {
 7574        self.mouse_context_menu.is_some()
 7575    }
 7576
 7577    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7578        self.inline_blame_popover_show_task.take();
 7579        if let Some(state) = &mut self.inline_blame_popover {
 7580            let hide_task = cx.spawn(async move |editor, cx| {
 7581                if !ignore_timeout {
 7582                    cx.background_executor()
 7583                        .timer(std::time::Duration::from_millis(100))
 7584                        .await;
 7585                }
 7586                editor
 7587                    .update(cx, |editor, cx| {
 7588                        editor.inline_blame_popover.take();
 7589                        cx.notify();
 7590                    })
 7591                    .ok();
 7592            });
 7593            state.hide_task = Some(hide_task);
 7594            true
 7595        } else {
 7596            false
 7597        }
 7598    }
 7599
 7600    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7601        if self.pending_rename.is_some() {
 7602            return None;
 7603        }
 7604
 7605        let provider = self.semantics_provider.clone()?;
 7606        let buffer = self.buffer.read(cx);
 7607        let newest_selection = self.selections.newest_anchor().clone();
 7608        let cursor_position = newest_selection.head();
 7609        let (cursor_buffer, cursor_buffer_position) =
 7610            buffer.text_anchor_for_position(cursor_position, cx)?;
 7611        let (tail_buffer, tail_buffer_position) =
 7612            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7613        if cursor_buffer != tail_buffer {
 7614            return None;
 7615        }
 7616
 7617        let snapshot = cursor_buffer.read(cx).snapshot();
 7618        let word_ranges = cx.background_spawn(async move {
 7619            // this might look odd to put on the background thread, but
 7620            // `surrounding_word` can be quite expensive as it calls into
 7621            // tree-sitter language scopes
 7622            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7623            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7624            (start_word_range, end_word_range)
 7625        });
 7626
 7627        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7628        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7629            let (start_word_range, end_word_range) = word_ranges.await;
 7630            if start_word_range != end_word_range {
 7631                this.update(cx, |this, cx| {
 7632                    this.document_highlights_task.take();
 7633                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7634                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7635                })
 7636                .ok();
 7637                return;
 7638            }
 7639            cx.background_executor()
 7640                .timer(Duration::from_millis(debounce))
 7641                .await;
 7642
 7643            let highlights = if let Some(highlights) = cx.update(|cx| {
 7644                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7645            }) {
 7646                highlights.await.log_err()
 7647            } else {
 7648                None
 7649            };
 7650
 7651            if let Some(highlights) = highlights {
 7652                this.update(cx, |this, cx| {
 7653                    if this.pending_rename.is_some() {
 7654                        return;
 7655                    }
 7656
 7657                    let buffer = this.buffer.read(cx);
 7658                    if buffer
 7659                        .text_anchor_for_position(cursor_position, cx)
 7660                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7661                    {
 7662                        return;
 7663                    }
 7664
 7665                    let mut write_ranges = Vec::new();
 7666                    let mut read_ranges = Vec::new();
 7667                    let multibuffer_snapshot = buffer.snapshot(cx);
 7668                    for highlight in highlights {
 7669                        for range in
 7670                            multibuffer_snapshot.buffer_range_to_excerpt_ranges(highlight.range)
 7671                        {
 7672                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7673                                write_ranges.push(range);
 7674                            } else {
 7675                                read_ranges.push(range);
 7676                            }
 7677                        }
 7678                    }
 7679
 7680                    this.highlight_background(
 7681                        HighlightKey::DocumentHighlightRead,
 7682                        &read_ranges,
 7683                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7684                        cx,
 7685                    );
 7686                    this.highlight_background(
 7687                        HighlightKey::DocumentHighlightWrite,
 7688                        &write_ranges,
 7689                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7690                        cx,
 7691                    );
 7692                    cx.notify();
 7693                })
 7694                .log_err();
 7695            }
 7696        }));
 7697        None
 7698    }
 7699
 7700    fn prepare_highlight_query_from_selection(
 7701        &mut self,
 7702        snapshot: &DisplaySnapshot,
 7703        cx: &mut Context<Editor>,
 7704    ) -> Option<(String, Range<Anchor>)> {
 7705        if matches!(self.mode, EditorMode::SingleLine) {
 7706            return None;
 7707        }
 7708        if !self.use_selection_highlight || !EditorSettings::get_global(cx).selection_highlight {
 7709            return None;
 7710        }
 7711        if self.selections.count() != 1 || self.selections.line_mode() {
 7712            return None;
 7713        }
 7714        let selection = self.selections.newest::<Point>(&snapshot);
 7715        // If the selection spans multiple rows OR it is empty
 7716        if selection.start.row != selection.end.row
 7717            || selection.start.column == selection.end.column
 7718        {
 7719            return None;
 7720        }
 7721        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7722        let query = snapshot
 7723            .buffer_snapshot()
 7724            .text_for_range(selection_anchor_range.clone())
 7725            .collect::<String>();
 7726        if query.trim().is_empty() {
 7727            return None;
 7728        }
 7729        Some((query, selection_anchor_range))
 7730    }
 7731
 7732    #[ztracing::instrument(skip_all)]
 7733    fn update_selection_occurrence_highlights(
 7734        &mut self,
 7735        multi_buffer_snapshot: MultiBufferSnapshot,
 7736        query_text: String,
 7737        query_range: Range<Anchor>,
 7738        multi_buffer_range_to_query: Range<Point>,
 7739        use_debounce: bool,
 7740        window: &mut Window,
 7741        cx: &mut Context<Editor>,
 7742    ) -> Task<()> {
 7743        cx.spawn_in(window, async move |editor, cx| {
 7744            if use_debounce {
 7745                cx.background_executor()
 7746                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7747                    .await;
 7748            }
 7749            let match_task = cx.background_spawn(async move {
 7750                let buffer_ranges = multi_buffer_snapshot
 7751                    .range_to_buffer_ranges(
 7752                        multi_buffer_range_to_query.start..multi_buffer_range_to_query.end,
 7753                    )
 7754                    .into_iter()
 7755                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7756                let mut match_ranges = Vec::new();
 7757                let Ok(regex) = project::search::SearchQuery::text(
 7758                    query_text,
 7759                    false,
 7760                    false,
 7761                    false,
 7762                    Default::default(),
 7763                    Default::default(),
 7764                    false,
 7765                    None,
 7766                ) else {
 7767                    return Vec::default();
 7768                };
 7769                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7770                for (buffer_snapshot, search_range, _) in buffer_ranges {
 7771                    match_ranges.extend(
 7772                        regex
 7773                            .search(
 7774                                &buffer_snapshot,
 7775                                Some(search_range.start.0..search_range.end.0),
 7776                            )
 7777                            .await
 7778                            .into_iter()
 7779                            .filter_map(|match_range| {
 7780                                let match_start = buffer_snapshot
 7781                                    .anchor_after(search_range.start + match_range.start);
 7782                                let match_end = buffer_snapshot
 7783                                    .anchor_before(search_range.start + match_range.end);
 7784                                {
 7785                                    let range = multi_buffer_snapshot
 7786                                        .anchor_in_buffer(match_start)?
 7787                                        ..multi_buffer_snapshot.anchor_in_buffer(match_end)?;
 7788                                    Some(range).filter(|match_anchor_range| {
 7789                                        match_anchor_range != &query_range
 7790                                    })
 7791                                }
 7792                            }),
 7793                    );
 7794                }
 7795                match_ranges
 7796            });
 7797            let match_ranges = match_task.await;
 7798            editor
 7799                .update_in(cx, |editor, _, cx| {
 7800                    if use_debounce {
 7801                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7802                        editor.debounced_selection_highlight_complete = true;
 7803                    } else if editor.debounced_selection_highlight_complete {
 7804                        return;
 7805                    }
 7806                    if !match_ranges.is_empty() {
 7807                        editor.highlight_background(
 7808                            HighlightKey::SelectedTextHighlight,
 7809                            &match_ranges,
 7810                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7811                            cx,
 7812                        )
 7813                    }
 7814                })
 7815                .log_err();
 7816        })
 7817    }
 7818
 7819    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7820        struct NewlineFold;
 7821        let type_id = std::any::TypeId::of::<NewlineFold>();
 7822        if !self.mode.is_single_line() {
 7823            return;
 7824        }
 7825        let snapshot = self.snapshot(window, cx);
 7826        if snapshot.buffer_snapshot().max_point().row == 0 {
 7827            return;
 7828        }
 7829        let task = cx.background_spawn(async move {
 7830            let new_newlines = snapshot
 7831                .buffer_chars_at(MultiBufferOffset(0))
 7832                .filter_map(|(c, i)| {
 7833                    if c == '\n' {
 7834                        Some(
 7835                            snapshot.buffer_snapshot().anchor_after(i)
 7836                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7837                        )
 7838                    } else {
 7839                        None
 7840                    }
 7841                })
 7842                .collect::<Vec<_>>();
 7843            let existing_newlines = snapshot
 7844                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7845                .filter_map(|fold| {
 7846                    if fold.placeholder.type_tag == Some(type_id) {
 7847                        Some(fold.range.start..fold.range.end)
 7848                    } else {
 7849                        None
 7850                    }
 7851                })
 7852                .collect::<Vec<_>>();
 7853
 7854            (new_newlines, existing_newlines)
 7855        });
 7856        self.folding_newlines = cx.spawn(async move |this, cx| {
 7857            let (new_newlines, existing_newlines) = task.await;
 7858            if new_newlines == existing_newlines {
 7859                return;
 7860            }
 7861            let placeholder = FoldPlaceholder {
 7862                render: Arc::new(move |_, _, cx| {
 7863                    div()
 7864                        .bg(cx.theme().status().hint_background)
 7865                        .border_b_1()
 7866                        .size_full()
 7867                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7868                        .border_color(cx.theme().status().hint)
 7869                        .child("\\n")
 7870                        .into_any()
 7871                }),
 7872                constrain_width: false,
 7873                merge_adjacent: false,
 7874                type_tag: Some(type_id),
 7875                collapsed_text: None,
 7876            };
 7877            let creases = new_newlines
 7878                .into_iter()
 7879                .map(|range| Crease::simple(range, placeholder.clone()))
 7880                .collect();
 7881            this.update(cx, |this, cx| {
 7882                this.display_map.update(cx, |display_map, cx| {
 7883                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7884                    display_map.fold(creases, cx);
 7885                });
 7886            })
 7887            .ok();
 7888        });
 7889    }
 7890
 7891    #[ztracing::instrument(skip_all)]
 7892    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7893        if !self.lsp_data_enabled() {
 7894            return;
 7895        }
 7896        let cursor = self.selections.newest_anchor().head();
 7897        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7898
 7899        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7900            self.outline_symbols_at_cursor =
 7901                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7902            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7903            cx.notify();
 7904        } else {
 7905            let syntax = cx.theme().syntax().clone();
 7906            let background_task = cx.background_spawn(async move {
 7907                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7908            });
 7909            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7910                cx.spawn(async move |this, cx| {
 7911                    let symbols = background_task.await;
 7912                    this.update(cx, |this, cx| {
 7913                        this.outline_symbols_at_cursor = symbols;
 7914                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7915                        cx.notify();
 7916                    })
 7917                    .ok();
 7918                });
 7919        }
 7920    }
 7921
 7922    #[ztracing::instrument(skip_all)]
 7923    fn refresh_selected_text_highlights(
 7924        &mut self,
 7925        snapshot: &DisplaySnapshot,
 7926        on_buffer_edit: bool,
 7927        window: &mut Window,
 7928        cx: &mut Context<Editor>,
 7929    ) {
 7930        let Some((query_text, query_range)) =
 7931            self.prepare_highlight_query_from_selection(snapshot, cx)
 7932        else {
 7933            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7934            self.quick_selection_highlight_task.take();
 7935            self.debounced_selection_highlight_task.take();
 7936            self.debounced_selection_highlight_complete = false;
 7937            return;
 7938        };
 7939        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7940        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7941        let query_changed = self
 7942            .quick_selection_highlight_task
 7943            .as_ref()
 7944            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7945        if query_changed {
 7946            self.debounced_selection_highlight_complete = false;
 7947        }
 7948        if on_buffer_edit || query_changed {
 7949            self.quick_selection_highlight_task = Some((
 7950                query_range.clone(),
 7951                self.update_selection_occurrence_highlights(
 7952                    snapshot.buffer.clone(),
 7953                    query_text.clone(),
 7954                    query_range.clone(),
 7955                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7956                    false,
 7957                    window,
 7958                    cx,
 7959                ),
 7960            ));
 7961        }
 7962        if on_buffer_edit
 7963            || self
 7964                .debounced_selection_highlight_task
 7965                .as_ref()
 7966                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7967        {
 7968            let multi_buffer_start = multi_buffer_snapshot
 7969                .anchor_before(MultiBufferOffset(0))
 7970                .to_point(&multi_buffer_snapshot);
 7971            let multi_buffer_end = multi_buffer_snapshot
 7972                .anchor_after(multi_buffer_snapshot.len())
 7973                .to_point(&multi_buffer_snapshot);
 7974            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7975            self.debounced_selection_highlight_task = Some((
 7976                query_range.clone(),
 7977                self.update_selection_occurrence_highlights(
 7978                    snapshot.buffer.clone(),
 7979                    query_text,
 7980                    query_range,
 7981                    multi_buffer_full_range,
 7982                    true,
 7983                    window,
 7984                    cx,
 7985                ),
 7986            ));
 7987        }
 7988    }
 7989
 7990    pub fn multi_buffer_visible_range(
 7991        &self,
 7992        display_snapshot: &DisplaySnapshot,
 7993        cx: &App,
 7994    ) -> Range<Point> {
 7995        let visible_start = self
 7996            .scroll_manager
 7997            .native_anchor(display_snapshot, cx)
 7998            .anchor
 7999            .to_point(display_snapshot.buffer_snapshot())
 8000            .to_display_point(display_snapshot);
 8001
 8002        let mut target_end = visible_start;
 8003        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 8004
 8005        visible_start.to_point(display_snapshot)
 8006            ..display_snapshot
 8007                .clip_point(target_end, Bias::Right)
 8008                .to_point(display_snapshot)
 8009    }
 8010
 8011    pub fn refresh_edit_prediction(
 8012        &mut self,
 8013        debounce: bool,
 8014        user_requested: bool,
 8015        window: &mut Window,
 8016        cx: &mut Context<Self>,
 8017    ) -> Option<()> {
 8018        if self.leader_id.is_some() {
 8019            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8020            return None;
 8021        }
 8022
 8023        let cursor = self.selections.newest_anchor().head();
 8024        let (buffer, cursor_buffer_position) =
 8025            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8026
 8027        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8028            return None;
 8029        }
 8030
 8031        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 8032            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8033            return None;
 8034        }
 8035
 8036        self.update_visible_edit_prediction(window, cx);
 8037
 8038        if !user_requested
 8039            && (!self.should_show_edit_predictions()
 8040                || !self.is_focused(window)
 8041                || buffer.read(cx).is_empty())
 8042        {
 8043            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8044            return None;
 8045        }
 8046
 8047        self.edit_prediction_provider()?
 8048            .refresh(buffer, cursor_buffer_position, debounce, cx);
 8049        Some(())
 8050    }
 8051
 8052    fn show_edit_predictions_in_menu(&self) -> bool {
 8053        match self.edit_prediction_settings {
 8054            EditPredictionSettings::Disabled => false,
 8055            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8056        }
 8057    }
 8058
 8059    pub fn edit_predictions_enabled(&self) -> bool {
 8060        match self.edit_prediction_settings {
 8061            EditPredictionSettings::Disabled => false,
 8062            EditPredictionSettings::Enabled { .. } => true,
 8063        }
 8064    }
 8065
 8066    fn edit_prediction_requires_modifier(&self) -> bool {
 8067        match self.edit_prediction_settings {
 8068            EditPredictionSettings::Disabled => false,
 8069            EditPredictionSettings::Enabled {
 8070                preview_requires_modifier,
 8071                ..
 8072            } => preview_requires_modifier,
 8073        }
 8074    }
 8075
 8076    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8077        if self.edit_prediction_provider.is_none() {
 8078            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8079            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8080            return;
 8081        }
 8082
 8083        let selection = self.selections.newest_anchor();
 8084        let cursor = selection.head();
 8085
 8086        if let Some((buffer, cursor_buffer_position)) =
 8087            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8088        {
 8089            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8090                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8091                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8092                return;
 8093            }
 8094            self.edit_prediction_settings =
 8095                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8096        }
 8097    }
 8098
 8099    fn edit_prediction_settings_at_position(
 8100        &self,
 8101        buffer: &Entity<Buffer>,
 8102        buffer_position: language::Anchor,
 8103        cx: &App,
 8104    ) -> EditPredictionSettings {
 8105        if !self.mode.is_full()
 8106            || !self.show_edit_predictions_override.unwrap_or(true)
 8107            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8108        {
 8109            return EditPredictionSettings::Disabled;
 8110        }
 8111
 8112        if !LanguageSettings::for_buffer(&buffer.read(cx), cx).show_edit_predictions {
 8113            return EditPredictionSettings::Disabled;
 8114        };
 8115
 8116        let by_provider = matches!(
 8117            self.menu_edit_predictions_policy,
 8118            MenuEditPredictionsPolicy::ByProvider
 8119        );
 8120
 8121        let show_in_menu = by_provider
 8122            && self
 8123                .edit_prediction_provider
 8124                .as_ref()
 8125                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8126
 8127        let file = buffer.read(cx).file();
 8128        let preview_requires_modifier =
 8129            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8130
 8131        EditPredictionSettings::Enabled {
 8132            show_in_menu,
 8133            preview_requires_modifier,
 8134        }
 8135    }
 8136
 8137    fn should_show_edit_predictions(&self) -> bool {
 8138        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8139    }
 8140
 8141    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8142        matches!(
 8143            self.edit_prediction_preview,
 8144            EditPredictionPreview::Active { .. }
 8145        )
 8146    }
 8147
 8148    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8149        let cursor = self.selections.newest_anchor().head();
 8150        if let Some((buffer, cursor_position)) =
 8151            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8152        {
 8153            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8154        } else {
 8155            false
 8156        }
 8157    }
 8158
 8159    pub fn supports_minimap(&self, cx: &App) -> bool {
 8160        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8161    }
 8162
 8163    fn edit_predictions_enabled_in_buffer(
 8164        &self,
 8165        buffer: &Entity<Buffer>,
 8166        buffer_position: language::Anchor,
 8167        cx: &App,
 8168    ) -> bool {
 8169        maybe!({
 8170            if self.read_only(cx) || self.leader_id.is_some() {
 8171                return Some(false);
 8172            }
 8173            let provider = self.edit_prediction_provider()?;
 8174            if !provider.is_enabled(buffer, buffer_position, cx) {
 8175                return Some(false);
 8176            }
 8177            let buffer = buffer.read(cx);
 8178            let Some(file) = buffer.file() else {
 8179                return Some(true);
 8180            };
 8181            let settings = all_language_settings(Some(file), cx);
 8182            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8183        })
 8184        .unwrap_or(false)
 8185    }
 8186
 8187    pub fn show_edit_prediction(
 8188        &mut self,
 8189        _: &ShowEditPrediction,
 8190        window: &mut Window,
 8191        cx: &mut Context<Self>,
 8192    ) {
 8193        if !self.has_active_edit_prediction() {
 8194            self.refresh_edit_prediction(false, true, window, cx);
 8195            return;
 8196        }
 8197
 8198        self.update_visible_edit_prediction(window, cx);
 8199    }
 8200
 8201    pub fn display_cursor_names(
 8202        &mut self,
 8203        _: &DisplayCursorNames,
 8204        window: &mut Window,
 8205        cx: &mut Context<Self>,
 8206    ) {
 8207        self.show_cursor_names(window, cx);
 8208    }
 8209
 8210    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8211        self.show_cursor_names = true;
 8212        cx.notify();
 8213        cx.spawn_in(window, async move |this, cx| {
 8214            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8215            this.update(cx, |this, cx| {
 8216                this.show_cursor_names = false;
 8217                cx.notify()
 8218            })
 8219            .ok()
 8220        })
 8221        .detach();
 8222    }
 8223
 8224    pub fn accept_partial_edit_prediction(
 8225        &mut self,
 8226        granularity: EditPredictionGranularity,
 8227        window: &mut Window,
 8228        cx: &mut Context<Self>,
 8229    ) {
 8230        if self.show_edit_predictions_in_menu() {
 8231            self.hide_context_menu(window, cx);
 8232        }
 8233
 8234        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8235            return;
 8236        };
 8237
 8238        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8239            return;
 8240        }
 8241
 8242        match &active_edit_prediction.completion {
 8243            EditPrediction::MoveWithin { target, .. } => {
 8244                let target = *target;
 8245
 8246                if matches!(granularity, EditPredictionGranularity::Full) {
 8247                    if let Some(position_map) = &self.last_position_map {
 8248                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8249                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8250
 8251                        if is_visible || !self.edit_prediction_requires_modifier() {
 8252                            self.unfold_ranges(&[target..target], true, false, cx);
 8253                            self.change_selections(
 8254                                SelectionEffects::scroll(Autoscroll::newest()),
 8255                                window,
 8256                                cx,
 8257                                |selections| {
 8258                                    selections.select_anchor_ranges([target..target]);
 8259                                },
 8260                            );
 8261                            self.clear_row_highlights::<EditPredictionPreview>();
 8262                            self.edit_prediction_preview
 8263                                .set_previous_scroll_position(None);
 8264                        } else {
 8265                            // Highlight and request scroll
 8266                            self.edit_prediction_preview
 8267                                .set_previous_scroll_position(Some(
 8268                                    position_map.snapshot.scroll_anchor,
 8269                                ));
 8270                            self.highlight_rows::<EditPredictionPreview>(
 8271                                target..target,
 8272                                cx.theme().colors().editor_highlighted_line_background,
 8273                                RowHighlightOptions {
 8274                                    autoscroll: true,
 8275                                    ..Default::default()
 8276                                },
 8277                                cx,
 8278                            );
 8279                            self.request_autoscroll(Autoscroll::fit(), cx);
 8280                        }
 8281                    }
 8282                } else {
 8283                    self.change_selections(
 8284                        SelectionEffects::scroll(Autoscroll::newest()),
 8285                        window,
 8286                        cx,
 8287                        |selections| {
 8288                            selections.select_anchor_ranges([target..target]);
 8289                        },
 8290                    );
 8291                }
 8292            }
 8293            EditPrediction::MoveOutside { snapshot, target } => {
 8294                if let Some(workspace) = self.workspace() {
 8295                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8296                        .detach_and_log_err(cx);
 8297                }
 8298            }
 8299            EditPrediction::Edit {
 8300                edits,
 8301                cursor_position,
 8302                ..
 8303            } => {
 8304                self.report_edit_prediction_event(
 8305                    active_edit_prediction.completion_id.clone(),
 8306                    true,
 8307                    cx,
 8308                );
 8309
 8310                match granularity {
 8311                    EditPredictionGranularity::Full => {
 8312                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8313
 8314                        // Compute fallback cursor position BEFORE applying the edit,
 8315                        // so the anchor tracks through the edit correctly
 8316                        let fallback_cursor_target = {
 8317                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8318                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8319                        };
 8320
 8321                        self.buffer.update(cx, |buffer, cx| {
 8322                            buffer.edit(edits.iter().cloned(), None, cx)
 8323                        });
 8324
 8325                        if let Some(provider) = self.edit_prediction_provider() {
 8326                            provider.accept(cx);
 8327                        }
 8328
 8329                        // Resolve cursor position after the edit is applied
 8330                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8331                            // The anchor tracks through the edit, then we add the offset
 8332                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8333                            let base_offset = anchor.to_offset(&snapshot).0;
 8334                            let target_offset =
 8335                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8336                            snapshot.anchor_after(target_offset)
 8337                        } else {
 8338                            fallback_cursor_target
 8339                        };
 8340
 8341                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8342                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8343                        });
 8344
 8345                        let selections = self.selections.disjoint_anchors_arc();
 8346                        if let Some(transaction_id_now) =
 8347                            self.buffer.read(cx).last_transaction_id(cx)
 8348                        {
 8349                            if transaction_id_prev != Some(transaction_id_now) {
 8350                                self.selection_history
 8351                                    .insert_transaction(transaction_id_now, selections);
 8352                            }
 8353                        }
 8354
 8355                        self.update_visible_edit_prediction(window, cx);
 8356                        if self.active_edit_prediction.is_none() {
 8357                            self.refresh_edit_prediction(true, true, window, cx);
 8358                        }
 8359                        cx.notify();
 8360                    }
 8361                    _ => {
 8362                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8363                        let cursor_offset = self
 8364                            .selections
 8365                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8366                            .head();
 8367
 8368                        let insertion = edits.iter().find_map(|(range, text)| {
 8369                            let range = range.to_offset(&snapshot);
 8370                            if range.is_empty() && range.start == cursor_offset {
 8371                                Some(text)
 8372                            } else {
 8373                                None
 8374                            }
 8375                        });
 8376
 8377                        if let Some(text) = insertion {
 8378                            let text_to_insert = match granularity {
 8379                                EditPredictionGranularity::Word => {
 8380                                    let mut partial = text
 8381                                        .chars()
 8382                                        .by_ref()
 8383                                        .take_while(|c| c.is_alphabetic())
 8384                                        .collect::<String>();
 8385                                    if partial.is_empty() {
 8386                                        partial = text
 8387                                            .chars()
 8388                                            .by_ref()
 8389                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8390                                            .collect::<String>();
 8391                                    }
 8392                                    partial
 8393                                }
 8394                                EditPredictionGranularity::Line => {
 8395                                    if let Some(line) = text.split_inclusive('\n').next() {
 8396                                        line.to_string()
 8397                                    } else {
 8398                                        text.to_string()
 8399                                    }
 8400                                }
 8401                                EditPredictionGranularity::Full => unreachable!(),
 8402                            };
 8403
 8404                            cx.emit(EditorEvent::InputHandled {
 8405                                utf16_range_to_replace: None,
 8406                                text: text_to_insert.clone().into(),
 8407                            });
 8408
 8409                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8410                            self.refresh_edit_prediction(true, true, window, cx);
 8411                            cx.notify();
 8412                        } else {
 8413                            self.accept_partial_edit_prediction(
 8414                                EditPredictionGranularity::Full,
 8415                                window,
 8416                                cx,
 8417                            );
 8418                        }
 8419                    }
 8420                }
 8421            }
 8422        }
 8423    }
 8424
 8425    pub fn accept_next_word_edit_prediction(
 8426        &mut self,
 8427        _: &AcceptNextWordEditPrediction,
 8428        window: &mut Window,
 8429        cx: &mut Context<Self>,
 8430    ) {
 8431        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8432    }
 8433
 8434    pub fn accept_next_line_edit_prediction(
 8435        &mut self,
 8436        _: &AcceptNextLineEditPrediction,
 8437        window: &mut Window,
 8438        cx: &mut Context<Self>,
 8439    ) {
 8440        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8441    }
 8442
 8443    pub fn accept_edit_prediction(
 8444        &mut self,
 8445        _: &AcceptEditPrediction,
 8446        window: &mut Window,
 8447        cx: &mut Context<Self>,
 8448    ) {
 8449        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8450    }
 8451
 8452    fn discard_edit_prediction(
 8453        &mut self,
 8454        reason: EditPredictionDiscardReason,
 8455        cx: &mut Context<Self>,
 8456    ) -> bool {
 8457        if reason == EditPredictionDiscardReason::Rejected {
 8458            let completion_id = self
 8459                .active_edit_prediction
 8460                .as_ref()
 8461                .and_then(|active_completion| active_completion.completion_id.clone());
 8462
 8463            self.report_edit_prediction_event(completion_id, false, cx);
 8464        }
 8465
 8466        if let Some(provider) = self.edit_prediction_provider() {
 8467            provider.discard(reason, cx);
 8468        }
 8469
 8470        self.take_active_edit_prediction(reason == EditPredictionDiscardReason::Ignored, cx)
 8471    }
 8472
 8473    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8474        let Some(provider) = self.edit_prediction_provider() else {
 8475            return;
 8476        };
 8477
 8478        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 8479        let Some((position, _)) =
 8480            buffer_snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())
 8481        else {
 8482            return;
 8483        };
 8484        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
 8485            return;
 8486        };
 8487
 8488        let extension = buffer
 8489            .read(cx)
 8490            .file()
 8491            .and_then(|file| Some(file.path().extension()?.to_string()));
 8492
 8493        let event_type = match accepted {
 8494            true => "Edit Prediction Accepted",
 8495            false => "Edit Prediction Discarded",
 8496        };
 8497        telemetry::event!(
 8498            event_type,
 8499            provider = provider.name(),
 8500            prediction_id = id,
 8501            suggestion_accepted = accepted,
 8502            file_extension = extension,
 8503        );
 8504    }
 8505
 8506    fn open_editor_at_anchor(
 8507        snapshot: &language::BufferSnapshot,
 8508        target: language::Anchor,
 8509        workspace: &Entity<Workspace>,
 8510        window: &mut Window,
 8511        cx: &mut App,
 8512    ) -> Task<Result<()>> {
 8513        workspace.update(cx, |workspace, cx| {
 8514            let path = snapshot.file().map(|file| file.full_path(cx));
 8515            let Some(path) =
 8516                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8517            else {
 8518                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8519            };
 8520            let target = text::ToPoint::to_point(&target, snapshot);
 8521            let item = workspace.open_path(path, None, true, window, cx);
 8522            window.spawn(cx, async move |cx| {
 8523                let Some(editor) = item.await?.downcast::<Editor>() else {
 8524                    return Ok(());
 8525                };
 8526                editor
 8527                    .update_in(cx, |editor, window, cx| {
 8528                        editor.go_to_singleton_buffer_point(target, window, cx);
 8529                    })
 8530                    .ok();
 8531                anyhow::Ok(())
 8532            })
 8533        })
 8534    }
 8535
 8536    pub fn has_active_edit_prediction(&self) -> bool {
 8537        self.active_edit_prediction.is_some()
 8538    }
 8539
 8540    fn take_active_edit_prediction(
 8541        &mut self,
 8542        preserve_stale_in_menu: bool,
 8543        cx: &mut Context<Self>,
 8544    ) -> bool {
 8545        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8546            if !preserve_stale_in_menu {
 8547                self.stale_edit_prediction_in_menu = None;
 8548            }
 8549            return false;
 8550        };
 8551
 8552        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8553        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8554        self.stale_edit_prediction_in_menu =
 8555            preserve_stale_in_menu.then_some(active_edit_prediction);
 8556        true
 8557    }
 8558
 8559    /// Returns true when we're displaying the edit prediction popover below the cursor
 8560    /// like we are not previewing and the LSP autocomplete menu is visible
 8561    /// or we are in `when_holding_modifier` mode.
 8562    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8563        if self.edit_prediction_preview_is_active()
 8564            || !self.show_edit_predictions_in_menu()
 8565            || !self.edit_predictions_enabled()
 8566        {
 8567            return false;
 8568        }
 8569
 8570        if self.has_visible_completions_menu() {
 8571            return true;
 8572        }
 8573
 8574        has_completion && self.edit_prediction_requires_modifier()
 8575    }
 8576
 8577    fn handle_modifiers_changed(
 8578        &mut self,
 8579        modifiers: Modifiers,
 8580        position_map: &PositionMap,
 8581        window: &mut Window,
 8582        cx: &mut Context<Self>,
 8583    ) {
 8584        self.update_edit_prediction_settings(cx);
 8585
 8586        // Ensure that the edit prediction preview is updated, even when not
 8587        // enabled, if there's an active edit prediction preview.
 8588        if self.show_edit_predictions_in_menu()
 8589            || self.edit_prediction_requires_modifier()
 8590            || matches!(
 8591                self.edit_prediction_preview,
 8592                EditPredictionPreview::Active { .. }
 8593            )
 8594        {
 8595            self.update_edit_prediction_preview(&modifiers, window, cx);
 8596        }
 8597
 8598        self.update_selection_mode(&modifiers, position_map, window, cx);
 8599
 8600        let mouse_position = window.mouse_position();
 8601        if !position_map.text_hitbox.is_hovered(window) {
 8602            return;
 8603        }
 8604
 8605        self.update_hovered_link(
 8606            position_map.point_for_position(mouse_position),
 8607            Some(mouse_position),
 8608            &position_map.snapshot,
 8609            modifiers,
 8610            window,
 8611            cx,
 8612        )
 8613    }
 8614
 8615    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8616        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8617            MultiCursorModifier::Alt => modifiers.secondary(),
 8618            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8619        }
 8620    }
 8621
 8622    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8623        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8624            MultiCursorModifier::Alt => modifiers.alt,
 8625            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8626        }
 8627    }
 8628
 8629    fn columnar_selection_mode(
 8630        modifiers: &Modifiers,
 8631        cx: &mut Context<Self>,
 8632    ) -> Option<ColumnarMode> {
 8633        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8634            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8635                Some(ColumnarMode::FromMouse)
 8636            } else if Self::is_alt_pressed(modifiers, cx) {
 8637                Some(ColumnarMode::FromSelection)
 8638            } else {
 8639                None
 8640            }
 8641        } else {
 8642            None
 8643        }
 8644    }
 8645
 8646    fn update_selection_mode(
 8647        &mut self,
 8648        modifiers: &Modifiers,
 8649        position_map: &PositionMap,
 8650        window: &mut Window,
 8651        cx: &mut Context<Self>,
 8652    ) {
 8653        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8654            return;
 8655        };
 8656        if self.selections.pending_anchor().is_none() {
 8657            return;
 8658        }
 8659
 8660        let mouse_position = window.mouse_position();
 8661        let point_for_position = position_map.point_for_position(mouse_position);
 8662        let position = point_for_position.previous_valid;
 8663
 8664        self.select(
 8665            SelectPhase::BeginColumnar {
 8666                position,
 8667                reset: false,
 8668                mode,
 8669                goal_column: point_for_position.exact_unclipped.column(),
 8670            },
 8671            window,
 8672            cx,
 8673        );
 8674    }
 8675
 8676    fn update_edit_prediction_preview(
 8677        &mut self,
 8678        modifiers: &Modifiers,
 8679        window: &mut Window,
 8680        cx: &mut Context<Self>,
 8681    ) {
 8682        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8683
 8684        if modifiers_held {
 8685            if matches!(
 8686                self.edit_prediction_preview,
 8687                EditPredictionPreview::Inactive { .. }
 8688            ) {
 8689                self.edit_prediction_preview = EditPredictionPreview::Active {
 8690                    previous_scroll_position: None,
 8691                    since: Instant::now(),
 8692                };
 8693
 8694                self.update_visible_edit_prediction(window, cx);
 8695                cx.notify();
 8696            }
 8697        } else if let EditPredictionPreview::Active {
 8698            previous_scroll_position,
 8699            since,
 8700        } = self.edit_prediction_preview
 8701        {
 8702            if let (Some(previous_scroll_position), Some(position_map)) =
 8703                (previous_scroll_position, self.last_position_map.as_ref())
 8704            {
 8705                self.set_scroll_position(
 8706                    previous_scroll_position
 8707                        .scroll_position(&position_map.snapshot.display_snapshot),
 8708                    window,
 8709                    cx,
 8710                );
 8711            }
 8712
 8713            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8714                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8715            };
 8716            self.clear_row_highlights::<EditPredictionPreview>();
 8717            self.update_visible_edit_prediction(window, cx);
 8718            cx.notify();
 8719        }
 8720    }
 8721
 8722    fn update_visible_edit_prediction(
 8723        &mut self,
 8724        _window: &mut Window,
 8725        cx: &mut Context<Self>,
 8726    ) -> Option<()> {
 8727        if self.ime_transaction.is_some() {
 8728            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8729            return None;
 8730        }
 8731
 8732        let selection = self.selections.newest_anchor();
 8733        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8734        let cursor = selection.head();
 8735        let (cursor_text_anchor, _) = multibuffer.anchor_to_buffer_anchor(cursor)?;
 8736        let buffer = self.buffer.read(cx).buffer(cursor_text_anchor.buffer_id)?;
 8737
 8738        // Check project-level disable_ai setting for the current buffer
 8739        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8740            return None;
 8741        }
 8742        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8743
 8744        let show_in_menu = self.show_edit_predictions_in_menu();
 8745        let completions_menu_has_precedence = !show_in_menu
 8746            && (self.context_menu.borrow().is_some()
 8747                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8748
 8749        if completions_menu_has_precedence
 8750            || !offset_selection.is_empty()
 8751            || self
 8752                .active_edit_prediction
 8753                .as_ref()
 8754                .is_some_and(|completion| {
 8755                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8756                        return false;
 8757                    };
 8758                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8759                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8760                    !invalidation_range.contains(&offset_selection.head())
 8761                })
 8762        {
 8763            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8764            return None;
 8765        }
 8766
 8767        self.take_active_edit_prediction(true, cx);
 8768        let Some(provider) = self.edit_prediction_provider() else {
 8769            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8770            return None;
 8771        };
 8772
 8773        self.edit_prediction_settings =
 8774            self.edit_prediction_settings_at_position(&buffer, cursor_text_anchor, cx);
 8775
 8776        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8777
 8778        if self.in_leading_whitespace {
 8779            let cursor_point = cursor.to_point(&multibuffer);
 8780            let mut suggested_indent = None;
 8781            multibuffer.suggested_indents_callback(
 8782                cursor_point.row..cursor_point.row + 1,
 8783                &mut |_, indent| {
 8784                    suggested_indent = Some(indent);
 8785                    ControlFlow::Break(())
 8786                },
 8787                cx,
 8788            );
 8789
 8790            if let Some(indent) = suggested_indent
 8791                && indent.len == cursor_point.column
 8792            {
 8793                self.in_leading_whitespace = false;
 8794            }
 8795        }
 8796
 8797        let edit_prediction = provider.suggest(&buffer, cursor_text_anchor, cx)?;
 8798
 8799        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8800        {
 8801            edit_prediction_types::EditPrediction::Local {
 8802                id,
 8803                edits,
 8804                cursor_position,
 8805                edit_preview,
 8806            } => (id, edits, cursor_position, edit_preview),
 8807            edit_prediction_types::EditPrediction::Jump {
 8808                id,
 8809                snapshot,
 8810                target,
 8811            } => {
 8812                if let Some(provider) = &self.edit_prediction_provider {
 8813                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8814                }
 8815                self.stale_edit_prediction_in_menu = None;
 8816                self.active_edit_prediction = Some(EditPredictionState {
 8817                    inlay_ids: vec![],
 8818                    completion: EditPrediction::MoveOutside { snapshot, target },
 8819                    completion_id: id,
 8820                    invalidation_range: None,
 8821                });
 8822                cx.notify();
 8823                return Some(());
 8824            }
 8825        };
 8826
 8827        let edits = edits
 8828            .into_iter()
 8829            .flat_map(|(range, new_text)| {
 8830                Some((
 8831                    multibuffer.buffer_anchor_range_to_anchor_range(range)?,
 8832                    new_text,
 8833                ))
 8834            })
 8835            .collect::<Vec<_>>();
 8836        if edits.is_empty() {
 8837            return None;
 8838        }
 8839
 8840        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8841            let anchor = multibuffer.anchor_in_excerpt(predicted.anchor)?;
 8842            Some((anchor, predicted.offset))
 8843        });
 8844
 8845        let first_edit_start = edits.first().unwrap().0.start;
 8846        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8847        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8848
 8849        let last_edit_end = edits.last().unwrap().0.end;
 8850        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8851        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8852
 8853        let cursor_row = cursor.to_point(&multibuffer).row;
 8854
 8855        let snapshot = multibuffer
 8856            .buffer_for_id(cursor_text_anchor.buffer_id)
 8857            .cloned()?;
 8858
 8859        let mut inlay_ids = Vec::new();
 8860        let invalidation_row_range;
 8861        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8862            Some(cursor_row..edit_end_row)
 8863        } else if cursor_row > edit_end_row {
 8864            Some(edit_start_row..cursor_row)
 8865        } else {
 8866            None
 8867        };
 8868        let supports_jump = self
 8869            .edit_prediction_provider
 8870            .as_ref()
 8871            .map(|provider| provider.provider.supports_jump_to_edit())
 8872            .unwrap_or(true);
 8873
 8874        let is_move = supports_jump
 8875            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8876        let completion = if is_move {
 8877            if let Some(provider) = &self.edit_prediction_provider {
 8878                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8879            }
 8880            invalidation_row_range =
 8881                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8882            let target = first_edit_start;
 8883            EditPrediction::MoveWithin { target, snapshot }
 8884        } else {
 8885            let show_completions_in_menu = self.has_visible_completions_menu();
 8886            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8887                && !self.edit_predictions_hidden_for_vim_mode;
 8888
 8889            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8890                if provider.show_tab_accept_marker() {
 8891                    EditDisplayMode::TabAccept
 8892                } else {
 8893                    EditDisplayMode::Inline
 8894                }
 8895            } else {
 8896                EditDisplayMode::DiffPopover
 8897            };
 8898
 8899            let report_shown = match display_mode {
 8900                EditDisplayMode::DiffPopover | EditDisplayMode::Inline => {
 8901                    show_completions_in_buffer || show_completions_in_menu
 8902                }
 8903                EditDisplayMode::TabAccept => {
 8904                    show_completions_in_menu || self.edit_prediction_preview_is_active()
 8905                }
 8906            };
 8907
 8908            if report_shown && let Some(provider) = &self.edit_prediction_provider {
 8909                let suggestion_display_type = match display_mode {
 8910                    EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8911                    EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8912                        SuggestionDisplayType::GhostText
 8913                    }
 8914                };
 8915                provider.provider.did_show(suggestion_display_type, cx);
 8916            }
 8917
 8918            if show_completions_in_buffer {
 8919                if edits
 8920                    .iter()
 8921                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8922                {
 8923                    let mut inlays = Vec::new();
 8924                    for (range, new_text) in &edits {
 8925                        let inlay = Inlay::edit_prediction(
 8926                            post_inc(&mut self.next_inlay_id),
 8927                            range.start,
 8928                            new_text.as_ref(),
 8929                        );
 8930                        inlay_ids.push(inlay.id);
 8931                        inlays.push(inlay);
 8932                    }
 8933
 8934                    self.splice_inlays(&[], inlays, cx);
 8935                } else {
 8936                    let background_color = cx.theme().status().deleted_background;
 8937                    self.highlight_text(
 8938                        HighlightKey::EditPredictionHighlight,
 8939                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8940                        HighlightStyle {
 8941                            background_color: Some(background_color),
 8942                            ..Default::default()
 8943                        },
 8944                        cx,
 8945                    );
 8946                }
 8947            }
 8948
 8949            invalidation_row_range = edit_start_row..edit_end_row;
 8950
 8951            EditPrediction::Edit {
 8952                edits,
 8953                cursor_position,
 8954                edit_preview,
 8955                display_mode,
 8956                snapshot,
 8957            }
 8958        };
 8959
 8960        let invalidation_range = multibuffer
 8961            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8962            ..multibuffer.anchor_after(Point::new(
 8963                invalidation_row_range.end,
 8964                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8965            ));
 8966
 8967        self.stale_edit_prediction_in_menu = None;
 8968        self.active_edit_prediction = Some(EditPredictionState {
 8969            inlay_ids,
 8970            completion,
 8971            completion_id,
 8972            invalidation_range: Some(invalidation_range),
 8973        });
 8974
 8975        cx.notify();
 8976
 8977        Some(())
 8978    }
 8979
 8980    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8981        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8982    }
 8983
 8984    /// Get all display points of breakpoints that will be rendered within editor
 8985    ///
 8986    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8987    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8988    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8989    fn active_breakpoints(
 8990        &self,
 8991        range: Range<DisplayRow>,
 8992        window: &mut Window,
 8993        cx: &mut Context<Self>,
 8994    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8995        let mut breakpoint_display_points = HashMap::default();
 8996
 8997        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8998            return breakpoint_display_points;
 8999        };
 9000
 9001        let snapshot = self.snapshot(window, cx);
 9002
 9003        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 9004
 9005        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 9006            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 9007
 9008        for (buffer_snapshot, range, _) in
 9009            multi_buffer_snapshot.range_to_buffer_ranges(range.start..range.end)
 9010        {
 9011            let Some(buffer) = self.buffer().read(cx).buffer(buffer_snapshot.remote_id()) else {
 9012                continue;
 9013            };
 9014            let breakpoints = breakpoint_store.read(cx).breakpoints(
 9015                &buffer,
 9016                Some(
 9017                    buffer_snapshot.anchor_before(range.start)
 9018                        ..buffer_snapshot.anchor_after(range.end),
 9019                ),
 9020                &buffer_snapshot,
 9021                cx,
 9022            );
 9023            for (breakpoint, state) in breakpoints {
 9024                let Some(multi_buffer_anchor) =
 9025                    multi_buffer_snapshot.anchor_in_excerpt(breakpoint.position)
 9026                else {
 9027                    continue;
 9028                };
 9029                let position = multi_buffer_anchor
 9030                    .to_point(&multi_buffer_snapshot)
 9031                    .to_display_point(&snapshot);
 9032
 9033                breakpoint_display_points.insert(
 9034                    position.row(),
 9035                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 9036                );
 9037            }
 9038        }
 9039
 9040        breakpoint_display_points
 9041    }
 9042
 9043    fn breakpoint_context_menu(
 9044        &self,
 9045        anchor: Anchor,
 9046        window: &mut Window,
 9047        cx: &mut Context<Self>,
 9048    ) -> Entity<ui::ContextMenu> {
 9049        let weak_editor = cx.weak_entity();
 9050        let focus_handle = self.focus_handle(cx);
 9051
 9052        let row = self
 9053            .buffer
 9054            .read(cx)
 9055            .snapshot(cx)
 9056            .summary_for_anchor::<Point>(&anchor)
 9057            .row;
 9058
 9059        let breakpoint = self
 9060            .breakpoint_at_row(row, window, cx)
 9061            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9062
 9063        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9064            "Edit Log Breakpoint"
 9065        } else {
 9066            "Set Log Breakpoint"
 9067        };
 9068
 9069        let condition_breakpoint_msg = if breakpoint
 9070            .as_ref()
 9071            .is_some_and(|bp| bp.1.condition.is_some())
 9072        {
 9073            "Edit Condition Breakpoint"
 9074        } else {
 9075            "Set Condition Breakpoint"
 9076        };
 9077
 9078        let hit_condition_breakpoint_msg = if breakpoint
 9079            .as_ref()
 9080            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9081        {
 9082            "Edit Hit Condition Breakpoint"
 9083        } else {
 9084            "Set Hit Condition Breakpoint"
 9085        };
 9086
 9087        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9088            "Unset Breakpoint"
 9089        } else {
 9090            "Set Breakpoint"
 9091        };
 9092
 9093        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9094
 9095        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9096            BreakpointState::Enabled => Some("Disable"),
 9097            BreakpointState::Disabled => Some("Enable"),
 9098        });
 9099
 9100        let (anchor, breakpoint) =
 9101            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9102
 9103        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9104            menu.on_blur_subscription(Subscription::new(|| {}))
 9105                .context(focus_handle)
 9106                .when(run_to_cursor, |this| {
 9107                    let weak_editor = weak_editor.clone();
 9108                    this.entry("Run to Cursor", None, move |window, cx| {
 9109                        weak_editor
 9110                            .update(cx, |editor, cx| {
 9111                                editor.change_selections(
 9112                                    SelectionEffects::no_scroll(),
 9113                                    window,
 9114                                    cx,
 9115                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9116                                );
 9117                            })
 9118                            .ok();
 9119
 9120                        window.dispatch_action(Box::new(RunToCursor), cx);
 9121                    })
 9122                    .separator()
 9123                })
 9124                .when_some(toggle_state_msg, |this, msg| {
 9125                    this.entry(msg, None, {
 9126                        let weak_editor = weak_editor.clone();
 9127                        let breakpoint = breakpoint.clone();
 9128                        move |_window, cx| {
 9129                            weak_editor
 9130                                .update(cx, |this, cx| {
 9131                                    this.edit_breakpoint_at_anchor(
 9132                                        anchor,
 9133                                        breakpoint.as_ref().clone(),
 9134                                        BreakpointEditAction::InvertState,
 9135                                        cx,
 9136                                    );
 9137                                })
 9138                                .log_err();
 9139                        }
 9140                    })
 9141                })
 9142                .entry(set_breakpoint_msg, None, {
 9143                    let weak_editor = weak_editor.clone();
 9144                    let breakpoint = breakpoint.clone();
 9145                    move |_window, cx| {
 9146                        weak_editor
 9147                            .update(cx, |this, cx| {
 9148                                this.edit_breakpoint_at_anchor(
 9149                                    anchor,
 9150                                    breakpoint.as_ref().clone(),
 9151                                    BreakpointEditAction::Toggle,
 9152                                    cx,
 9153                                );
 9154                            })
 9155                            .log_err();
 9156                    }
 9157                })
 9158                .entry(log_breakpoint_msg, None, {
 9159                    let breakpoint = breakpoint.clone();
 9160                    let weak_editor = weak_editor.clone();
 9161                    move |window, cx| {
 9162                        weak_editor
 9163                            .update(cx, |this, cx| {
 9164                                this.add_edit_breakpoint_block(
 9165                                    anchor,
 9166                                    breakpoint.as_ref(),
 9167                                    BreakpointPromptEditAction::Log,
 9168                                    window,
 9169                                    cx,
 9170                                );
 9171                            })
 9172                            .log_err();
 9173                    }
 9174                })
 9175                .entry(condition_breakpoint_msg, None, {
 9176                    let breakpoint = breakpoint.clone();
 9177                    let weak_editor = weak_editor.clone();
 9178                    move |window, cx| {
 9179                        weak_editor
 9180                            .update(cx, |this, cx| {
 9181                                this.add_edit_breakpoint_block(
 9182                                    anchor,
 9183                                    breakpoint.as_ref(),
 9184                                    BreakpointPromptEditAction::Condition,
 9185                                    window,
 9186                                    cx,
 9187                                );
 9188                            })
 9189                            .log_err();
 9190                    }
 9191                })
 9192                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9193                    weak_editor
 9194                        .update(cx, |this, cx| {
 9195                            this.add_edit_breakpoint_block(
 9196                                anchor,
 9197                                breakpoint.as_ref(),
 9198                                BreakpointPromptEditAction::HitCondition,
 9199                                window,
 9200                                cx,
 9201                            );
 9202                        })
 9203                        .log_err();
 9204                })
 9205        })
 9206    }
 9207
 9208    fn render_breakpoint(
 9209        &self,
 9210        position: Anchor,
 9211        row: DisplayRow,
 9212        breakpoint: &Breakpoint,
 9213        state: Option<BreakpointSessionState>,
 9214        cx: &mut Context<Self>,
 9215    ) -> IconButton {
 9216        let is_rejected = state.is_some_and(|s| !s.verified);
 9217        // Is it a breakpoint that shows up when hovering over gutter?
 9218        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9219            (false, false),
 9220            |PhantomBreakpointIndicator {
 9221                 is_active,
 9222                 display_row,
 9223                 collides_with_existing_breakpoint,
 9224             }| {
 9225                (
 9226                    is_active && display_row == row,
 9227                    collides_with_existing_breakpoint,
 9228                )
 9229            },
 9230        );
 9231
 9232        let (color, icon) = {
 9233            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9234                (false, false) => ui::IconName::DebugBreakpoint,
 9235                (true, false) => ui::IconName::DebugLogBreakpoint,
 9236                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9237                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9238            };
 9239
 9240            let theme_colors = cx.theme().colors();
 9241
 9242            let color = if is_phantom {
 9243                if collides_with_existing {
 9244                    Color::Custom(
 9245                        theme_colors
 9246                            .debugger_accent
 9247                            .blend(theme_colors.text.opacity(0.6)),
 9248                    )
 9249                } else {
 9250                    Color::Hint
 9251                }
 9252            } else if is_rejected {
 9253                Color::Disabled
 9254            } else {
 9255                Color::Debugger
 9256            };
 9257
 9258            (color, icon)
 9259        };
 9260
 9261        let breakpoint = Arc::from(breakpoint.clone());
 9262
 9263        let alt_as_text = gpui::Keystroke {
 9264            modifiers: Modifiers::secondary_key(),
 9265            ..Default::default()
 9266        };
 9267        let primary_action_text = if breakpoint.is_disabled() {
 9268            "Enable breakpoint"
 9269        } else if is_phantom && !collides_with_existing {
 9270            "Set breakpoint"
 9271        } else {
 9272            "Unset breakpoint"
 9273        };
 9274        let focus_handle = self.focus_handle.clone();
 9275
 9276        let meta = if is_rejected {
 9277            SharedString::from("No executable code is associated with this line.")
 9278        } else if collides_with_existing && !breakpoint.is_disabled() {
 9279            SharedString::from(format!(
 9280                "{alt_as_text}-click to disable,\nright-click for more options."
 9281            ))
 9282        } else {
 9283            SharedString::from("Right-click for more options.")
 9284        };
 9285        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9286            .icon_size(IconSize::XSmall)
 9287            .size(ui::ButtonSize::None)
 9288            .when(is_rejected, |this| {
 9289                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9290            })
 9291            .icon_color(color)
 9292            .style(ButtonStyle::Transparent)
 9293            .on_click(cx.listener({
 9294                move |editor, event: &ClickEvent, window, cx| {
 9295                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9296                        BreakpointEditAction::InvertState
 9297                    } else {
 9298                        BreakpointEditAction::Toggle
 9299                    };
 9300
 9301                    window.focus(&editor.focus_handle(cx), cx);
 9302                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9303                    editor.edit_breakpoint_at_anchor(
 9304                        position,
 9305                        breakpoint.as_ref().clone(),
 9306                        edit_action,
 9307                        cx,
 9308                    );
 9309                }
 9310            }))
 9311            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9312                editor.set_breakpoint_context_menu(
 9313                    row,
 9314                    Some(position),
 9315                    event.position(),
 9316                    window,
 9317                    cx,
 9318                );
 9319            }))
 9320            .tooltip(move |_window, cx| {
 9321                Tooltip::with_meta_in(
 9322                    primary_action_text,
 9323                    Some(&ToggleBreakpoint),
 9324                    meta.clone(),
 9325                    &focus_handle,
 9326                    cx,
 9327                )
 9328            })
 9329    }
 9330
 9331    fn build_tasks_context(
 9332        project: &Entity<Project>,
 9333        buffer: &Entity<Buffer>,
 9334        buffer_row: u32,
 9335        tasks: &Arc<RunnableTasks>,
 9336        cx: &mut Context<Self>,
 9337    ) -> Task<Option<task::TaskContext>> {
 9338        let position = Point::new(buffer_row, tasks.column);
 9339        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9340        let location = Location {
 9341            buffer: buffer.clone(),
 9342            range: range_start..range_start,
 9343        };
 9344        // Fill in the environmental variables from the tree-sitter captures
 9345        let mut captured_task_variables = TaskVariables::default();
 9346        for (capture_name, value) in tasks.extra_variables.clone() {
 9347            captured_task_variables.insert(
 9348                task::VariableName::Custom(capture_name.into()),
 9349                value.clone(),
 9350            );
 9351        }
 9352        project.update(cx, |project, cx| {
 9353            project.task_store().update(cx, |task_store, cx| {
 9354                task_store.task_context_for_location(captured_task_variables, location, cx)
 9355            })
 9356        })
 9357    }
 9358
 9359    pub fn context_menu_visible(&self) -> bool {
 9360        !self.edit_prediction_preview_is_active()
 9361            && self
 9362                .context_menu
 9363                .borrow()
 9364                .as_ref()
 9365                .is_some_and(|menu| menu.visible())
 9366    }
 9367
 9368    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9369        self.context_menu
 9370            .borrow()
 9371            .as_ref()
 9372            .map(|menu| menu.origin())
 9373    }
 9374
 9375    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9376        self.context_menu_options = Some(options);
 9377    }
 9378
 9379    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9380    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9381
 9382    fn render_edit_prediction_popover(
 9383        &mut self,
 9384        text_bounds: &Bounds<Pixels>,
 9385        content_origin: gpui::Point<Pixels>,
 9386        right_margin: Pixels,
 9387        editor_snapshot: &EditorSnapshot,
 9388        visible_row_range: Range<DisplayRow>,
 9389        scroll_top: ScrollOffset,
 9390        scroll_bottom: ScrollOffset,
 9391        line_layouts: &[LineWithInvisibles],
 9392        line_height: Pixels,
 9393        scroll_position: gpui::Point<ScrollOffset>,
 9394        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9395        newest_selection_head: Option<DisplayPoint>,
 9396        editor_width: Pixels,
 9397        style: &EditorStyle,
 9398        window: &mut Window,
 9399        cx: &mut App,
 9400    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9401        if self.mode().is_minimap() {
 9402            return None;
 9403        }
 9404        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9405
 9406        if self.edit_prediction_visible_in_cursor_popover(true) {
 9407            return None;
 9408        }
 9409
 9410        match &active_edit_prediction.completion {
 9411            EditPrediction::MoveWithin { target, .. } => {
 9412                let target_display_point = target.to_display_point(editor_snapshot);
 9413
 9414                if self.edit_prediction_requires_modifier() {
 9415                    if !self.edit_prediction_preview_is_active() {
 9416                        return None;
 9417                    }
 9418
 9419                    self.render_edit_prediction_modifier_jump_popover(
 9420                        text_bounds,
 9421                        content_origin,
 9422                        visible_row_range,
 9423                        line_layouts,
 9424                        line_height,
 9425                        scroll_pixel_position,
 9426                        newest_selection_head,
 9427                        target_display_point,
 9428                        window,
 9429                        cx,
 9430                    )
 9431                } else {
 9432                    self.render_edit_prediction_eager_jump_popover(
 9433                        text_bounds,
 9434                        content_origin,
 9435                        editor_snapshot,
 9436                        visible_row_range,
 9437                        scroll_top,
 9438                        scroll_bottom,
 9439                        line_height,
 9440                        scroll_pixel_position,
 9441                        target_display_point,
 9442                        editor_width,
 9443                        window,
 9444                        cx,
 9445                    )
 9446                }
 9447            }
 9448            EditPrediction::Edit {
 9449                display_mode: EditDisplayMode::Inline,
 9450                ..
 9451            } => None,
 9452            EditPrediction::Edit {
 9453                display_mode: EditDisplayMode::TabAccept,
 9454                edits,
 9455                ..
 9456            } => {
 9457                let range = &edits.first()?.0;
 9458                let target_display_point = range.end.to_display_point(editor_snapshot);
 9459
 9460                self.render_edit_prediction_end_of_line_popover(
 9461                    "Accept",
 9462                    editor_snapshot,
 9463                    visible_row_range,
 9464                    target_display_point,
 9465                    line_height,
 9466                    scroll_pixel_position,
 9467                    content_origin,
 9468                    editor_width,
 9469                    window,
 9470                    cx,
 9471                )
 9472            }
 9473            EditPrediction::Edit {
 9474                edits,
 9475                edit_preview,
 9476                display_mode: EditDisplayMode::DiffPopover,
 9477                snapshot,
 9478                ..
 9479            } => self.render_edit_prediction_diff_popover(
 9480                text_bounds,
 9481                content_origin,
 9482                right_margin,
 9483                editor_snapshot,
 9484                visible_row_range,
 9485                line_layouts,
 9486                line_height,
 9487                scroll_position,
 9488                scroll_pixel_position,
 9489                newest_selection_head,
 9490                editor_width,
 9491                style,
 9492                edits,
 9493                edit_preview,
 9494                snapshot,
 9495                window,
 9496                cx,
 9497            ),
 9498            EditPrediction::MoveOutside { snapshot, .. } => {
 9499                let mut element = self
 9500                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9501                    .into_any();
 9502
 9503                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9504                let origin_x = text_bounds.size.width - size.width - px(30.);
 9505                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9506                element.prepaint_at(origin, window, cx);
 9507
 9508                Some((element, origin))
 9509            }
 9510        }
 9511    }
 9512
 9513    fn render_edit_prediction_modifier_jump_popover(
 9514        &mut self,
 9515        text_bounds: &Bounds<Pixels>,
 9516        content_origin: gpui::Point<Pixels>,
 9517        visible_row_range: Range<DisplayRow>,
 9518        line_layouts: &[LineWithInvisibles],
 9519        line_height: Pixels,
 9520        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9521        newest_selection_head: Option<DisplayPoint>,
 9522        target_display_point: DisplayPoint,
 9523        window: &mut Window,
 9524        cx: &mut App,
 9525    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9526        let scrolled_content_origin =
 9527            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9528
 9529        const SCROLL_PADDING_Y: Pixels = px(12.);
 9530
 9531        if target_display_point.row() < visible_row_range.start {
 9532            return self.render_edit_prediction_scroll_popover(
 9533                &|_| SCROLL_PADDING_Y,
 9534                IconName::ArrowUp,
 9535                visible_row_range,
 9536                line_layouts,
 9537                newest_selection_head,
 9538                scrolled_content_origin,
 9539                window,
 9540                cx,
 9541            );
 9542        } else if target_display_point.row() >= visible_row_range.end {
 9543            return self.render_edit_prediction_scroll_popover(
 9544                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9545                IconName::ArrowDown,
 9546                visible_row_range,
 9547                line_layouts,
 9548                newest_selection_head,
 9549                scrolled_content_origin,
 9550                window,
 9551                cx,
 9552            );
 9553        }
 9554
 9555        const POLE_WIDTH: Pixels = px(2.);
 9556
 9557        let line_layout =
 9558            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9559        let target_column = target_display_point.column() as usize;
 9560
 9561        let target_x = line_layout.x_for_index(target_column);
 9562        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9563            - scroll_pixel_position.y;
 9564
 9565        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9566
 9567        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9568        border_color.l += 0.001;
 9569
 9570        let mut element = v_flex()
 9571            .items_end()
 9572            .when(flag_on_right, |el| el.items_start())
 9573            .child(if flag_on_right {
 9574                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9575                    .rounded_bl(px(0.))
 9576                    .rounded_tl(px(0.))
 9577                    .border_l_2()
 9578                    .border_color(border_color)
 9579            } else {
 9580                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9581                    .rounded_br(px(0.))
 9582                    .rounded_tr(px(0.))
 9583                    .border_r_2()
 9584                    .border_color(border_color)
 9585            })
 9586            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9587            .into_any();
 9588
 9589        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9590
 9591        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9592            - point(
 9593                if flag_on_right {
 9594                    POLE_WIDTH
 9595                } else {
 9596                    size.width - POLE_WIDTH
 9597                },
 9598                size.height - line_height,
 9599            );
 9600
 9601        origin.x = origin.x.max(content_origin.x);
 9602
 9603        element.prepaint_at(origin, window, cx);
 9604
 9605        Some((element, origin))
 9606    }
 9607
 9608    fn render_edit_prediction_scroll_popover(
 9609        &mut self,
 9610        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9611        scroll_icon: IconName,
 9612        visible_row_range: Range<DisplayRow>,
 9613        line_layouts: &[LineWithInvisibles],
 9614        newest_selection_head: Option<DisplayPoint>,
 9615        scrolled_content_origin: gpui::Point<Pixels>,
 9616        window: &mut Window,
 9617        cx: &mut App,
 9618    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9619        let mut element = self
 9620            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9621            .into_any();
 9622
 9623        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9624
 9625        let cursor = newest_selection_head?;
 9626        let cursor_row_layout =
 9627            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9628        let cursor_column = cursor.column() as usize;
 9629
 9630        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9631
 9632        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9633
 9634        element.prepaint_at(origin, window, cx);
 9635        Some((element, origin))
 9636    }
 9637
 9638    fn render_edit_prediction_eager_jump_popover(
 9639        &mut self,
 9640        text_bounds: &Bounds<Pixels>,
 9641        content_origin: gpui::Point<Pixels>,
 9642        editor_snapshot: &EditorSnapshot,
 9643        visible_row_range: Range<DisplayRow>,
 9644        scroll_top: ScrollOffset,
 9645        scroll_bottom: ScrollOffset,
 9646        line_height: Pixels,
 9647        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9648        target_display_point: DisplayPoint,
 9649        editor_width: Pixels,
 9650        window: &mut Window,
 9651        cx: &mut App,
 9652    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9653        if target_display_point.row().as_f64() < scroll_top {
 9654            let mut element = self
 9655                .render_edit_prediction_line_popover(
 9656                    "Jump to Edit",
 9657                    Some(IconName::ArrowUp),
 9658                    window,
 9659                    cx,
 9660                )
 9661                .into_any();
 9662
 9663            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9664            let offset = point(
 9665                (text_bounds.size.width - size.width) / 2.,
 9666                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9667            );
 9668
 9669            let origin = text_bounds.origin + offset;
 9670            element.prepaint_at(origin, window, cx);
 9671            Some((element, origin))
 9672        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9673            let mut element = self
 9674                .render_edit_prediction_line_popover(
 9675                    "Jump to Edit",
 9676                    Some(IconName::ArrowDown),
 9677                    window,
 9678                    cx,
 9679                )
 9680                .into_any();
 9681
 9682            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9683            let offset = point(
 9684                (text_bounds.size.width - size.width) / 2.,
 9685                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9686            );
 9687
 9688            let origin = text_bounds.origin + offset;
 9689            element.prepaint_at(origin, window, cx);
 9690            Some((element, origin))
 9691        } else {
 9692            self.render_edit_prediction_end_of_line_popover(
 9693                "Jump to Edit",
 9694                editor_snapshot,
 9695                visible_row_range,
 9696                target_display_point,
 9697                line_height,
 9698                scroll_pixel_position,
 9699                content_origin,
 9700                editor_width,
 9701                window,
 9702                cx,
 9703            )
 9704        }
 9705    }
 9706
 9707    fn render_edit_prediction_end_of_line_popover(
 9708        self: &mut Editor,
 9709        label: &'static str,
 9710        editor_snapshot: &EditorSnapshot,
 9711        visible_row_range: Range<DisplayRow>,
 9712        target_display_point: DisplayPoint,
 9713        line_height: Pixels,
 9714        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9715        content_origin: gpui::Point<Pixels>,
 9716        editor_width: Pixels,
 9717        window: &mut Window,
 9718        cx: &mut App,
 9719    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9720        let target_line_end = DisplayPoint::new(
 9721            target_display_point.row(),
 9722            editor_snapshot.line_len(target_display_point.row()),
 9723        );
 9724
 9725        let mut element = self
 9726            .render_edit_prediction_line_popover(label, None, window, cx)
 9727            .into_any();
 9728
 9729        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9730
 9731        let line_origin =
 9732            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9733
 9734        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9735        let mut origin = start_point
 9736            + line_origin
 9737            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9738        origin.x = origin.x.max(content_origin.x);
 9739
 9740        let max_x = content_origin.x + editor_width - size.width;
 9741
 9742        if origin.x > max_x {
 9743            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9744
 9745            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9746                origin.y += offset;
 9747                IconName::ArrowUp
 9748            } else {
 9749                origin.y -= offset;
 9750                IconName::ArrowDown
 9751            };
 9752
 9753            element = self
 9754                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9755                .into_any();
 9756
 9757            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9758
 9759            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9760        }
 9761
 9762        element.prepaint_at(origin, window, cx);
 9763        Some((element, origin))
 9764    }
 9765
 9766    fn render_edit_prediction_diff_popover(
 9767        self: &Editor,
 9768        text_bounds: &Bounds<Pixels>,
 9769        content_origin: gpui::Point<Pixels>,
 9770        right_margin: Pixels,
 9771        editor_snapshot: &EditorSnapshot,
 9772        visible_row_range: Range<DisplayRow>,
 9773        line_layouts: &[LineWithInvisibles],
 9774        line_height: Pixels,
 9775        scroll_position: gpui::Point<ScrollOffset>,
 9776        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9777        newest_selection_head: Option<DisplayPoint>,
 9778        editor_width: Pixels,
 9779        style: &EditorStyle,
 9780        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9781        edit_preview: &Option<language::EditPreview>,
 9782        snapshot: &language::BufferSnapshot,
 9783        window: &mut Window,
 9784        cx: &mut App,
 9785    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9786        let edit_start = edits
 9787            .first()
 9788            .unwrap()
 9789            .0
 9790            .start
 9791            .to_display_point(editor_snapshot);
 9792        let edit_end = edits
 9793            .last()
 9794            .unwrap()
 9795            .0
 9796            .end
 9797            .to_display_point(editor_snapshot);
 9798
 9799        let is_visible = visible_row_range.contains(&edit_start.row())
 9800            || visible_row_range.contains(&edit_end.row());
 9801        if !is_visible {
 9802            return None;
 9803        }
 9804
 9805        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9806            crate::edit_prediction_edit_text(
 9807                snapshot,
 9808                edits,
 9809                edit_preview,
 9810                false,
 9811                editor_snapshot.buffer_snapshot(),
 9812                cx,
 9813            )
 9814        } else {
 9815            // Fallback for providers without edit_preview
 9816            crate::edit_prediction_fallback_text(edits, cx)
 9817        };
 9818
 9819        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9820        let line_count = highlighted_edits.text.lines().count();
 9821
 9822        const BORDER_WIDTH: Pixels = px(1.);
 9823
 9824        let keybind = self.render_edit_prediction_keybind(window, cx);
 9825        let has_keybind = keybind.is_some();
 9826
 9827        let mut element = h_flex()
 9828            .items_start()
 9829            .child(
 9830                h_flex()
 9831                    .bg(cx.theme().colors().editor_background)
 9832                    .border(BORDER_WIDTH)
 9833                    .shadow_xs()
 9834                    .border_color(cx.theme().colors().border)
 9835                    .rounded_l_lg()
 9836                    .when(line_count > 1, |el| el.rounded_br_lg())
 9837                    .pr_1()
 9838                    .child(styled_text),
 9839            )
 9840            .child(
 9841                h_flex()
 9842                    .h(line_height + BORDER_WIDTH * 2.)
 9843                    .px_1p5()
 9844                    .gap_1()
 9845                    // Workaround: For some reason, there's a gap if we don't do this
 9846                    .ml(-BORDER_WIDTH)
 9847                    .shadow(vec![gpui::BoxShadow {
 9848                        color: gpui::black().opacity(0.05),
 9849                        offset: point(px(1.), px(1.)),
 9850                        blur_radius: px(2.),
 9851                        spread_radius: px(0.),
 9852                    }])
 9853                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9854                    .border(BORDER_WIDTH)
 9855                    .border_color(cx.theme().colors().border)
 9856                    .rounded_r_lg()
 9857                    .id("edit_prediction_diff_popover_keybind")
 9858                    .when(!has_keybind, |el| {
 9859                        let status_colors = cx.theme().status();
 9860
 9861                        el.bg(status_colors.error_background)
 9862                            .border_color(status_colors.error.opacity(0.6))
 9863                            .child(Icon::new(IconName::Info).color(Color::Error))
 9864                            .cursor_default()
 9865                            .hoverable_tooltip(move |_window, cx| {
 9866                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9867                            })
 9868                    })
 9869                    .children(keybind),
 9870            )
 9871            .into_any();
 9872
 9873        let longest_row =
 9874            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9875        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9876            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9877        } else {
 9878            layout_line(
 9879                longest_row,
 9880                editor_snapshot,
 9881                style,
 9882                editor_width,
 9883                |_| false,
 9884                window,
 9885                cx,
 9886            )
 9887            .width
 9888        };
 9889
 9890        let viewport_bounds =
 9891            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9892                right: -right_margin,
 9893                ..Default::default()
 9894            });
 9895
 9896        let x_after_longest = Pixels::from(
 9897            ScrollPixelOffset::from(
 9898                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9899            ) - scroll_pixel_position.x,
 9900        );
 9901
 9902        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9903
 9904        // Fully visible if it can be displayed within the window (allow overlapping other
 9905        // panes). However, this is only allowed if the popover starts within text_bounds.
 9906        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9907            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9908
 9909        let mut origin = if can_position_to_the_right {
 9910            point(
 9911                x_after_longest,
 9912                text_bounds.origin.y
 9913                    + Pixels::from(
 9914                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9915                            - scroll_pixel_position.y,
 9916                    ),
 9917            )
 9918        } else {
 9919            let cursor_row = newest_selection_head.map(|head| head.row());
 9920            let above_edit = edit_start
 9921                .row()
 9922                .0
 9923                .checked_sub(line_count as u32)
 9924                .map(DisplayRow);
 9925            let below_edit = Some(edit_end.row() + 1);
 9926            let above_cursor =
 9927                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9928            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9929
 9930            // Place the edit popover adjacent to the edit if there is a location
 9931            // available that is onscreen and does not obscure the cursor. Otherwise,
 9932            // place it adjacent to the cursor.
 9933            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9934                .into_iter()
 9935                .flatten()
 9936                .find(|&start_row| {
 9937                    let end_row = start_row + line_count as u32;
 9938                    visible_row_range.contains(&start_row)
 9939                        && visible_row_range.contains(&end_row)
 9940                        && cursor_row
 9941                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9942                })?;
 9943
 9944            content_origin
 9945                + point(
 9946                    Pixels::from(-scroll_pixel_position.x),
 9947                    Pixels::from(
 9948                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9949                    ),
 9950                )
 9951        };
 9952
 9953        origin.x -= BORDER_WIDTH;
 9954
 9955        window.with_content_mask(
 9956            Some(gpui::ContentMask {
 9957                bounds: *text_bounds,
 9958            }),
 9959            |window| {
 9960                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9961            },
 9962        );
 9963
 9964        // Do not return an element, since it will already be drawn due to defer_draw.
 9965        None
 9966    }
 9967
 9968    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9969        px(30.)
 9970    }
 9971
 9972    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9973        if self.read_only(cx) {
 9974            cx.theme().players().read_only()
 9975        } else {
 9976            self.style.as_ref().unwrap().local_player
 9977        }
 9978    }
 9979
 9980    fn render_edit_prediction_inline_keystroke(
 9981        &self,
 9982        keystroke: &gpui::KeybindingKeystroke,
 9983        modifiers_color: Color,
 9984        cx: &App,
 9985    ) -> AnyElement {
 9986        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9987
 9988        h_flex()
 9989            .px_0p5()
 9990            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9991            .font(
 9992                theme_settings::ThemeSettings::get_global(cx)
 9993                    .buffer_font
 9994                    .clone(),
 9995            )
 9996            .text_size(TextSize::XSmall.rems(cx))
 9997            .child(h_flex().children(ui::render_modifiers(
 9998                keystroke.modifiers(),
 9999                PlatformStyle::platform(),
10000                Some(modifiers_color),
10001                Some(IconSize::XSmall.rems().into()),
10002                true,
10003            )))
10004            .when(is_platform_style_mac, |parent| {
10005                parent.child(keystroke.key().to_string())
10006            })
10007            .when(!is_platform_style_mac, |parent| {
10008                parent.child(
10009                    Key::new(ui::utils::capitalize(keystroke.key()), Some(Color::Default))
10010                        .size(Some(IconSize::XSmall.rems().into())),
10011                )
10012            })
10013            .into_any()
10014    }
10015
10016    fn render_edit_prediction_popover_keystroke(
10017        &self,
10018        keystroke: &gpui::KeybindingKeystroke,
10019        color: Color,
10020        cx: &App,
10021    ) -> AnyElement {
10022        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10023
10024        if keystroke.modifiers().modified() {
10025            h_flex()
10026                .font(
10027                    theme_settings::ThemeSettings::get_global(cx)
10028                        .buffer_font
10029                        .clone(),
10030                )
10031                .when(is_platform_style_mac, |parent| parent.gap_1())
10032                .child(h_flex().children(ui::render_modifiers(
10033                    keystroke.modifiers(),
10034                    PlatformStyle::platform(),
10035                    Some(color),
10036                    None,
10037                    false,
10038                )))
10039                .into_any()
10040        } else {
10041            Key::new(ui::utils::capitalize(keystroke.key()), Some(color))
10042                .size(Some(IconSize::XSmall.rems().into()))
10043                .into_any_element()
10044        }
10045    }
10046
10047    fn render_edit_prediction_keybind(
10048        &self,
10049        window: &mut Window,
10050        cx: &mut App,
10051    ) -> Option<AnyElement> {
10052        let keybind_display =
10053            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
10054        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
10055
10056        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
10057            Color::Accent
10058        } else {
10059            Color::Muted
10060        };
10061
10062        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
10063    }
10064
10065    fn render_edit_prediction_line_popover(
10066        &self,
10067        label: impl Into<SharedString>,
10068        icon: Option<IconName>,
10069        window: &mut Window,
10070        cx: &mut App,
10071    ) -> Stateful<Div> {
10072        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10073
10074        let keybind = self.render_edit_prediction_keybind(window, cx);
10075        let has_keybind = keybind.is_some();
10076        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10077
10078        h_flex()
10079            .id("ep-line-popover")
10080            .py_0p5()
10081            .pl_1()
10082            .pr(padding_right)
10083            .gap_1()
10084            .rounded_md()
10085            .border_1()
10086            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10087            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10088            .shadow_xs()
10089            .when(!has_keybind, |el| {
10090                let status_colors = cx.theme().status();
10091
10092                el.bg(status_colors.error_background)
10093                    .border_color(status_colors.error.opacity(0.6))
10094                    .pl_2()
10095                    .child(Icon::new(icons.error).color(Color::Error))
10096                    .cursor_default()
10097                    .hoverable_tooltip(move |_window, cx| {
10098                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10099                    })
10100            })
10101            .children(keybind)
10102            .child(
10103                Label::new(label)
10104                    .size(LabelSize::Small)
10105                    .when(!has_keybind, |el| {
10106                        el.color(cx.theme().status().error.into()).strikethrough()
10107                    }),
10108            )
10109            .when(!has_keybind, |el| {
10110                el.child(
10111                    h_flex().ml_1().child(
10112                        Icon::new(IconName::Info)
10113                            .size(IconSize::Small)
10114                            .color(cx.theme().status().error.into()),
10115                    ),
10116                )
10117            })
10118            .when_some(icon, |element, icon| {
10119                element.child(
10120                    div()
10121                        .mt(px(1.5))
10122                        .child(Icon::new(icon).size(IconSize::Small)),
10123                )
10124            })
10125    }
10126
10127    fn render_edit_prediction_jump_outside_popover(
10128        &self,
10129        snapshot: &BufferSnapshot,
10130        window: &mut Window,
10131        cx: &mut App,
10132    ) -> Stateful<Div> {
10133        let keybind = self.render_edit_prediction_keybind(window, cx);
10134        let has_keybind = keybind.is_some();
10135        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10136
10137        let file_name = snapshot
10138            .file()
10139            .map(|file| SharedString::new(file.file_name(cx)))
10140            .unwrap_or(SharedString::new_static("untitled"));
10141
10142        h_flex()
10143            .id("ep-jump-outside-popover")
10144            .py_1()
10145            .px_2()
10146            .gap_1()
10147            .rounded_md()
10148            .border_1()
10149            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10150            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10151            .shadow_xs()
10152            .when(!has_keybind, |el| {
10153                let status_colors = cx.theme().status();
10154
10155                el.bg(status_colors.error_background)
10156                    .border_color(status_colors.error.opacity(0.6))
10157                    .pl_2()
10158                    .child(Icon::new(icons.error).color(Color::Error))
10159                    .cursor_default()
10160                    .hoverable_tooltip(move |_window, cx| {
10161                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10162                    })
10163            })
10164            .children(keybind)
10165            .child(
10166                Label::new(file_name)
10167                    .size(LabelSize::Small)
10168                    .buffer_font(cx)
10169                    .when(!has_keybind, |el| {
10170                        el.color(cx.theme().status().error.into()).strikethrough()
10171                    }),
10172            )
10173            .when(!has_keybind, |el| {
10174                el.child(
10175                    h_flex().ml_1().child(
10176                        Icon::new(IconName::Info)
10177                            .size(IconSize::Small)
10178                            .color(cx.theme().status().error.into()),
10179                    ),
10180                )
10181            })
10182            .child(
10183                div()
10184                    .mt(px(1.5))
10185                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10186            )
10187    }
10188
10189    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10190        let accent_color = cx.theme().colors().text_accent;
10191        let editor_bg_color = cx.theme().colors().editor_background;
10192        editor_bg_color.blend(accent_color.opacity(0.1))
10193    }
10194
10195    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
10196        let accent_color = cx.theme().colors().text_accent;
10197        let editor_bg_color = cx.theme().colors().editor_background;
10198        editor_bg_color.blend(accent_color.opacity(0.6))
10199    }
10200    fn get_prediction_provider_icons(
10201        provider: &Option<RegisteredEditPredictionDelegate>,
10202        cx: &App,
10203    ) -> edit_prediction_types::EditPredictionIconSet {
10204        match provider {
10205            Some(provider) => provider.provider.icons(cx),
10206            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10207        }
10208    }
10209
10210    fn render_edit_prediction_cursor_popover(
10211        &self,
10212        min_width: Pixels,
10213        max_width: Pixels,
10214        cursor_point: Point,
10215        style: &EditorStyle,
10216        window: &mut Window,
10217        cx: &mut Context<Editor>,
10218    ) -> Option<AnyElement> {
10219        let provider = self.edit_prediction_provider.as_ref()?;
10220        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10221
10222        let is_refreshing = provider.provider.is_refreshing(cx);
10223
10224        fn pending_completion_container(icon: IconName) -> Div {
10225            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10226        }
10227
10228        let completion = match &self.active_edit_prediction {
10229            Some(prediction) => {
10230                if !self.has_visible_completions_menu() {
10231                    const RADIUS: Pixels = px(6.);
10232                    const BORDER_WIDTH: Pixels = px(1.);
10233                    let keybind_display = self.edit_prediction_keybind_display(
10234                        EditPredictionKeybindSurface::CursorPopoverCompact,
10235                        window,
10236                        cx,
10237                    );
10238
10239                    return Some(
10240                        h_flex()
10241                            .elevation_2(cx)
10242                            .border(BORDER_WIDTH)
10243                            .border_color(cx.theme().colors().border)
10244                            .when(keybind_display.missing_accept_keystroke, |el| {
10245                                el.border_color(cx.theme().status().error)
10246                            })
10247                            .rounded(RADIUS)
10248                            .rounded_tl(px(0.))
10249                            .overflow_hidden()
10250                            .child(div().px_1p5().child(match &prediction.completion {
10251                                EditPrediction::MoveWithin { target, snapshot } => {
10252                                    use text::ToPoint as _;
10253                                    if target.text_anchor_in(&snapshot).to_point(snapshot).row
10254                                        > cursor_point.row
10255                                    {
10256                                        Icon::new(icons.down)
10257                                    } else {
10258                                        Icon::new(icons.up)
10259                                    }
10260                                }
10261                                EditPrediction::MoveOutside { .. } => {
10262                                    // TODO [zeta2] custom icon for external jump?
10263                                    Icon::new(icons.base)
10264                                }
10265                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10266                            }))
10267                            .child(
10268                                h_flex()
10269                                    .gap_1()
10270                                    .py_1()
10271                                    .px_2()
10272                                    .rounded_r(RADIUS - BORDER_WIDTH)
10273                                    .border_l_1()
10274                                    .border_color(cx.theme().colors().border)
10275                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10276                                    .when(keybind_display.show_hold_label, |el| {
10277                                        el.child(
10278                                            Label::new("Hold")
10279                                                .size(LabelSize::Small)
10280                                                .when(
10281                                                    keybind_display.missing_accept_keystroke,
10282                                                    |el| el.strikethrough(),
10283                                                )
10284                                                .line_height_style(LineHeightStyle::UiLabel),
10285                                        )
10286                                    })
10287                                    .id("edit_prediction_cursor_popover_keybind")
10288                                    .when(keybind_display.missing_accept_keystroke, |el| {
10289                                        let status_colors = cx.theme().status();
10290
10291                                        el.bg(status_colors.error_background)
10292                                            .border_color(status_colors.error.opacity(0.6))
10293                                            .child(Icon::new(IconName::Info).color(Color::Error))
10294                                            .cursor_default()
10295                                            .hoverable_tooltip(move |_window, cx| {
10296                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10297                                                    .into()
10298                                            })
10299                                    })
10300                                    .when_some(
10301                                        keybind_display.displayed_keystroke.as_ref(),
10302                                        |el, compact_keystroke| {
10303                                            el.child(self.render_edit_prediction_popover_keystroke(
10304                                                compact_keystroke,
10305                                                Color::Default,
10306                                                cx,
10307                                            ))
10308                                        },
10309                                    ),
10310                            )
10311                            .into_any(),
10312                    );
10313                }
10314
10315                self.render_edit_prediction_cursor_popover_preview(
10316                    prediction,
10317                    cursor_point,
10318                    style,
10319                    cx,
10320                )?
10321            }
10322
10323            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10324                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10325                    stale_completion,
10326                    cursor_point,
10327                    style,
10328                    cx,
10329                )?,
10330
10331                None => pending_completion_container(icons.base)
10332                    .child(Label::new("...").size(LabelSize::Small)),
10333            },
10334
10335            None => pending_completion_container(icons.base)
10336                .child(Label::new("...").size(LabelSize::Small)),
10337        };
10338
10339        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10340            completion
10341                .with_animation(
10342                    "loading-completion",
10343                    Animation::new(Duration::from_secs(2))
10344                        .repeat()
10345                        .with_easing(pulsating_between(0.4, 0.8)),
10346                    |label, delta| label.opacity(delta),
10347                )
10348                .into_any_element()
10349        } else {
10350            completion.into_any_element()
10351        };
10352
10353        let has_completion = self.active_edit_prediction.is_some();
10354        let keybind_display = self.edit_prediction_keybind_display(
10355            EditPredictionKeybindSurface::CursorPopoverExpanded,
10356            window,
10357            cx,
10358        );
10359
10360        Some(
10361            h_flex()
10362                .min_w(min_width)
10363                .max_w(max_width)
10364                .flex_1()
10365                .elevation_2(cx)
10366                .border_color(cx.theme().colors().border)
10367                .child(
10368                    div()
10369                        .flex_1()
10370                        .py_1()
10371                        .px_2()
10372                        .overflow_hidden()
10373                        .child(completion),
10374                )
10375                .when_some(
10376                    keybind_display.displayed_keystroke.as_ref(),
10377                    |el, keystroke| {
10378                        let key_color = if !has_completion {
10379                            Color::Muted
10380                        } else {
10381                            Color::Default
10382                        };
10383
10384                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10385                            el.child(
10386                                h_flex()
10387                                    .h_full()
10388                                    .border_l_1()
10389                                    .rounded_r_lg()
10390                                    .border_color(cx.theme().colors().border)
10391                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10392                                    .gap_1()
10393                                    .py_1()
10394                                    .px_2()
10395                                    .child(self.render_edit_prediction_popover_keystroke(
10396                                        keystroke, key_color, cx,
10397                                    ))
10398                                    .child(Label::new("Preview").into_any_element())
10399                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10400                            )
10401                        } else {
10402                            el.child(
10403                                h_flex()
10404                                    .h_full()
10405                                    .border_l_1()
10406                                    .rounded_r_lg()
10407                                    .border_color(cx.theme().colors().border)
10408                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10409                                    .gap_1()
10410                                    .py_1()
10411                                    .px_2()
10412                                    .child(self.render_edit_prediction_popover_keystroke(
10413                                        keystroke, key_color, cx,
10414                                    ))
10415                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10416                            )
10417                        }
10418                    },
10419                )
10420                .into_any(),
10421        )
10422    }
10423
10424    fn render_edit_prediction_cursor_popover_preview(
10425        &self,
10426        completion: &EditPredictionState,
10427        cursor_point: Point,
10428        style: &EditorStyle,
10429        cx: &mut Context<Editor>,
10430    ) -> Option<Div> {
10431        use text::ToPoint as _;
10432
10433        fn render_relative_row_jump(
10434            prefix: impl Into<String>,
10435            current_row: u32,
10436            target_row: u32,
10437        ) -> Div {
10438            let (row_diff, arrow) = if target_row < current_row {
10439                (current_row - target_row, IconName::ArrowUp)
10440            } else {
10441                (target_row - current_row, IconName::ArrowDown)
10442            };
10443
10444            h_flex()
10445                .child(
10446                    Label::new(format!("{}{}", prefix.into(), row_diff))
10447                        .color(Color::Muted)
10448                        .size(LabelSize::Small),
10449                )
10450                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10451        }
10452
10453        let supports_jump = self
10454            .edit_prediction_provider
10455            .as_ref()
10456            .map(|provider| provider.provider.supports_jump_to_edit())
10457            .unwrap_or(true);
10458
10459        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10460
10461        match &completion.completion {
10462            EditPrediction::MoveWithin {
10463                target, snapshot, ..
10464            } => {
10465                if !supports_jump {
10466                    return None;
10467                }
10468                let (target, _) = self.display_snapshot(cx).anchor_to_buffer_anchor(*target)?;
10469
10470                Some(
10471                    h_flex()
10472                        .px_2()
10473                        .gap_2()
10474                        .flex_1()
10475                        .child(if target.to_point(snapshot).row > cursor_point.row {
10476                            Icon::new(icons.down)
10477                        } else {
10478                            Icon::new(icons.up)
10479                        })
10480                        .child(Label::new("Jump to Edit")),
10481                )
10482            }
10483            EditPrediction::MoveOutside { snapshot, .. } => {
10484                let file_name = snapshot
10485                    .file()
10486                    .map(|file| file.file_name(cx))
10487                    .unwrap_or("untitled");
10488                Some(
10489                    h_flex()
10490                        .px_2()
10491                        .gap_2()
10492                        .flex_1()
10493                        .child(Icon::new(icons.base))
10494                        .child(Label::new(format!("Jump to {file_name}"))),
10495                )
10496            }
10497            EditPrediction::Edit {
10498                edits,
10499                edit_preview,
10500                snapshot,
10501                ..
10502            } => {
10503                let first_edit_row = self
10504                    .display_snapshot(cx)
10505                    .anchor_to_buffer_anchor(edits.first()?.0.start)?
10506                    .0
10507                    .to_point(snapshot)
10508                    .row;
10509
10510                let (highlighted_edits, has_more_lines) =
10511                    if let Some(edit_preview) = edit_preview.as_ref() {
10512                        crate::edit_prediction_edit_text(
10513                            snapshot,
10514                            edits,
10515                            edit_preview,
10516                            true,
10517                            &self.display_snapshot(cx),
10518                            cx,
10519                        )
10520                        .first_line_preview()
10521                    } else {
10522                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10523                    };
10524
10525                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10526                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10527
10528                let preview = h_flex()
10529                    .gap_1()
10530                    .min_w_16()
10531                    .child(styled_text)
10532                    .when(has_more_lines, |parent| parent.child(""));
10533
10534                let left = if supports_jump && first_edit_row != cursor_point.row {
10535                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10536                        .into_any_element()
10537                } else {
10538                    Icon::new(icons.base).into_any_element()
10539                };
10540
10541                Some(
10542                    h_flex()
10543                        .h_full()
10544                        .flex_1()
10545                        .gap_2()
10546                        .pr_1()
10547                        .overflow_x_hidden()
10548                        .font(
10549                            theme_settings::ThemeSettings::get_global(cx)
10550                                .buffer_font
10551                                .clone(),
10552                        )
10553                        .child(left)
10554                        .child(preview),
10555                )
10556            }
10557        }
10558    }
10559
10560    pub fn render_context_menu(
10561        &mut self,
10562        max_height_in_lines: u32,
10563        window: &mut Window,
10564        cx: &mut Context<Editor>,
10565    ) -> Option<AnyElement> {
10566        let menu = self.context_menu.borrow();
10567        let menu = menu.as_ref()?;
10568        if !menu.visible() {
10569            return None;
10570        };
10571        self.style
10572            .as_ref()
10573            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10574    }
10575
10576    fn render_context_menu_aside(
10577        &mut self,
10578        max_size: Size<Pixels>,
10579        window: &mut Window,
10580        cx: &mut Context<Editor>,
10581    ) -> Option<AnyElement> {
10582        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10583            if menu.visible() {
10584                menu.render_aside(max_size, window, cx)
10585            } else {
10586                None
10587            }
10588        })
10589    }
10590
10591    fn hide_context_menu(
10592        &mut self,
10593        window: &mut Window,
10594        cx: &mut Context<Self>,
10595    ) -> Option<CodeContextMenu> {
10596        cx.notify();
10597        self.completion_tasks.clear();
10598        let context_menu = self.context_menu.borrow_mut().take();
10599        self.stale_edit_prediction_in_menu.take();
10600        self.update_visible_edit_prediction(window, cx);
10601        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10602            && let Some(completion_provider) = &self.completion_provider
10603        {
10604            completion_provider.selection_changed(None, window, cx);
10605        }
10606        context_menu
10607    }
10608
10609    fn show_snippet_choices(
10610        &mut self,
10611        choices: &Vec<String>,
10612        selection: Range<Anchor>,
10613        cx: &mut Context<Self>,
10614    ) {
10615        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
10616        let Some((buffer_snapshot, range)) =
10617            buffer_snapshot.anchor_range_to_buffer_anchor_range(selection.clone())
10618        else {
10619            return;
10620        };
10621        let Some(buffer) = self.buffer.read(cx).buffer(buffer_snapshot.remote_id()) else {
10622            return;
10623        };
10624
10625        let id = post_inc(&mut self.next_completion_id);
10626        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10627        let mut context_menu = self.context_menu.borrow_mut();
10628        let old_menu = context_menu.take();
10629        *context_menu = Some(CodeContextMenu::Completions(
10630            CompletionsMenu::new_snippet_choices(
10631                id,
10632                true,
10633                choices,
10634                selection.start,
10635                range,
10636                buffer,
10637                old_menu.map(|menu| menu.primary_scroll_handle()),
10638                snippet_sort_order,
10639            ),
10640        ));
10641    }
10642
10643    pub fn insert_snippet(
10644        &mut self,
10645        insertion_ranges: &[Range<MultiBufferOffset>],
10646        snippet: Snippet,
10647        window: &mut Window,
10648        cx: &mut Context<Self>,
10649    ) -> Result<()> {
10650        struct Tabstop<T> {
10651            is_end_tabstop: bool,
10652            ranges: Vec<Range<T>>,
10653            choices: Option<Vec<String>>,
10654        }
10655
10656        let tabstops = self.buffer.update(cx, |buffer, cx| {
10657            let snippet_text: Arc<str> = snippet.text.clone().into();
10658            let edits = insertion_ranges
10659                .iter()
10660                .cloned()
10661                .map(|range| (range, snippet_text.clone()));
10662            let autoindent_mode = AutoindentMode::Block {
10663                original_indent_columns: Vec::new(),
10664            };
10665            buffer.edit(edits, Some(autoindent_mode), cx);
10666
10667            let snapshot = &*buffer.read(cx);
10668            let snippet = &snippet;
10669            snippet
10670                .tabstops
10671                .iter()
10672                .map(|tabstop| {
10673                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10674                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10675                    });
10676                    let mut tabstop_ranges = tabstop
10677                        .ranges
10678                        .iter()
10679                        .flat_map(|tabstop_range| {
10680                            let mut delta = 0_isize;
10681                            insertion_ranges.iter().map(move |insertion_range| {
10682                                let insertion_start = insertion_range.start + delta;
10683                                delta += snippet.text.len() as isize
10684                                    - (insertion_range.end - insertion_range.start) as isize;
10685
10686                                let start =
10687                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10688                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10689                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10690                            })
10691                        })
10692                        .collect::<Vec<_>>();
10693                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10694
10695                    Tabstop {
10696                        is_end_tabstop,
10697                        ranges: tabstop_ranges,
10698                        choices: tabstop.choices.clone(),
10699                    }
10700                })
10701                .collect::<Vec<_>>()
10702        });
10703        if let Some(tabstop) = tabstops.first() {
10704            self.change_selections(Default::default(), window, cx, |s| {
10705                // Reverse order so that the first range is the newest created selection.
10706                // Completions will use it and autoscroll will prioritize it.
10707                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10708            });
10709
10710            if let Some(choices) = &tabstop.choices
10711                && let Some(selection) = tabstop.ranges.first()
10712            {
10713                self.show_snippet_choices(choices, selection.clone(), cx)
10714            }
10715
10716            // If we're already at the last tabstop and it's at the end of the snippet,
10717            // we're done, we don't need to keep the state around.
10718            if !tabstop.is_end_tabstop {
10719                let choices = tabstops
10720                    .iter()
10721                    .map(|tabstop| tabstop.choices.clone())
10722                    .collect();
10723
10724                let ranges = tabstops
10725                    .into_iter()
10726                    .map(|tabstop| tabstop.ranges)
10727                    .collect::<Vec<_>>();
10728
10729                self.snippet_stack.push(SnippetState {
10730                    active_index: 0,
10731                    ranges,
10732                    choices,
10733                });
10734            }
10735
10736            // Check whether the just-entered snippet ends with an auto-closable bracket.
10737            if self.autoclose_regions.is_empty() {
10738                let snapshot = self.buffer.read(cx).snapshot(cx);
10739                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10740                    let selection_head = selection.head();
10741                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10742                        continue;
10743                    };
10744
10745                    let mut bracket_pair = None;
10746                    let max_lookup_length = scope
10747                        .brackets()
10748                        .map(|(pair, _)| {
10749                            pair.start
10750                                .as_str()
10751                                .chars()
10752                                .count()
10753                                .max(pair.end.as_str().chars().count())
10754                        })
10755                        .max();
10756                    if let Some(max_lookup_length) = max_lookup_length {
10757                        let next_text = snapshot
10758                            .chars_at(selection_head)
10759                            .take(max_lookup_length)
10760                            .collect::<String>();
10761                        let prev_text = snapshot
10762                            .reversed_chars_at(selection_head)
10763                            .take(max_lookup_length)
10764                            .collect::<String>();
10765
10766                        for (pair, enabled) in scope.brackets() {
10767                            if enabled
10768                                && pair.close
10769                                && prev_text.starts_with(pair.start.as_str())
10770                                && next_text.starts_with(pair.end.as_str())
10771                            {
10772                                bracket_pair = Some(pair.clone());
10773                                break;
10774                            }
10775                        }
10776                    }
10777
10778                    if let Some(pair) = bracket_pair {
10779                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10780                        let autoclose_enabled =
10781                            self.use_autoclose && snapshot_settings.use_autoclose;
10782                        if autoclose_enabled {
10783                            let start = snapshot.anchor_after(selection_head);
10784                            let end = snapshot.anchor_after(selection_head);
10785                            self.autoclose_regions.push(AutocloseRegion {
10786                                selection_id: selection.id,
10787                                range: start..end,
10788                                pair,
10789                            });
10790                        }
10791                    }
10792                }
10793            }
10794        }
10795        Ok(())
10796    }
10797
10798    pub fn move_to_next_snippet_tabstop(
10799        &mut self,
10800        window: &mut Window,
10801        cx: &mut Context<Self>,
10802    ) -> bool {
10803        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10804    }
10805
10806    pub fn move_to_prev_snippet_tabstop(
10807        &mut self,
10808        window: &mut Window,
10809        cx: &mut Context<Self>,
10810    ) -> bool {
10811        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10812    }
10813
10814    pub fn move_to_snippet_tabstop(
10815        &mut self,
10816        bias: Bias,
10817        window: &mut Window,
10818        cx: &mut Context<Self>,
10819    ) -> bool {
10820        if let Some(mut snippet) = self.snippet_stack.pop() {
10821            match bias {
10822                Bias::Left => {
10823                    if snippet.active_index > 0 {
10824                        snippet.active_index -= 1;
10825                    } else {
10826                        self.snippet_stack.push(snippet);
10827                        return false;
10828                    }
10829                }
10830                Bias::Right => {
10831                    if snippet.active_index + 1 < snippet.ranges.len() {
10832                        snippet.active_index += 1;
10833                    } else {
10834                        self.snippet_stack.push(snippet);
10835                        return false;
10836                    }
10837                }
10838            }
10839            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10840                self.change_selections(Default::default(), window, cx, |s| {
10841                    // Reverse order so that the first range is the newest created selection.
10842                    // Completions will use it and autoscroll will prioritize it.
10843                    s.select_ranges(current_ranges.iter().rev().cloned())
10844                });
10845
10846                if let Some(choices) = &snippet.choices[snippet.active_index]
10847                    && let Some(selection) = current_ranges.first()
10848                {
10849                    self.show_snippet_choices(choices, selection.clone(), cx);
10850                }
10851
10852                // If snippet state is not at the last tabstop, push it back on the stack
10853                if snippet.active_index + 1 < snippet.ranges.len() {
10854                    self.snippet_stack.push(snippet);
10855                }
10856                return true;
10857            }
10858        }
10859
10860        false
10861    }
10862
10863    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10864        self.transact(window, cx, |this, window, cx| {
10865            this.select_all(&SelectAll, window, cx);
10866            this.insert("", window, cx);
10867        });
10868    }
10869
10870    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10871        if self.read_only(cx) {
10872            return;
10873        }
10874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10875        self.transact(window, cx, |this, window, cx| {
10876            this.select_autoclose_pair(window, cx);
10877
10878            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10879
10880            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10881            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10882            for selection in &mut selections {
10883                if selection.is_empty() {
10884                    let old_head = selection.head();
10885                    let mut new_head =
10886                        movement::left(&display_map, old_head.to_display_point(&display_map))
10887                            .to_point(&display_map);
10888                    if let Some((buffer, line_buffer_range)) = display_map
10889                        .buffer_snapshot()
10890                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10891                    {
10892                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10893                        let indent_len = match indent_size.kind {
10894                            IndentKind::Space => {
10895                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10896                            }
10897                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10898                        };
10899                        if old_head.column <= indent_size.len && old_head.column > 0 {
10900                            let indent_len = indent_len.get();
10901                            new_head = cmp::min(
10902                                new_head,
10903                                MultiBufferPoint::new(
10904                                    old_head.row,
10905                                    ((old_head.column - 1) / indent_len) * indent_len,
10906                                ),
10907                            );
10908                        }
10909                    }
10910
10911                    selection.set_head(new_head, SelectionGoal::None);
10912                }
10913            }
10914
10915            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10916            this.insert("", window, cx);
10917            linked_edits.apply_with_left_expansion(cx);
10918            this.refresh_edit_prediction(true, false, window, cx);
10919            refresh_linked_ranges(this, window, cx);
10920        });
10921    }
10922
10923    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10924        if self.read_only(cx) {
10925            return;
10926        }
10927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10928        self.transact(window, cx, |this, window, cx| {
10929            this.change_selections(Default::default(), window, cx, |s| {
10930                s.move_with(&mut |map, selection| {
10931                    if selection.is_empty() {
10932                        let cursor = movement::right(map, selection.head());
10933                        selection.end = cursor;
10934                        selection.reversed = true;
10935                        selection.goal = SelectionGoal::None;
10936                    }
10937                })
10938            });
10939            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10940            this.insert("", window, cx);
10941            linked_edits.apply(cx);
10942            this.refresh_edit_prediction(true, false, window, cx);
10943            refresh_linked_ranges(this, window, cx);
10944        });
10945    }
10946
10947    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10948        if self.mode.is_single_line() {
10949            cx.propagate();
10950            return;
10951        }
10952
10953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10954        if self.move_to_prev_snippet_tabstop(window, cx) {
10955            return;
10956        }
10957        self.outdent(&Outdent, window, cx);
10958    }
10959
10960    pub fn next_snippet_tabstop(
10961        &mut self,
10962        _: &NextSnippetTabstop,
10963        window: &mut Window,
10964        cx: &mut Context<Self>,
10965    ) {
10966        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10967            cx.propagate();
10968            return;
10969        }
10970
10971        if self.move_to_next_snippet_tabstop(window, cx) {
10972            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10973            return;
10974        }
10975        cx.propagate();
10976    }
10977
10978    pub fn previous_snippet_tabstop(
10979        &mut self,
10980        _: &PreviousSnippetTabstop,
10981        window: &mut Window,
10982        cx: &mut Context<Self>,
10983    ) {
10984        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10985            cx.propagate();
10986            return;
10987        }
10988
10989        if self.move_to_prev_snippet_tabstop(window, cx) {
10990            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10991            return;
10992        }
10993        cx.propagate();
10994    }
10995
10996    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10997        if self.mode.is_single_line() {
10998            cx.propagate();
10999            return;
11000        }
11001
11002        if self.move_to_next_snippet_tabstop(window, cx) {
11003            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11004            return;
11005        }
11006        if self.read_only(cx) {
11007            return;
11008        }
11009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11010        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
11011        let buffer = self.buffer.read(cx);
11012        let snapshot = buffer.snapshot(cx);
11013        let rows_iter = selections.iter().map(|s| s.head().row);
11014        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
11015
11016        let has_some_cursor_in_whitespace = selections
11017            .iter()
11018            .filter(|selection| selection.is_empty())
11019            .any(|selection| {
11020                let cursor = selection.head();
11021                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11022                cursor.column < current_indent.len
11023            });
11024
11025        let mut edits = Vec::new();
11026        let mut prev_edited_row = 0;
11027        let mut row_delta = 0;
11028        for selection in &mut selections {
11029            if selection.start.row != prev_edited_row {
11030                row_delta = 0;
11031            }
11032            prev_edited_row = selection.end.row;
11033
11034            // If cursor is after a list prefix, make selection non-empty to trigger line indent
11035            if selection.is_empty() {
11036                let cursor = selection.head();
11037                let settings = buffer.language_settings_at(cursor, cx);
11038                if settings.indent_list_on_tab {
11039                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
11040                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
11041                            row_delta = Self::indent_selection(
11042                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
11043                            );
11044                            continue;
11045                        }
11046                    }
11047                }
11048            }
11049
11050            // If the selection is non-empty, then increase the indentation of the selected lines.
11051            if !selection.is_empty() {
11052                row_delta =
11053                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11054                continue;
11055            }
11056
11057            let cursor = selection.head();
11058            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11059            if let Some(suggested_indent) =
11060                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
11061            {
11062                // Don't do anything if already at suggested indent
11063                // and there is any other cursor which is not
11064                if has_some_cursor_in_whitespace
11065                    && cursor.column == current_indent.len
11066                    && current_indent.len == suggested_indent.len
11067                {
11068                    continue;
11069                }
11070
11071                // Adjust line and move cursor to suggested indent
11072                // if cursor is not at suggested indent
11073                if cursor.column < suggested_indent.len
11074                    && cursor.column <= current_indent.len
11075                    && current_indent.len <= suggested_indent.len
11076                {
11077                    selection.start = Point::new(cursor.row, suggested_indent.len);
11078                    selection.end = selection.start;
11079                    if row_delta == 0 {
11080                        edits.extend(Buffer::edit_for_indent_size_adjustment(
11081                            cursor.row,
11082                            current_indent,
11083                            suggested_indent,
11084                        ));
11085                        row_delta = suggested_indent.len - current_indent.len;
11086                    }
11087                    continue;
11088                }
11089
11090                // If current indent is more than suggested indent
11091                // only move cursor to current indent and skip indent
11092                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11093                    selection.start = Point::new(cursor.row, current_indent.len);
11094                    selection.end = selection.start;
11095                    continue;
11096                }
11097            }
11098
11099            // Otherwise, insert a hard or soft tab.
11100            let settings = buffer.language_settings_at(cursor, cx);
11101            let tab_size = if settings.hard_tabs {
11102                IndentSize::tab()
11103            } else {
11104                let tab_size = settings.tab_size.get();
11105                let indent_remainder = snapshot
11106                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11107                    .flat_map(str::chars)
11108                    .fold(row_delta % tab_size, |counter: u32, c| {
11109                        if c == '\t' {
11110                            0
11111                        } else {
11112                            (counter + 1) % tab_size
11113                        }
11114                    });
11115
11116                let chars_to_next_tab_stop = tab_size - indent_remainder;
11117                IndentSize::spaces(chars_to_next_tab_stop)
11118            };
11119            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11120            selection.end = selection.start;
11121            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11122            row_delta += tab_size.len;
11123        }
11124
11125        self.transact(window, cx, |this, window, cx| {
11126            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11127            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11128            this.refresh_edit_prediction(true, false, window, cx);
11129        });
11130    }
11131
11132    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11133        if self.read_only(cx) {
11134            return;
11135        }
11136        if self.mode.is_single_line() {
11137            cx.propagate();
11138            return;
11139        }
11140
11141        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11142        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11143        let mut prev_edited_row = 0;
11144        let mut row_delta = 0;
11145        let mut edits = Vec::new();
11146        let buffer = self.buffer.read(cx);
11147        let snapshot = buffer.snapshot(cx);
11148        for selection in &mut selections {
11149            if selection.start.row != prev_edited_row {
11150                row_delta = 0;
11151            }
11152            prev_edited_row = selection.end.row;
11153
11154            row_delta =
11155                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11156        }
11157
11158        self.transact(window, cx, |this, window, cx| {
11159            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11160            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11161        });
11162    }
11163
11164    fn indent_selection(
11165        buffer: &MultiBuffer,
11166        snapshot: &MultiBufferSnapshot,
11167        selection: &mut Selection<Point>,
11168        edits: &mut Vec<(Range<Point>, String)>,
11169        delta_for_start_row: u32,
11170        cx: &App,
11171    ) -> u32 {
11172        let settings = buffer.language_settings_at(selection.start, cx);
11173        let tab_size = settings.tab_size.get();
11174        let indent_kind = if settings.hard_tabs {
11175            IndentKind::Tab
11176        } else {
11177            IndentKind::Space
11178        };
11179        let mut start_row = selection.start.row;
11180        let mut end_row = selection.end.row + 1;
11181
11182        // If a selection ends at the beginning of a line, don't indent
11183        // that last line.
11184        if selection.end.column == 0 && selection.end.row > selection.start.row {
11185            end_row -= 1;
11186        }
11187
11188        // Avoid re-indenting a row that has already been indented by a
11189        // previous selection, but still update this selection's column
11190        // to reflect that indentation.
11191        if delta_for_start_row > 0 {
11192            start_row += 1;
11193            selection.start.column += delta_for_start_row;
11194            if selection.end.row == selection.start.row {
11195                selection.end.column += delta_for_start_row;
11196            }
11197        }
11198
11199        let mut delta_for_end_row = 0;
11200        let has_multiple_rows = start_row + 1 != end_row;
11201        for row in start_row..end_row {
11202            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11203            let indent_delta = match (current_indent.kind, indent_kind) {
11204                (IndentKind::Space, IndentKind::Space) => {
11205                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11206                    IndentSize::spaces(columns_to_next_tab_stop)
11207                }
11208                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11209                (_, IndentKind::Tab) => IndentSize::tab(),
11210            };
11211
11212            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11213                0
11214            } else {
11215                selection.start.column
11216            };
11217            let row_start = Point::new(row, start);
11218            edits.push((
11219                row_start..row_start,
11220                indent_delta.chars().collect::<String>(),
11221            ));
11222
11223            // Update this selection's endpoints to reflect the indentation.
11224            if row == selection.start.row {
11225                selection.start.column += indent_delta.len;
11226            }
11227            if row == selection.end.row {
11228                selection.end.column += indent_delta.len;
11229                delta_for_end_row = indent_delta.len;
11230            }
11231        }
11232
11233        if selection.start.row == selection.end.row {
11234            delta_for_start_row + delta_for_end_row
11235        } else {
11236            delta_for_end_row
11237        }
11238    }
11239
11240    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11241        if self.read_only(cx) {
11242            return;
11243        }
11244        if self.mode.is_single_line() {
11245            cx.propagate();
11246            return;
11247        }
11248
11249        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11251        let selections = self.selections.all::<Point>(&display_map);
11252        let mut deletion_ranges = Vec::new();
11253        let mut last_outdent = None;
11254        {
11255            let buffer = self.buffer.read(cx);
11256            let snapshot = buffer.snapshot(cx);
11257            for selection in &selections {
11258                let settings = buffer.language_settings_at(selection.start, cx);
11259                let tab_size = settings.tab_size.get();
11260                let mut rows = selection.spanned_rows(false, &display_map);
11261
11262                // Avoid re-outdenting a row that has already been outdented by a
11263                // previous selection.
11264                if let Some(last_row) = last_outdent
11265                    && last_row == rows.start
11266                {
11267                    rows.start = rows.start.next_row();
11268                }
11269                let has_multiple_rows = rows.len() > 1;
11270                for row in rows.iter_rows() {
11271                    let indent_size = snapshot.indent_size_for_line(row);
11272                    if indent_size.len > 0 {
11273                        let deletion_len = match indent_size.kind {
11274                            IndentKind::Space => {
11275                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11276                                if columns_to_prev_tab_stop == 0 {
11277                                    tab_size
11278                                } else {
11279                                    columns_to_prev_tab_stop
11280                                }
11281                            }
11282                            IndentKind::Tab => 1,
11283                        };
11284                        let start = if has_multiple_rows
11285                            || deletion_len > selection.start.column
11286                            || indent_size.len < selection.start.column
11287                        {
11288                            0
11289                        } else {
11290                            selection.start.column - deletion_len
11291                        };
11292                        deletion_ranges.push(
11293                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11294                        );
11295                        last_outdent = Some(row);
11296                    }
11297                }
11298            }
11299        }
11300
11301        self.transact(window, cx, |this, window, cx| {
11302            this.buffer.update(cx, |buffer, cx| {
11303                let empty_str: Arc<str> = Arc::default();
11304                buffer.edit(
11305                    deletion_ranges
11306                        .into_iter()
11307                        .map(|range| (range, empty_str.clone())),
11308                    None,
11309                    cx,
11310                );
11311            });
11312            let selections = this
11313                .selections
11314                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11315            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11316        });
11317    }
11318
11319    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11320        if self.read_only(cx) {
11321            return;
11322        }
11323        if self.mode.is_single_line() {
11324            cx.propagate();
11325            return;
11326        }
11327
11328        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11329        let selections = self
11330            .selections
11331            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11332            .into_iter()
11333            .map(|s| s.range());
11334
11335        self.transact(window, cx, |this, window, cx| {
11336            this.buffer.update(cx, |buffer, cx| {
11337                buffer.autoindent_ranges(selections, cx);
11338            });
11339            let selections = this
11340                .selections
11341                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11342            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11343        });
11344    }
11345
11346    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11347        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11349        let selections = self.selections.all::<Point>(&display_map);
11350
11351        let mut new_cursors = Vec::new();
11352        let mut edit_ranges = Vec::new();
11353        let mut selections = selections.iter().peekable();
11354        while let Some(selection) = selections.next() {
11355            let mut rows = selection.spanned_rows(false, &display_map);
11356
11357            // Accumulate contiguous regions of rows that we want to delete.
11358            while let Some(next_selection) = selections.peek() {
11359                let next_rows = next_selection.spanned_rows(false, &display_map);
11360                if next_rows.start <= rows.end {
11361                    rows.end = next_rows.end;
11362                    selections.next().unwrap();
11363                } else {
11364                    break;
11365                }
11366            }
11367
11368            let buffer = display_map.buffer_snapshot();
11369            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11370            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11371                // If there's a line after the range, delete the \n from the end of the row range
11372                (
11373                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11374                    rows.end,
11375                )
11376            } else {
11377                // If there isn't a line after the range, delete the \n from the line before the
11378                // start of the row range
11379                edit_start = edit_start.saturating_sub_usize(1);
11380                (buffer.len(), rows.start.previous_row())
11381            };
11382
11383            let text_layout_details = self.text_layout_details(window, cx);
11384            let x = display_map.x_for_display_point(
11385                selection.head().to_display_point(&display_map),
11386                &text_layout_details,
11387            );
11388            let row = Point::new(target_row.0, 0)
11389                .to_display_point(&display_map)
11390                .row();
11391            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11392
11393            new_cursors.push((
11394                selection.id,
11395                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11396                SelectionGoal::None,
11397            ));
11398            edit_ranges.push(edit_start..edit_end);
11399        }
11400
11401        self.transact(window, cx, |this, window, cx| {
11402            let buffer = this.buffer.update(cx, |buffer, cx| {
11403                let empty_str: Arc<str> = Arc::default();
11404                buffer.edit(
11405                    edit_ranges
11406                        .into_iter()
11407                        .map(|range| (range, empty_str.clone())),
11408                    None,
11409                    cx,
11410                );
11411                buffer.snapshot(cx)
11412            });
11413            let new_selections = new_cursors
11414                .into_iter()
11415                .map(|(id, cursor, goal)| {
11416                    let cursor = cursor.to_point(&buffer);
11417                    Selection {
11418                        id,
11419                        start: cursor,
11420                        end: cursor,
11421                        reversed: false,
11422                        goal,
11423                    }
11424                })
11425                .collect();
11426
11427            this.change_selections(Default::default(), window, cx, |s| {
11428                s.select(new_selections);
11429            });
11430        });
11431    }
11432
11433    pub fn join_lines_impl(
11434        &mut self,
11435        insert_whitespace: bool,
11436        window: &mut Window,
11437        cx: &mut Context<Self>,
11438    ) {
11439        if self.read_only(cx) {
11440            return;
11441        }
11442        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11443        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11444            let start = MultiBufferRow(selection.start.row);
11445            // Treat single line selections as if they include the next line. Otherwise this action
11446            // would do nothing for single line selections individual cursors.
11447            let end = if selection.start.row == selection.end.row {
11448                MultiBufferRow(selection.start.row + 1)
11449            } else if selection.end.column == 0 {
11450                // If the selection ends at the start of a line, it's logically at the end of the
11451                // previous line (plus its newline).
11452                // Don't include the end line unless there's only one line selected.
11453                if selection.start.row + 1 == selection.end.row {
11454                    MultiBufferRow(selection.end.row)
11455                } else {
11456                    MultiBufferRow(selection.end.row - 1)
11457                }
11458            } else {
11459                MultiBufferRow(selection.end.row)
11460            };
11461
11462            if let Some(last_row_range) = row_ranges.last_mut()
11463                && start <= last_row_range.end
11464            {
11465                last_row_range.end = end;
11466                continue;
11467            }
11468            row_ranges.push(start..end);
11469        }
11470
11471        let snapshot = self.buffer.read(cx).snapshot(cx);
11472        let mut cursor_positions = Vec::new();
11473        for row_range in &row_ranges {
11474            let anchor = snapshot.anchor_before(Point::new(
11475                row_range.end.previous_row().0,
11476                snapshot.line_len(row_range.end.previous_row()),
11477            ));
11478            cursor_positions.push(anchor..anchor);
11479        }
11480
11481        self.transact(window, cx, |this, window, cx| {
11482            for row_range in row_ranges.into_iter().rev() {
11483                for row in row_range.iter_rows().rev() {
11484                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11485                    let next_line_row = row.next_row();
11486                    let indent = snapshot.indent_size_for_line(next_line_row);
11487                    let mut join_start_column = indent.len;
11488
11489                    if let Some(language_scope) =
11490                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11491                    {
11492                        let line_end =
11493                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11494                        let line_text_after_indent = snapshot
11495                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11496                            .collect::<String>();
11497
11498                        if !line_text_after_indent.is_empty() {
11499                            let block_prefix = language_scope
11500                                .block_comment()
11501                                .map(|c| c.prefix.as_ref())
11502                                .filter(|p| !p.is_empty());
11503                            let doc_prefix = language_scope
11504                                .documentation_comment()
11505                                .map(|c| c.prefix.as_ref())
11506                                .filter(|p| !p.is_empty());
11507                            let all_prefixes = language_scope
11508                                .line_comment_prefixes()
11509                                .iter()
11510                                .map(|p| p.as_ref())
11511                                .chain(block_prefix)
11512                                .chain(doc_prefix)
11513                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11514
11515                            let mut longest_prefix_len = None;
11516                            for prefix in all_prefixes {
11517                                let trimmed = prefix.trim_end();
11518                                if line_text_after_indent.starts_with(trimmed) {
11519                                    let candidate_len =
11520                                        if line_text_after_indent.starts_with(prefix) {
11521                                            prefix.len()
11522                                        } else {
11523                                            trimmed.len()
11524                                        };
11525                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11526                                        longest_prefix_len = Some(candidate_len);
11527                                    }
11528                                }
11529                            }
11530
11531                            if let Some(prefix_len) = longest_prefix_len {
11532                                join_start_column =
11533                                    join_start_column.saturating_add(prefix_len as u32);
11534                            }
11535                        }
11536                    }
11537
11538                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11539
11540                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11541                        && insert_whitespace
11542                    {
11543                        " "
11544                    } else {
11545                        ""
11546                    };
11547
11548                    this.buffer.update(cx, |buffer, cx| {
11549                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11550                    });
11551                }
11552            }
11553
11554            this.change_selections(Default::default(), window, cx, |s| {
11555                s.select_anchor_ranges(cursor_positions)
11556            });
11557        });
11558    }
11559
11560    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11561        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11562        self.join_lines_impl(true, window, cx);
11563    }
11564
11565    pub fn sort_lines_case_sensitive(
11566        &mut self,
11567        _: &SortLinesCaseSensitive,
11568        window: &mut Window,
11569        cx: &mut Context<Self>,
11570    ) {
11571        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11572    }
11573
11574    pub fn sort_lines_by_length(
11575        &mut self,
11576        _: &SortLinesByLength,
11577        window: &mut Window,
11578        cx: &mut Context<Self>,
11579    ) {
11580        self.manipulate_immutable_lines(window, cx, |lines| {
11581            lines.sort_by_key(|&line| line.chars().count())
11582        })
11583    }
11584
11585    pub fn sort_lines_case_insensitive(
11586        &mut self,
11587        _: &SortLinesCaseInsensitive,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        self.manipulate_immutable_lines(window, cx, |lines| {
11592            lines.sort_by_key(|line| line.to_lowercase())
11593        })
11594    }
11595
11596    pub fn unique_lines_case_insensitive(
11597        &mut self,
11598        _: &UniqueLinesCaseInsensitive,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.manipulate_immutable_lines(window, cx, |lines| {
11603            let mut seen = HashSet::default();
11604            lines.retain(|line| seen.insert(line.to_lowercase()));
11605        })
11606    }
11607
11608    pub fn unique_lines_case_sensitive(
11609        &mut self,
11610        _: &UniqueLinesCaseSensitive,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        self.manipulate_immutable_lines(window, cx, |lines| {
11615            let mut seen = HashSet::default();
11616            lines.retain(|line| seen.insert(*line));
11617        })
11618    }
11619
11620    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11621        let snapshot = self.buffer.read(cx).snapshot(cx);
11622        for selection in self.selections.disjoint_anchors_arc().iter() {
11623            if snapshot
11624                .language_at(selection.start)
11625                .and_then(|lang| lang.config().wrap_characters.as_ref())
11626                .is_some()
11627            {
11628                return true;
11629            }
11630        }
11631        false
11632    }
11633
11634    fn wrap_selections_in_tag(
11635        &mut self,
11636        _: &WrapSelectionsInTag,
11637        window: &mut Window,
11638        cx: &mut Context<Self>,
11639    ) {
11640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11641
11642        let snapshot = self.buffer.read(cx).snapshot(cx);
11643
11644        let mut edits = Vec::new();
11645        let mut boundaries = Vec::new();
11646
11647        for selection in self
11648            .selections
11649            .all_adjusted(&self.display_snapshot(cx))
11650            .iter()
11651        {
11652            let Some(wrap_config) = snapshot
11653                .language_at(selection.start)
11654                .and_then(|lang| lang.config().wrap_characters.clone())
11655            else {
11656                continue;
11657            };
11658
11659            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11660            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11661
11662            let start_before = snapshot.anchor_before(selection.start);
11663            let end_after = snapshot.anchor_after(selection.end);
11664
11665            edits.push((start_before..start_before, open_tag));
11666            edits.push((end_after..end_after, close_tag));
11667
11668            boundaries.push((
11669                start_before,
11670                end_after,
11671                wrap_config.start_prefix.len(),
11672                wrap_config.end_suffix.len(),
11673            ));
11674        }
11675
11676        if edits.is_empty() {
11677            return;
11678        }
11679
11680        self.transact(window, cx, |this, window, cx| {
11681            let buffer = this.buffer.update(cx, |buffer, cx| {
11682                buffer.edit(edits, None, cx);
11683                buffer.snapshot(cx)
11684            });
11685
11686            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11687            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11688                boundaries.into_iter()
11689            {
11690                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11691                let close_offset = end_after
11692                    .to_offset(&buffer)
11693                    .saturating_sub_usize(end_suffix_len);
11694                new_selections.push(open_offset..open_offset);
11695                new_selections.push(close_offset..close_offset);
11696            }
11697
11698            this.change_selections(Default::default(), window, cx, |s| {
11699                s.select_ranges(new_selections);
11700            });
11701
11702            this.request_autoscroll(Autoscroll::fit(), cx);
11703        });
11704    }
11705
11706    pub fn toggle_read_only(
11707        &mut self,
11708        _: &workspace::ToggleReadOnlyFile,
11709        _: &mut Window,
11710        cx: &mut Context<Self>,
11711    ) {
11712        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11713            buffer.update(cx, |buffer, cx| {
11714                buffer.set_capability(
11715                    match buffer.capability() {
11716                        Capability::ReadWrite => Capability::Read,
11717                        Capability::Read => Capability::ReadWrite,
11718                        Capability::ReadOnly => Capability::ReadOnly,
11719                    },
11720                    cx,
11721                );
11722            })
11723        }
11724    }
11725
11726    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11727        let Some(project) = self.project.clone() else {
11728            return;
11729        };
11730        let task = self.reload(project, window, cx);
11731        self.detach_and_notify_err(task, window, cx);
11732    }
11733
11734    pub fn restore_file(
11735        &mut self,
11736        _: &::git::RestoreFile,
11737        window: &mut Window,
11738        cx: &mut Context<Self>,
11739    ) {
11740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11741        let mut buffer_ids = HashSet::default();
11742        let snapshot = self.buffer().read(cx).snapshot(cx);
11743        for selection in self
11744            .selections
11745            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11746        {
11747            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11748        }
11749
11750        let ranges = buffer_ids
11751            .into_iter()
11752            .flat_map(|buffer_id| snapshot.range_for_buffer(buffer_id))
11753            .collect::<Vec<_>>();
11754
11755        self.restore_hunks_in_ranges(ranges, window, cx);
11756    }
11757
11758    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11760        let selections = self
11761            .selections
11762            .all(&self.display_snapshot(cx))
11763            .into_iter()
11764            .map(|s| s.range())
11765            .collect();
11766        self.restore_hunks_in_ranges(selections, window, cx);
11767    }
11768
11769    /// Restores the diff hunks in the editor's selections and moves the cursor
11770    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11771    /// not all diff hunks are expanded.
11772    pub fn restore_and_next(
11773        &mut self,
11774        _: &::git::RestoreAndNext,
11775        window: &mut Window,
11776        cx: &mut Context<Self>,
11777    ) {
11778        let selections = self
11779            .selections
11780            .all(&self.display_snapshot(cx))
11781            .into_iter()
11782            .map(|selection| selection.range())
11783            .collect();
11784
11785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11786        self.restore_hunks_in_ranges(selections, window, cx);
11787
11788        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11789        let wrap_around = !all_diff_hunks_expanded;
11790        let snapshot = self.snapshot(window, cx);
11791        let position = self
11792            .selections
11793            .newest::<Point>(&snapshot.display_snapshot)
11794            .head();
11795
11796        self.go_to_hunk_before_or_after_position(
11797            &snapshot,
11798            position,
11799            Direction::Next,
11800            wrap_around,
11801            window,
11802            cx,
11803        );
11804    }
11805
11806    pub fn restore_hunks_in_ranges(
11807        &mut self,
11808        ranges: Vec<Range<Point>>,
11809        window: &mut Window,
11810        cx: &mut Context<Editor>,
11811    ) {
11812        if self.delegate_stage_and_restore {
11813            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11814            if !hunks.is_empty() {
11815                cx.emit(EditorEvent::RestoreRequested { hunks });
11816            }
11817            return;
11818        }
11819        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11820        self.transact(window, cx, |editor, window, cx| {
11821            editor.restore_diff_hunks(hunks, cx);
11822            let selections = editor
11823                .selections
11824                .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
11825            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11826                s.select(selections);
11827            });
11828        });
11829    }
11830
11831    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11832        let mut revert_changes = HashMap::default();
11833        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11834        for (buffer_id, hunks) in &chunk_by {
11835            let hunks = hunks.collect::<Vec<_>>();
11836            for hunk in &hunks {
11837                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11838            }
11839            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11840        }
11841        if !revert_changes.is_empty() {
11842            self.buffer().update(cx, |multi_buffer, cx| {
11843                for (buffer_id, changes) in revert_changes {
11844                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11845                        buffer.update(cx, |buffer, cx| {
11846                            buffer.edit(
11847                                changes
11848                                    .into_iter()
11849                                    .map(|(range, text)| (range, text.to_string())),
11850                                None,
11851                                cx,
11852                            );
11853                        });
11854                    }
11855                }
11856            });
11857        }
11858    }
11859
11860    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11861        if let Some(status) = self
11862            .addons
11863            .iter()
11864            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11865        {
11866            return Some(status);
11867        }
11868        self.project
11869            .as_ref()?
11870            .read(cx)
11871            .status_for_buffer_id(buffer_id, cx)
11872    }
11873
11874    pub fn open_active_item_in_terminal(
11875        &mut self,
11876        _: &OpenInTerminal,
11877        window: &mut Window,
11878        cx: &mut Context<Self>,
11879    ) {
11880        if let Some(working_directory) = self.active_buffer(cx).and_then(|buffer| {
11881            let project_path = buffer.read(cx).project_path(cx)?;
11882            let project = self.project()?.read(cx);
11883            let entry = project.entry_for_path(&project_path, cx)?;
11884            let parent = match &entry.canonical_path {
11885                Some(canonical_path) => canonical_path.to_path_buf(),
11886                None => project.absolute_path(&project_path, cx)?,
11887            }
11888            .parent()?
11889            .to_path_buf();
11890            Some(parent)
11891        }) {
11892            window.dispatch_action(
11893                OpenTerminal {
11894                    working_directory,
11895                    local: false,
11896                }
11897                .boxed_clone(),
11898                cx,
11899            );
11900        }
11901    }
11902
11903    fn set_breakpoint_context_menu(
11904        &mut self,
11905        display_row: DisplayRow,
11906        position: Option<Anchor>,
11907        clicked_point: gpui::Point<Pixels>,
11908        window: &mut Window,
11909        cx: &mut Context<Self>,
11910    ) {
11911        let source = self
11912            .buffer
11913            .read(cx)
11914            .snapshot(cx)
11915            .anchor_before(Point::new(display_row.0, 0u32));
11916
11917        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11918
11919        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11920            self,
11921            source,
11922            clicked_point,
11923            context_menu,
11924            window,
11925            cx,
11926        );
11927    }
11928
11929    fn add_edit_breakpoint_block(
11930        &mut self,
11931        anchor: Anchor,
11932        breakpoint: &Breakpoint,
11933        edit_action: BreakpointPromptEditAction,
11934        window: &mut Window,
11935        cx: &mut Context<Self>,
11936    ) {
11937        let weak_editor = cx.weak_entity();
11938        let bp_prompt = cx.new(|cx| {
11939            BreakpointPromptEditor::new(
11940                weak_editor,
11941                anchor,
11942                breakpoint.clone(),
11943                edit_action,
11944                window,
11945                cx,
11946            )
11947        });
11948
11949        let height = bp_prompt.update(cx, |this, cx| {
11950            this.prompt
11951                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11952        });
11953        let cloned_prompt = bp_prompt.clone();
11954        let blocks = vec![BlockProperties {
11955            style: BlockStyle::Sticky,
11956            placement: BlockPlacement::Above(anchor),
11957            height: Some(height),
11958            render: Arc::new(move |cx| {
11959                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11960                cloned_prompt.clone().into_any_element()
11961            }),
11962            priority: 0,
11963        }];
11964
11965        let focus_handle = bp_prompt.focus_handle(cx);
11966        window.focus(&focus_handle, cx);
11967
11968        let block_ids = self.insert_blocks(blocks, None, cx);
11969        bp_prompt.update(cx, |prompt, _| {
11970            prompt.add_block_ids(block_ids);
11971        });
11972    }
11973
11974    pub(crate) fn breakpoint_at_row(
11975        &self,
11976        row: u32,
11977        window: &mut Window,
11978        cx: &mut Context<Self>,
11979    ) -> Option<(Anchor, Breakpoint)> {
11980        let snapshot = self.snapshot(window, cx);
11981        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11982
11983        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11984    }
11985
11986    pub(crate) fn breakpoint_at_anchor(
11987        &self,
11988        breakpoint_position: Anchor,
11989        snapshot: &EditorSnapshot,
11990        cx: &mut Context<Self>,
11991    ) -> Option<(Anchor, Breakpoint)> {
11992        let (breakpoint_position, _) = snapshot
11993            .buffer_snapshot()
11994            .anchor_to_buffer_anchor(breakpoint_position)?;
11995        let buffer = self.buffer.read(cx).buffer(breakpoint_position.buffer_id)?;
11996
11997        let buffer_snapshot = buffer.read(cx).snapshot();
11998
11999        let row = buffer_snapshot
12000            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position)
12001            .row;
12002
12003        let line_len = buffer_snapshot.line_len(row);
12004        let anchor_end = buffer_snapshot.anchor_after(Point::new(row, line_len));
12005
12006        self.breakpoint_store
12007            .as_ref()?
12008            .read_with(cx, |breakpoint_store, cx| {
12009                breakpoint_store
12010                    .breakpoints(
12011                        &buffer,
12012                        Some(breakpoint_position..anchor_end),
12013                        &buffer_snapshot,
12014                        cx,
12015                    )
12016                    .next()
12017                    .and_then(|(bp, _)| {
12018                        let breakpoint_row = buffer_snapshot
12019                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
12020                            .row;
12021
12022                        if breakpoint_row == row {
12023                            snapshot
12024                                .buffer_snapshot()
12025                                .anchor_in_excerpt(bp.position)
12026                                .map(|position| (position, bp.bp.clone()))
12027                        } else {
12028                            None
12029                        }
12030                    })
12031            })
12032    }
12033
12034    pub fn edit_log_breakpoint(
12035        &mut self,
12036        _: &EditLogBreakpoint,
12037        window: &mut Window,
12038        cx: &mut Context<Self>,
12039    ) {
12040        if self.breakpoint_store.is_none() {
12041            return;
12042        }
12043
12044        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12045            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
12046                message: None,
12047                state: BreakpointState::Enabled,
12048                condition: None,
12049                hit_condition: None,
12050            });
12051
12052            self.add_edit_breakpoint_block(
12053                anchor,
12054                &breakpoint,
12055                BreakpointPromptEditAction::Log,
12056                window,
12057                cx,
12058            );
12059        }
12060    }
12061
12062    fn breakpoints_at_cursors(
12063        &self,
12064        window: &mut Window,
12065        cx: &mut Context<Self>,
12066    ) -> Vec<(Anchor, Option<Breakpoint>)> {
12067        let snapshot = self.snapshot(window, cx);
12068        let cursors = self
12069            .selections
12070            .disjoint_anchors_arc()
12071            .iter()
12072            .map(|selection| {
12073                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12074
12075                let breakpoint_position = self
12076                    .breakpoint_at_row(cursor_position.row, window, cx)
12077                    .map(|bp| bp.0)
12078                    .unwrap_or_else(|| {
12079                        snapshot
12080                            .display_snapshot
12081                            .buffer_snapshot()
12082                            .anchor_after(Point::new(cursor_position.row, 0))
12083                    });
12084
12085                let breakpoint = self
12086                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12087                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12088
12089                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12090            })
12091            // 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.
12092            .collect::<HashMap<Anchor, _>>();
12093
12094        cursors.into_iter().collect()
12095    }
12096
12097    pub fn enable_breakpoint(
12098        &mut self,
12099        _: &crate::actions::EnableBreakpoint,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        if self.breakpoint_store.is_none() {
12104            return;
12105        }
12106
12107        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12108            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12109                continue;
12110            };
12111            self.edit_breakpoint_at_anchor(
12112                anchor,
12113                breakpoint,
12114                BreakpointEditAction::InvertState,
12115                cx,
12116            );
12117        }
12118    }
12119
12120    pub fn align_selections(
12121        &mut self,
12122        _: &crate::actions::AlignSelections,
12123        window: &mut Window,
12124        cx: &mut Context<Self>,
12125    ) {
12126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12127
12128        let display_snapshot = self.display_snapshot(cx);
12129
12130        struct CursorData {
12131            anchor: Anchor,
12132            point: Point,
12133        }
12134        let cursor_data: Vec<CursorData> = self
12135            .selections
12136            .disjoint_anchors()
12137            .iter()
12138            .map(|selection| {
12139                let anchor = if selection.reversed {
12140                    selection.head()
12141                } else {
12142                    selection.tail()
12143                };
12144                CursorData {
12145                    anchor: anchor,
12146                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12147                }
12148            })
12149            .collect();
12150
12151        let rows_anchors_count: Vec<usize> = cursor_data
12152            .iter()
12153            .map(|cursor| cursor.point.row)
12154            .chunk_by(|&row| row)
12155            .into_iter()
12156            .map(|(_, group)| group.count())
12157            .collect();
12158        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12159        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12160        let mut edits = Vec::new();
12161
12162        for column_idx in 0..max_columns {
12163            let mut cursor_index = 0;
12164
12165            // Calculate target_column => position that the selections will go
12166            let mut target_column = 0;
12167            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12168                // Skip rows that don't have this column
12169                if column_idx >= *cursor_count {
12170                    cursor_index += cursor_count;
12171                    continue;
12172                }
12173
12174                let point = &cursor_data[cursor_index + column_idx].point;
12175                let adjusted_column = point.column + rows_column_offset[row_idx];
12176                if adjusted_column > target_column {
12177                    target_column = adjusted_column;
12178                }
12179                cursor_index += cursor_count;
12180            }
12181
12182            // Collect edits for this column
12183            cursor_index = 0;
12184            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12185                // Skip rows that don't have this column
12186                if column_idx >= *cursor_count {
12187                    cursor_index += *cursor_count;
12188                    continue;
12189                }
12190
12191                let point = &cursor_data[cursor_index + column_idx].point;
12192                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12193                if spaces_needed > 0 {
12194                    let anchor = cursor_data[cursor_index + column_idx]
12195                        .anchor
12196                        .bias_left(&display_snapshot);
12197                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12198                }
12199                rows_column_offset[row_idx] += spaces_needed;
12200
12201                cursor_index += *cursor_count;
12202            }
12203        }
12204
12205        if !edits.is_empty() {
12206            self.transact(window, cx, |editor, _window, cx| {
12207                editor.edit(edits, cx);
12208            });
12209        }
12210    }
12211
12212    pub fn disable_breakpoint(
12213        &mut self,
12214        _: &crate::actions::DisableBreakpoint,
12215        window: &mut Window,
12216        cx: &mut Context<Self>,
12217    ) {
12218        if self.breakpoint_store.is_none() {
12219            return;
12220        }
12221
12222        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12223            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12224                continue;
12225            };
12226            self.edit_breakpoint_at_anchor(
12227                anchor,
12228                breakpoint,
12229                BreakpointEditAction::InvertState,
12230                cx,
12231            );
12232        }
12233    }
12234
12235    pub fn toggle_breakpoint(
12236        &mut self,
12237        _: &crate::actions::ToggleBreakpoint,
12238        window: &mut Window,
12239        cx: &mut Context<Self>,
12240    ) {
12241        if self.breakpoint_store.is_none() {
12242            return;
12243        }
12244
12245        let snapshot = self.snapshot(window, cx);
12246        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12247            if self.gutter_breakpoint_indicator.0.is_some() {
12248                let display_row = anchor
12249                    .to_point(snapshot.buffer_snapshot())
12250                    .to_display_point(&snapshot.display_snapshot)
12251                    .row();
12252                self.update_breakpoint_collision_on_toggle(
12253                    display_row,
12254                    &BreakpointEditAction::Toggle,
12255                );
12256            }
12257
12258            if let Some(breakpoint) = breakpoint {
12259                self.edit_breakpoint_at_anchor(
12260                    anchor,
12261                    breakpoint,
12262                    BreakpointEditAction::Toggle,
12263                    cx,
12264                );
12265            } else {
12266                self.edit_breakpoint_at_anchor(
12267                    anchor,
12268                    Breakpoint::new_standard(),
12269                    BreakpointEditAction::Toggle,
12270                    cx,
12271                );
12272            }
12273        }
12274    }
12275
12276    fn update_breakpoint_collision_on_toggle(
12277        &mut self,
12278        display_row: DisplayRow,
12279        edit_action: &BreakpointEditAction,
12280    ) {
12281        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12282            if breakpoint_indicator.display_row == display_row
12283                && matches!(edit_action, BreakpointEditAction::Toggle)
12284            {
12285                breakpoint_indicator.collides_with_existing_breakpoint =
12286                    !breakpoint_indicator.collides_with_existing_breakpoint;
12287            }
12288        }
12289    }
12290
12291    pub fn edit_breakpoint_at_anchor(
12292        &mut self,
12293        breakpoint_position: Anchor,
12294        breakpoint: Breakpoint,
12295        edit_action: BreakpointEditAction,
12296        cx: &mut Context<Self>,
12297    ) {
12298        let Some(breakpoint_store) = &self.breakpoint_store else {
12299            return;
12300        };
12301        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12302        let Some((position, _)) = buffer_snapshot.anchor_to_buffer_anchor(breakpoint_position)
12303        else {
12304            return;
12305        };
12306        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
12307            return;
12308        };
12309
12310        breakpoint_store.update(cx, |breakpoint_store, cx| {
12311            breakpoint_store.toggle_breakpoint(
12312                buffer,
12313                BreakpointWithPosition {
12314                    position,
12315                    bp: breakpoint,
12316                },
12317                edit_action,
12318                cx,
12319            );
12320        });
12321
12322        cx.notify();
12323    }
12324
12325    #[cfg(any(test, feature = "test-support"))]
12326    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12327        self.breakpoint_store.clone()
12328    }
12329
12330    pub fn prepare_restore_change(
12331        &self,
12332        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12333        hunk: &MultiBufferDiffHunk,
12334        cx: &mut App,
12335    ) -> Option<()> {
12336        if hunk.is_created_file() {
12337            return None;
12338        }
12339        let multi_buffer = self.buffer.read(cx);
12340        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
12341        let diff_snapshot = multi_buffer_snapshot.diff_for_buffer_id(hunk.buffer_id)?;
12342        let original_text = diff_snapshot
12343            .base_text()
12344            .as_rope()
12345            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12346        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
12347        let buffer = buffer.read(cx);
12348        let buffer_snapshot = buffer.snapshot();
12349        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12350        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12351            probe
12352                .0
12353                .start
12354                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12355                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12356        }) {
12357            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12358            Some(())
12359        } else {
12360            None
12361        }
12362    }
12363
12364    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12365        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12366    }
12367
12368    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12369        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12370    }
12371
12372    pub fn rotate_selections_forward(
12373        &mut self,
12374        _: &RotateSelectionsForward,
12375        window: &mut Window,
12376        cx: &mut Context<Self>,
12377    ) {
12378        self.rotate_selections(window, cx, false)
12379    }
12380
12381    pub fn rotate_selections_backward(
12382        &mut self,
12383        _: &RotateSelectionsBackward,
12384        window: &mut Window,
12385        cx: &mut Context<Self>,
12386    ) {
12387        self.rotate_selections(window, cx, true)
12388    }
12389
12390    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12392        let display_snapshot = self.display_snapshot(cx);
12393        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12394
12395        if selections.len() < 2 {
12396            return;
12397        }
12398
12399        let (edits, new_selections) = {
12400            let buffer = self.buffer.read(cx).read(cx);
12401            let has_selections = selections.iter().any(|s| !s.is_empty());
12402            if has_selections {
12403                let mut selected_texts: Vec<String> = selections
12404                    .iter()
12405                    .map(|selection| {
12406                        buffer
12407                            .text_for_range(selection.start..selection.end)
12408                            .collect()
12409                    })
12410                    .collect();
12411
12412                if reverse {
12413                    selected_texts.rotate_left(1);
12414                } else {
12415                    selected_texts.rotate_right(1);
12416                }
12417
12418                let mut offset_delta: i64 = 0;
12419                let mut new_selections = Vec::new();
12420                let edits: Vec<_> = selections
12421                    .iter()
12422                    .zip(selected_texts.iter())
12423                    .map(|(selection, new_text)| {
12424                        let old_len = (selection.end.0 - selection.start.0) as i64;
12425                        let new_len = new_text.len() as i64;
12426                        let adjusted_start =
12427                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12428                        let adjusted_end =
12429                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12430
12431                        new_selections.push(Selection {
12432                            id: selection.id,
12433                            start: adjusted_start,
12434                            end: adjusted_end,
12435                            reversed: selection.reversed,
12436                            goal: selection.goal,
12437                        });
12438
12439                        offset_delta += new_len - old_len;
12440                        (selection.start..selection.end, new_text.clone())
12441                    })
12442                    .collect();
12443                (edits, new_selections)
12444            } else {
12445                let mut all_rows: Vec<u32> = selections
12446                    .iter()
12447                    .map(|selection| buffer.offset_to_point(selection.start).row)
12448                    .collect();
12449                all_rows.sort_unstable();
12450                all_rows.dedup();
12451
12452                if all_rows.len() < 2 {
12453                    return;
12454                }
12455
12456                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12457                    .iter()
12458                    .map(|&row| {
12459                        let start = Point::new(row, 0);
12460                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12461                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12462                    })
12463                    .collect();
12464
12465                let mut line_texts: Vec<String> = line_ranges
12466                    .iter()
12467                    .map(|range| buffer.text_for_range(range.clone()).collect())
12468                    .collect();
12469
12470                if reverse {
12471                    line_texts.rotate_left(1);
12472                } else {
12473                    line_texts.rotate_right(1);
12474                }
12475
12476                let edits = line_ranges
12477                    .iter()
12478                    .zip(line_texts.iter())
12479                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12480                    .collect();
12481
12482                let num_rows = all_rows.len();
12483                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12484                    .iter()
12485                    .enumerate()
12486                    .map(|(i, &row)| (row, i))
12487                    .collect();
12488
12489                // Compute new line start offsets after rotation (handles CRLF)
12490                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12491                let first_line_start = line_ranges[0].start.0;
12492                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12493                for text in line_texts.iter().take(num_rows - 1) {
12494                    let prev_start = *new_line_starts.last().unwrap();
12495                    new_line_starts.push(prev_start + text.len() + newline_len);
12496                }
12497
12498                let new_selections = selections
12499                    .iter()
12500                    .map(|selection| {
12501                        let point = buffer.offset_to_point(selection.start);
12502                        let old_index = row_to_index[&point.row];
12503                        let new_index = if reverse {
12504                            (old_index + num_rows - 1) % num_rows
12505                        } else {
12506                            (old_index + 1) % num_rows
12507                        };
12508                        let new_offset =
12509                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12510                        Selection {
12511                            id: selection.id,
12512                            start: new_offset,
12513                            end: new_offset,
12514                            reversed: selection.reversed,
12515                            goal: selection.goal,
12516                        }
12517                    })
12518                    .collect();
12519
12520                (edits, new_selections)
12521            }
12522        };
12523
12524        self.transact(window, cx, |this, window, cx| {
12525            this.buffer.update(cx, |buffer, cx| {
12526                buffer.edit(edits, None, cx);
12527            });
12528            this.change_selections(Default::default(), window, cx, |s| {
12529                s.select(new_selections);
12530            });
12531        });
12532    }
12533
12534    fn manipulate_lines<M>(
12535        &mut self,
12536        window: &mut Window,
12537        cx: &mut Context<Self>,
12538        mut manipulate: M,
12539    ) where
12540        M: FnMut(&str) -> LineManipulationResult,
12541    {
12542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12543
12544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12545        let buffer = self.buffer.read(cx).snapshot(cx);
12546
12547        let mut edits = Vec::new();
12548
12549        let selections = self.selections.all::<Point>(&display_map);
12550        let mut selections = selections.iter().peekable();
12551        let mut contiguous_row_selections = Vec::new();
12552        let mut new_selections = Vec::new();
12553        let mut added_lines = 0;
12554        let mut removed_lines = 0;
12555
12556        while let Some(selection) = selections.next() {
12557            let (start_row, end_row) = consume_contiguous_rows(
12558                &mut contiguous_row_selections,
12559                selection,
12560                &display_map,
12561                &mut selections,
12562            );
12563
12564            let start_point = Point::new(start_row.0, 0);
12565            let end_point = Point::new(
12566                end_row.previous_row().0,
12567                buffer.line_len(end_row.previous_row()),
12568            );
12569            let text = buffer
12570                .text_for_range(start_point..end_point)
12571                .collect::<String>();
12572
12573            let LineManipulationResult {
12574                new_text,
12575                line_count_before,
12576                line_count_after,
12577            } = manipulate(&text);
12578
12579            edits.push((start_point..end_point, new_text));
12580
12581            // Selections must change based on added and removed line count
12582            let start_row =
12583                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12584            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12585            new_selections.push(Selection {
12586                id: selection.id,
12587                start: start_row,
12588                end: end_row,
12589                goal: SelectionGoal::None,
12590                reversed: selection.reversed,
12591            });
12592
12593            if line_count_after > line_count_before {
12594                added_lines += line_count_after - line_count_before;
12595            } else if line_count_before > line_count_after {
12596                removed_lines += line_count_before - line_count_after;
12597            }
12598        }
12599
12600        self.transact(window, cx, |this, window, cx| {
12601            let buffer = this.buffer.update(cx, |buffer, cx| {
12602                buffer.edit(edits, None, cx);
12603                buffer.snapshot(cx)
12604            });
12605
12606            // Recalculate offsets on newly edited buffer
12607            let new_selections = new_selections
12608                .iter()
12609                .map(|s| {
12610                    let start_point = Point::new(s.start.0, 0);
12611                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12612                    Selection {
12613                        id: s.id,
12614                        start: buffer.point_to_offset(start_point),
12615                        end: buffer.point_to_offset(end_point),
12616                        goal: s.goal,
12617                        reversed: s.reversed,
12618                    }
12619                })
12620                .collect();
12621
12622            this.change_selections(Default::default(), window, cx, |s| {
12623                s.select(new_selections);
12624            });
12625
12626            this.request_autoscroll(Autoscroll::fit(), cx);
12627        });
12628    }
12629
12630    fn manipulate_immutable_lines<Fn>(
12631        &mut self,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634        mut callback: Fn,
12635    ) where
12636        Fn: FnMut(&mut Vec<&str>),
12637    {
12638        self.manipulate_lines(window, cx, |text| {
12639            let mut lines: Vec<&str> = text.split('\n').collect();
12640            let line_count_before = lines.len();
12641
12642            callback(&mut lines);
12643
12644            LineManipulationResult {
12645                new_text: lines.join("\n"),
12646                line_count_before,
12647                line_count_after: lines.len(),
12648            }
12649        });
12650    }
12651
12652    fn manipulate_mutable_lines<Fn>(
12653        &mut self,
12654        window: &mut Window,
12655        cx: &mut Context<Self>,
12656        mut callback: Fn,
12657    ) where
12658        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12659    {
12660        self.manipulate_lines(window, cx, |text| {
12661            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12662            let line_count_before = lines.len();
12663
12664            callback(&mut lines);
12665
12666            LineManipulationResult {
12667                new_text: lines.join("\n"),
12668                line_count_before,
12669                line_count_after: lines.len(),
12670            }
12671        });
12672    }
12673
12674    pub fn convert_indentation_to_spaces(
12675        &mut self,
12676        _: &ConvertIndentationToSpaces,
12677        window: &mut Window,
12678        cx: &mut Context<Self>,
12679    ) {
12680        let settings = self.buffer.read(cx).language_settings(cx);
12681        let tab_size = settings.tab_size.get() as usize;
12682
12683        self.manipulate_mutable_lines(window, cx, |lines| {
12684            // Allocates a reasonably sized scratch buffer once for the whole loop
12685            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12686            // Avoids recomputing spaces that could be inserted many times
12687            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12688                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12689                .collect();
12690
12691            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12692                let mut chars = line.as_ref().chars();
12693                let mut col = 0;
12694                let mut changed = false;
12695
12696                for ch in chars.by_ref() {
12697                    match ch {
12698                        ' ' => {
12699                            reindented_line.push(' ');
12700                            col += 1;
12701                        }
12702                        '\t' => {
12703                            // \t are converted to spaces depending on the current column
12704                            let spaces_len = tab_size - (col % tab_size);
12705                            reindented_line.extend(&space_cache[spaces_len - 1]);
12706                            col += spaces_len;
12707                            changed = true;
12708                        }
12709                        _ => {
12710                            // If we dont append before break, the character is consumed
12711                            reindented_line.push(ch);
12712                            break;
12713                        }
12714                    }
12715                }
12716
12717                if !changed {
12718                    reindented_line.clear();
12719                    continue;
12720                }
12721                // Append the rest of the line and replace old reference with new one
12722                reindented_line.extend(chars);
12723                *line = Cow::Owned(reindented_line.clone());
12724                reindented_line.clear();
12725            }
12726        });
12727    }
12728
12729    pub fn convert_indentation_to_tabs(
12730        &mut self,
12731        _: &ConvertIndentationToTabs,
12732        window: &mut Window,
12733        cx: &mut Context<Self>,
12734    ) {
12735        let settings = self.buffer.read(cx).language_settings(cx);
12736        let tab_size = settings.tab_size.get() as usize;
12737
12738        self.manipulate_mutable_lines(window, cx, |lines| {
12739            // Allocates a reasonably sized buffer once for the whole loop
12740            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12741            // Avoids recomputing spaces that could be inserted many times
12742            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12743                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12744                .collect();
12745
12746            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12747                let mut chars = line.chars();
12748                let mut spaces_count = 0;
12749                let mut first_non_indent_char = None;
12750                let mut changed = false;
12751
12752                for ch in chars.by_ref() {
12753                    match ch {
12754                        ' ' => {
12755                            // Keep track of spaces. Append \t when we reach tab_size
12756                            spaces_count += 1;
12757                            changed = true;
12758                            if spaces_count == tab_size {
12759                                reindented_line.push('\t');
12760                                spaces_count = 0;
12761                            }
12762                        }
12763                        '\t' => {
12764                            reindented_line.push('\t');
12765                            spaces_count = 0;
12766                        }
12767                        _ => {
12768                            // Dont append it yet, we might have remaining spaces
12769                            first_non_indent_char = Some(ch);
12770                            break;
12771                        }
12772                    }
12773                }
12774
12775                if !changed {
12776                    reindented_line.clear();
12777                    continue;
12778                }
12779                // Remaining spaces that didn't make a full tab stop
12780                if spaces_count > 0 {
12781                    reindented_line.extend(&space_cache[spaces_count - 1]);
12782                }
12783                // If we consume an extra character that was not indentation, add it back
12784                if let Some(extra_char) = first_non_indent_char {
12785                    reindented_line.push(extra_char);
12786                }
12787                // Append the rest of the line and replace old reference with new one
12788                reindented_line.extend(chars);
12789                *line = Cow::Owned(reindented_line.clone());
12790                reindented_line.clear();
12791            }
12792        });
12793    }
12794
12795    pub fn convert_to_upper_case(
12796        &mut self,
12797        _: &ConvertToUpperCase,
12798        window: &mut Window,
12799        cx: &mut Context<Self>,
12800    ) {
12801        self.manipulate_text(window, cx, |text| text.to_uppercase())
12802    }
12803
12804    pub fn convert_to_lower_case(
12805        &mut self,
12806        _: &ConvertToLowerCase,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) {
12810        self.manipulate_text(window, cx, |text| text.to_lowercase())
12811    }
12812
12813    pub fn convert_to_title_case(
12814        &mut self,
12815        _: &ConvertToTitleCase,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) {
12819        self.manipulate_text(window, cx, |text| {
12820            Self::convert_text_case(text, Case::Title)
12821        })
12822    }
12823
12824    pub fn convert_to_snake_case(
12825        &mut self,
12826        _: &ConvertToSnakeCase,
12827        window: &mut Window,
12828        cx: &mut Context<Self>,
12829    ) {
12830        self.manipulate_text(window, cx, |text| {
12831            Self::convert_text_case(text, Case::Snake)
12832        })
12833    }
12834
12835    pub fn convert_to_kebab_case(
12836        &mut self,
12837        _: &ConvertToKebabCase,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.manipulate_text(window, cx, |text| {
12842            Self::convert_text_case(text, Case::Kebab)
12843        })
12844    }
12845
12846    pub fn convert_to_upper_camel_case(
12847        &mut self,
12848        _: &ConvertToUpperCamelCase,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        self.manipulate_text(window, cx, |text| {
12853            Self::convert_text_case(text, Case::UpperCamel)
12854        })
12855    }
12856
12857    pub fn convert_to_lower_camel_case(
12858        &mut self,
12859        _: &ConvertToLowerCamelCase,
12860        window: &mut Window,
12861        cx: &mut Context<Self>,
12862    ) {
12863        self.manipulate_text(window, cx, |text| {
12864            Self::convert_text_case(text, Case::Camel)
12865        })
12866    }
12867
12868    pub fn convert_to_opposite_case(
12869        &mut self,
12870        _: &ConvertToOppositeCase,
12871        window: &mut Window,
12872        cx: &mut Context<Self>,
12873    ) {
12874        self.manipulate_text(window, cx, |text| {
12875            text.chars()
12876                .fold(String::with_capacity(text.len()), |mut t, c| {
12877                    if c.is_uppercase() {
12878                        t.extend(c.to_lowercase());
12879                    } else {
12880                        t.extend(c.to_uppercase());
12881                    }
12882                    t
12883                })
12884        })
12885    }
12886
12887    pub fn convert_to_sentence_case(
12888        &mut self,
12889        _: &ConvertToSentenceCase,
12890        window: &mut Window,
12891        cx: &mut Context<Self>,
12892    ) {
12893        self.manipulate_text(window, cx, |text| {
12894            Self::convert_text_case(text, Case::Sentence)
12895        })
12896    }
12897
12898    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12899        self.manipulate_text(window, cx, |text| {
12900            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12901            if has_upper_case_characters {
12902                text.to_lowercase()
12903            } else {
12904                text.to_uppercase()
12905            }
12906        })
12907    }
12908
12909    pub fn convert_to_rot13(
12910        &mut self,
12911        _: &ConvertToRot13,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        self.manipulate_text(window, cx, |text| {
12916            text.chars()
12917                .map(|c| match c {
12918                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12919                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12920                    _ => c,
12921                })
12922                .collect()
12923        })
12924    }
12925
12926    fn convert_text_case(text: &str, case: Case) -> String {
12927        text.lines()
12928            .map(|line| {
12929                let trimmed_start = line.trim_start();
12930                let leading = &line[..line.len() - trimmed_start.len()];
12931                let trimmed = trimmed_start.trim_end();
12932                let trailing = &trimmed_start[trimmed.len()..];
12933                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12934            })
12935            .join("\n")
12936    }
12937
12938    pub fn convert_to_rot47(
12939        &mut self,
12940        _: &ConvertToRot47,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) {
12944        self.manipulate_text(window, cx, |text| {
12945            text.chars()
12946                .map(|c| {
12947                    let code_point = c as u32;
12948                    if code_point >= 33 && code_point <= 126 {
12949                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12950                    }
12951                    c
12952                })
12953                .collect()
12954        })
12955    }
12956
12957    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12958    where
12959        Fn: FnMut(&str) -> String,
12960    {
12961        let buffer = self.buffer.read(cx).snapshot(cx);
12962
12963        let mut new_selections = Vec::new();
12964        let mut edits = Vec::new();
12965        let mut selection_adjustment = 0isize;
12966
12967        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12968            let selection_is_empty = selection.is_empty();
12969
12970            let (start, end) = if selection_is_empty {
12971                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12972                (word_range.start, word_range.end)
12973            } else {
12974                (
12975                    buffer.point_to_offset(selection.start),
12976                    buffer.point_to_offset(selection.end),
12977                )
12978            };
12979
12980            let text = buffer.text_for_range(start..end).collect::<String>();
12981            let old_length = text.len() as isize;
12982            let text = callback(&text);
12983
12984            new_selections.push(Selection {
12985                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12986                end: MultiBufferOffset(
12987                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12988                ),
12989                goal: SelectionGoal::None,
12990                id: selection.id,
12991                reversed: selection.reversed,
12992            });
12993
12994            selection_adjustment += old_length - text.len() as isize;
12995
12996            edits.push((start..end, text));
12997        }
12998
12999        self.transact(window, cx, |this, window, cx| {
13000            this.buffer.update(cx, |buffer, cx| {
13001                buffer.edit(edits, None, cx);
13002            });
13003
13004            this.change_selections(Default::default(), window, cx, |s| {
13005                s.select(new_selections);
13006            });
13007
13008            this.request_autoscroll(Autoscroll::fit(), cx);
13009        });
13010    }
13011
13012    pub fn move_selection_on_drop(
13013        &mut self,
13014        selection: &Selection<Anchor>,
13015        target: DisplayPoint,
13016        is_cut: bool,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13021        let buffer = display_map.buffer_snapshot();
13022        let mut edits = Vec::new();
13023        let insert_point = display_map
13024            .clip_point(target, Bias::Left)
13025            .to_point(&display_map);
13026        let text = buffer
13027            .text_for_range(selection.start..selection.end)
13028            .collect::<String>();
13029        if is_cut {
13030            edits.push(((selection.start..selection.end), String::new()));
13031        }
13032        let insert_anchor = buffer.anchor_before(insert_point);
13033        edits.push(((insert_anchor..insert_anchor), text));
13034        let last_edit_start = insert_anchor.bias_left(buffer);
13035        let last_edit_end = insert_anchor.bias_right(buffer);
13036        self.transact(window, cx, |this, window, cx| {
13037            this.buffer.update(cx, |buffer, cx| {
13038                buffer.edit(edits, None, cx);
13039            });
13040            this.change_selections(Default::default(), window, cx, |s| {
13041                s.select_anchor_ranges([last_edit_start..last_edit_end]);
13042            });
13043        });
13044    }
13045
13046    pub fn clear_selection_drag_state(&mut self) {
13047        self.selection_drag_state = SelectionDragState::None;
13048    }
13049
13050    pub fn duplicate(
13051        &mut self,
13052        upwards: bool,
13053        whole_lines: bool,
13054        window: &mut Window,
13055        cx: &mut Context<Self>,
13056    ) {
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13058
13059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13060        let buffer = display_map.buffer_snapshot();
13061        let selections = self.selections.all::<Point>(&display_map);
13062
13063        let mut edits = Vec::new();
13064        let mut selections_iter = selections.iter().peekable();
13065        while let Some(selection) = selections_iter.next() {
13066            let mut rows = selection.spanned_rows(false, &display_map);
13067            // duplicate line-wise
13068            if whole_lines || selection.start == selection.end {
13069                // Avoid duplicating the same lines twice.
13070                while let Some(next_selection) = selections_iter.peek() {
13071                    let next_rows = next_selection.spanned_rows(false, &display_map);
13072                    if next_rows.start < rows.end {
13073                        rows.end = next_rows.end;
13074                        selections_iter.next().unwrap();
13075                    } else {
13076                        break;
13077                    }
13078                }
13079
13080                // Copy the text from the selected row region and splice it either at the start
13081                // or end of the region.
13082                let start = Point::new(rows.start.0, 0);
13083                let end = Point::new(
13084                    rows.end.previous_row().0,
13085                    buffer.line_len(rows.end.previous_row()),
13086                );
13087
13088                let mut text = buffer.text_for_range(start..end).collect::<String>();
13089
13090                let insert_location = if upwards {
13091                    // When duplicating upward, we need to insert before the current line.
13092                    // If we're on the last line and it doesn't end with a newline,
13093                    // we need to add a newline before the duplicated content.
13094                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13095                        && buffer.max_point().column > 0
13096                        && !text.ends_with('\n');
13097
13098                    if needs_leading_newline {
13099                        text.insert(0, '\n');
13100                        end
13101                    } else {
13102                        text.push('\n');
13103                        Point::new(rows.start.0, 0)
13104                    }
13105                } else {
13106                    text.push('\n');
13107                    start
13108                };
13109                edits.push((insert_location..insert_location, text));
13110            } else {
13111                // duplicate character-wise
13112                let start = selection.start;
13113                let end = selection.end;
13114                let text = buffer.text_for_range(start..end).collect::<String>();
13115                edits.push((selection.end..selection.end, text));
13116            }
13117        }
13118
13119        self.transact(window, cx, |this, window, cx| {
13120            this.buffer.update(cx, |buffer, cx| {
13121                buffer.edit(edits, None, cx);
13122            });
13123
13124            // When duplicating upward with whole lines, move the cursor to the duplicated line
13125            if upwards && whole_lines {
13126                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13127
13128                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13129                    let mut new_ranges = Vec::new();
13130                    let selections = s.all::<Point>(&display_map);
13131                    let mut selections_iter = selections.iter().peekable();
13132
13133                    while let Some(first_selection) = selections_iter.next() {
13134                        // Group contiguous selections together to find the total row span
13135                        let mut group_selections = vec![first_selection];
13136                        let mut rows = first_selection.spanned_rows(false, &display_map);
13137
13138                        while let Some(next_selection) = selections_iter.peek() {
13139                            let next_rows = next_selection.spanned_rows(false, &display_map);
13140                            if next_rows.start < rows.end {
13141                                rows.end = next_rows.end;
13142                                group_selections.push(selections_iter.next().unwrap());
13143                            } else {
13144                                break;
13145                            }
13146                        }
13147
13148                        let row_count = rows.end.0 - rows.start.0;
13149
13150                        // Move all selections in this group up by the total number of duplicated rows
13151                        for selection in group_selections {
13152                            let new_start = Point::new(
13153                                selection.start.row.saturating_sub(row_count),
13154                                selection.start.column,
13155                            );
13156
13157                            let new_end = Point::new(
13158                                selection.end.row.saturating_sub(row_count),
13159                                selection.end.column,
13160                            );
13161
13162                            new_ranges.push(new_start..new_end);
13163                        }
13164                    }
13165
13166                    s.select_ranges(new_ranges);
13167                });
13168            }
13169
13170            this.request_autoscroll(Autoscroll::fit(), cx);
13171        });
13172    }
13173
13174    pub fn duplicate_line_up(
13175        &mut self,
13176        _: &DuplicateLineUp,
13177        window: &mut Window,
13178        cx: &mut Context<Self>,
13179    ) {
13180        self.duplicate(true, true, window, cx);
13181    }
13182
13183    pub fn duplicate_line_down(
13184        &mut self,
13185        _: &DuplicateLineDown,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        self.duplicate(false, true, window, cx);
13190    }
13191
13192    pub fn duplicate_selection(
13193        &mut self,
13194        _: &DuplicateSelection,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        self.duplicate(false, false, window, cx);
13199    }
13200
13201    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13203        if self.mode.is_single_line() {
13204            cx.propagate();
13205            return;
13206        }
13207
13208        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13209        let buffer = self.buffer.read(cx).snapshot(cx);
13210
13211        let mut edits = Vec::new();
13212        let mut unfold_ranges = Vec::new();
13213        let mut refold_creases = Vec::new();
13214
13215        let selections = self.selections.all::<Point>(&display_map);
13216        let mut selections = selections.iter().peekable();
13217        let mut contiguous_row_selections = Vec::new();
13218        let mut new_selections = Vec::new();
13219
13220        while let Some(selection) = selections.next() {
13221            // Find all the selections that span a contiguous row range
13222            let (start_row, end_row) = consume_contiguous_rows(
13223                &mut contiguous_row_selections,
13224                selection,
13225                &display_map,
13226                &mut selections,
13227            );
13228
13229            // Move the text spanned by the row range to be before the line preceding the row range
13230            if start_row.0 > 0 {
13231                let range_to_move = Point::new(
13232                    start_row.previous_row().0,
13233                    buffer.line_len(start_row.previous_row()),
13234                )
13235                    ..Point::new(
13236                        end_row.previous_row().0,
13237                        buffer.line_len(end_row.previous_row()),
13238                    );
13239                let insertion_point = display_map
13240                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13241                    .0;
13242
13243                // Don't move lines across excerpts
13244                if buffer
13245                    .excerpt_containing(insertion_point..range_to_move.end)
13246                    .is_some()
13247                {
13248                    let text = buffer
13249                        .text_for_range(range_to_move.clone())
13250                        .flat_map(|s| s.chars())
13251                        .skip(1)
13252                        .chain(['\n'])
13253                        .collect::<String>();
13254
13255                    edits.push((
13256                        buffer.anchor_after(range_to_move.start)
13257                            ..buffer.anchor_before(range_to_move.end),
13258                        String::new(),
13259                    ));
13260                    let insertion_anchor = buffer.anchor_after(insertion_point);
13261                    edits.push((insertion_anchor..insertion_anchor, text));
13262
13263                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13264
13265                    // Move selections up
13266                    new_selections.extend(contiguous_row_selections.drain(..).map(
13267                        |mut selection| {
13268                            selection.start.row -= row_delta;
13269                            selection.end.row -= row_delta;
13270                            selection
13271                        },
13272                    ));
13273
13274                    // Move folds up
13275                    unfold_ranges.push(range_to_move.clone());
13276                    for fold in display_map.folds_in_range(
13277                        buffer.anchor_before(range_to_move.start)
13278                            ..buffer.anchor_after(range_to_move.end),
13279                    ) {
13280                        let mut start = fold.range.start.to_point(&buffer);
13281                        let mut end = fold.range.end.to_point(&buffer);
13282                        start.row -= row_delta;
13283                        end.row -= row_delta;
13284                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13285                    }
13286                }
13287            }
13288
13289            // If we didn't move line(s), preserve the existing selections
13290            new_selections.append(&mut contiguous_row_selections);
13291        }
13292
13293        self.transact(window, cx, |this, window, cx| {
13294            this.unfold_ranges(&unfold_ranges, true, true, cx);
13295            this.buffer.update(cx, |buffer, cx| {
13296                for (range, text) in edits {
13297                    buffer.edit([(range, text)], None, cx);
13298                }
13299            });
13300            this.fold_creases(refold_creases, true, window, cx);
13301            this.change_selections(Default::default(), window, cx, |s| {
13302                s.select(new_selections);
13303            })
13304        });
13305    }
13306
13307    pub fn move_line_down(
13308        &mut self,
13309        _: &MoveLineDown,
13310        window: &mut Window,
13311        cx: &mut Context<Self>,
13312    ) {
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13314        if self.mode.is_single_line() {
13315            cx.propagate();
13316            return;
13317        }
13318
13319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13320        let buffer = self.buffer.read(cx).snapshot(cx);
13321
13322        let mut edits = Vec::new();
13323        let mut unfold_ranges = Vec::new();
13324        let mut refold_creases = Vec::new();
13325
13326        let selections = self.selections.all::<Point>(&display_map);
13327        let mut selections = selections.iter().peekable();
13328        let mut contiguous_row_selections = Vec::new();
13329        let mut new_selections = Vec::new();
13330
13331        while let Some(selection) = selections.next() {
13332            // Find all the selections that span a contiguous row range
13333            let (start_row, end_row) = consume_contiguous_rows(
13334                &mut contiguous_row_selections,
13335                selection,
13336                &display_map,
13337                &mut selections,
13338            );
13339
13340            // Move the text spanned by the row range to be after the last line of the row range
13341            if end_row.0 <= buffer.max_point().row {
13342                let range_to_move =
13343                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13344                let insertion_point = display_map
13345                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13346                    .0;
13347
13348                // Don't move lines across excerpt boundaries
13349                if buffer
13350                    .excerpt_containing(range_to_move.start..insertion_point)
13351                    .is_some()
13352                {
13353                    let mut text = String::from("\n");
13354                    text.extend(buffer.text_for_range(range_to_move.clone()));
13355                    text.pop(); // Drop trailing newline
13356                    edits.push((
13357                        buffer.anchor_after(range_to_move.start)
13358                            ..buffer.anchor_before(range_to_move.end),
13359                        String::new(),
13360                    ));
13361                    let insertion_anchor = buffer.anchor_after(insertion_point);
13362                    edits.push((insertion_anchor..insertion_anchor, text));
13363
13364                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13365
13366                    // Move selections down
13367                    new_selections.extend(contiguous_row_selections.drain(..).map(
13368                        |mut selection| {
13369                            selection.start.row += row_delta;
13370                            selection.end.row += row_delta;
13371                            selection
13372                        },
13373                    ));
13374
13375                    // Move folds down
13376                    unfold_ranges.push(range_to_move.clone());
13377                    for fold in display_map.folds_in_range(
13378                        buffer.anchor_before(range_to_move.start)
13379                            ..buffer.anchor_after(range_to_move.end),
13380                    ) {
13381                        let mut start = fold.range.start.to_point(&buffer);
13382                        let mut end = fold.range.end.to_point(&buffer);
13383                        start.row += row_delta;
13384                        end.row += row_delta;
13385                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13386                    }
13387                }
13388            }
13389
13390            // If we didn't move line(s), preserve the existing selections
13391            new_selections.append(&mut contiguous_row_selections);
13392        }
13393
13394        self.transact(window, cx, |this, window, cx| {
13395            this.unfold_ranges(&unfold_ranges, true, true, cx);
13396            this.buffer.update(cx, |buffer, cx| {
13397                for (range, text) in edits {
13398                    buffer.edit([(range, text)], None, cx);
13399                }
13400            });
13401            this.fold_creases(refold_creases, true, window, cx);
13402            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13403        });
13404    }
13405
13406    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13408        let text_layout_details = &self.text_layout_details(window, cx);
13409        self.transact(window, cx, |this, window, cx| {
13410            let edits = this.change_selections(Default::default(), window, cx, |s| {
13411                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13412                s.move_with(&mut |display_map, selection| {
13413                    if !selection.is_empty() {
13414                        return;
13415                    }
13416
13417                    let mut head = selection.head();
13418                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13419                    if head.column() == display_map.line_len(head.row()) {
13420                        transpose_offset = display_map
13421                            .buffer_snapshot()
13422                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13423                    }
13424
13425                    if transpose_offset == MultiBufferOffset(0) {
13426                        return;
13427                    }
13428
13429                    *head.column_mut() += 1;
13430                    head = display_map.clip_point(head, Bias::Right);
13431                    let goal = SelectionGoal::HorizontalPosition(
13432                        display_map
13433                            .x_for_display_point(head, text_layout_details)
13434                            .into(),
13435                    );
13436                    selection.collapse_to(head, goal);
13437
13438                    let transpose_start = display_map
13439                        .buffer_snapshot()
13440                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13441                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13442                        let transpose_end = display_map
13443                            .buffer_snapshot()
13444                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13445                        if let Some(ch) = display_map
13446                            .buffer_snapshot()
13447                            .chars_at(transpose_start)
13448                            .next()
13449                        {
13450                            edits.push((transpose_start..transpose_offset, String::new()));
13451                            edits.push((transpose_end..transpose_end, ch.to_string()));
13452                        }
13453                    }
13454                });
13455                edits
13456            });
13457            this.buffer
13458                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13459            let selections = this
13460                .selections
13461                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13462            this.change_selections(Default::default(), window, cx, |s| {
13463                s.select(selections);
13464            });
13465        });
13466    }
13467
13468    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13470        if self.mode.is_single_line() {
13471            cx.propagate();
13472            return;
13473        }
13474
13475        self.rewrap_impl(RewrapOptions::default(), cx)
13476    }
13477
13478    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13479        let buffer = self.buffer.read(cx).snapshot(cx);
13480        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13481
13482        #[derive(Clone, Debug, PartialEq)]
13483        enum CommentFormat {
13484            /// single line comment, with prefix for line
13485            Line(String),
13486            /// single line within a block comment, with prefix for line
13487            BlockLine(String),
13488            /// a single line of a block comment that includes the initial delimiter
13489            BlockCommentWithStart(BlockCommentConfig),
13490            /// a single line of a block comment that includes the ending delimiter
13491            BlockCommentWithEnd(BlockCommentConfig),
13492        }
13493
13494        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13495        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13496            let language_settings = buffer.language_settings_at(selection.head(), cx);
13497            let language_scope = buffer.language_scope_at(selection.head());
13498
13499            let indent_and_prefix_for_row =
13500                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13501                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13502                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13503                        &language_scope
13504                    {
13505                        let indent_end = Point::new(row, indent.len);
13506                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13507                        let line_text_after_indent = buffer
13508                            .text_for_range(indent_end..line_end)
13509                            .collect::<String>();
13510
13511                        let is_within_comment_override = buffer
13512                            .language_scope_at(indent_end)
13513                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13514                        let comment_delimiters = if is_within_comment_override {
13515                            // we are within a comment syntax node, but we don't
13516                            // yet know what kind of comment: block, doc or line
13517                            match (
13518                                language_scope.documentation_comment(),
13519                                language_scope.block_comment(),
13520                            ) {
13521                                (Some(config), _) | (_, Some(config))
13522                                    if buffer.contains_str_at(indent_end, &config.start) =>
13523                                {
13524                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13525                                }
13526                                (Some(config), _) | (_, Some(config))
13527                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13528                                {
13529                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13530                                }
13531                                (Some(config), _) | (_, Some(config))
13532                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13533                                {
13534                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13535                                }
13536                                (_, _) => language_scope
13537                                    .line_comment_prefixes()
13538                                    .iter()
13539                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13540                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13541                            }
13542                        } else {
13543                            // we not in an overridden comment node, but we may
13544                            // be within a non-overridden line comment node
13545                            language_scope
13546                                .line_comment_prefixes()
13547                                .iter()
13548                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13549                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13550                        };
13551
13552                        let rewrap_prefix = language_scope
13553                            .rewrap_prefixes()
13554                            .iter()
13555                            .find_map(|prefix_regex| {
13556                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13557                                    if mat.start() == 0 {
13558                                        Some(mat.as_str().to_string())
13559                                    } else {
13560                                        None
13561                                    }
13562                                })
13563                            })
13564                            .flatten();
13565                        (comment_delimiters, rewrap_prefix)
13566                    } else {
13567                        (None, None)
13568                    };
13569                    (indent, comment_prefix, rewrap_prefix)
13570                };
13571
13572            let mut start_row = selection.start.row;
13573            let mut end_row = selection.end.row;
13574
13575            if selection.is_empty() {
13576                let cursor_row = selection.start.row;
13577
13578                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13579                let line_prefix = match &comment_prefix {
13580                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13581                        Some(prefix.as_str())
13582                    }
13583                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13584                        prefix, ..
13585                    })) => Some(prefix.as_ref()),
13586                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13587                        start: _,
13588                        end: _,
13589                        prefix,
13590                        tab_size,
13591                    })) => {
13592                        indent_size.len += tab_size;
13593                        Some(prefix.as_ref())
13594                    }
13595                    None => None,
13596                };
13597                let indent_prefix = indent_size.chars().collect::<String>();
13598                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13599
13600                'expand_upwards: while start_row > 0 {
13601                    let prev_row = start_row - 1;
13602                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13603                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13604                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13605                    {
13606                        start_row = prev_row;
13607                    } else {
13608                        break 'expand_upwards;
13609                    }
13610                }
13611
13612                'expand_downwards: while end_row < buffer.max_point().row {
13613                    let next_row = end_row + 1;
13614                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13615                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13616                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13617                    {
13618                        end_row = next_row;
13619                    } else {
13620                        break 'expand_downwards;
13621                    }
13622                }
13623            }
13624
13625            let mut non_blank_rows_iter = (start_row..=end_row)
13626                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13627                .peekable();
13628
13629            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13630                row
13631            } else {
13632                return Vec::new();
13633            };
13634
13635            let mut ranges = Vec::new();
13636
13637            let mut current_range_start = first_row;
13638            let mut prev_row = first_row;
13639            let (
13640                mut current_range_indent,
13641                mut current_range_comment_delimiters,
13642                mut current_range_rewrap_prefix,
13643            ) = indent_and_prefix_for_row(first_row);
13644
13645            for row in non_blank_rows_iter.skip(1) {
13646                let has_paragraph_break = row > prev_row + 1;
13647
13648                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13649                    indent_and_prefix_for_row(row);
13650
13651                let has_indent_change = row_indent != current_range_indent;
13652                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13653
13654                let has_boundary_change = has_comment_change
13655                    || row_rewrap_prefix.is_some()
13656                    || (has_indent_change && current_range_comment_delimiters.is_some());
13657
13658                if has_paragraph_break || has_boundary_change {
13659                    ranges.push((
13660                        language_settings.clone(),
13661                        Point::new(current_range_start, 0)
13662                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13663                        current_range_indent,
13664                        current_range_comment_delimiters.clone(),
13665                        current_range_rewrap_prefix.clone(),
13666                    ));
13667                    current_range_start = row;
13668                    current_range_indent = row_indent;
13669                    current_range_comment_delimiters = row_comment_delimiters;
13670                    current_range_rewrap_prefix = row_rewrap_prefix;
13671                }
13672                prev_row = row;
13673            }
13674
13675            ranges.push((
13676                language_settings.clone(),
13677                Point::new(current_range_start, 0)
13678                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13679                current_range_indent,
13680                current_range_comment_delimiters,
13681                current_range_rewrap_prefix,
13682            ));
13683
13684            ranges
13685        });
13686
13687        let mut edits = Vec::new();
13688        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13689
13690        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13691            wrap_ranges
13692        {
13693            let start_row = wrap_range.start.row;
13694            let end_row = wrap_range.end.row;
13695
13696            // Skip selections that overlap with a range that has already been rewrapped.
13697            let selection_range = start_row..end_row;
13698            if rewrapped_row_ranges
13699                .iter()
13700                .any(|range| range.overlaps(&selection_range))
13701            {
13702                continue;
13703            }
13704
13705            let tab_size = language_settings.tab_size;
13706
13707            let (line_prefix, inside_comment) = match &comment_prefix {
13708                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13709                    (Some(prefix.as_str()), true)
13710                }
13711                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13712                    (Some(prefix.as_ref()), true)
13713                }
13714                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13715                    start: _,
13716                    end: _,
13717                    prefix,
13718                    tab_size,
13719                })) => {
13720                    indent_size.len += tab_size;
13721                    (Some(prefix.as_ref()), true)
13722                }
13723                None => (None, false),
13724            };
13725            let indent_prefix = indent_size.chars().collect::<String>();
13726            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13727
13728            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13729                RewrapBehavior::InComments => inside_comment,
13730                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13731                RewrapBehavior::Anywhere => true,
13732            };
13733
13734            let should_rewrap = options.override_language_settings
13735                || allow_rewrap_based_on_language
13736                || self.hard_wrap.is_some();
13737            if !should_rewrap {
13738                continue;
13739            }
13740
13741            let start = Point::new(start_row, 0);
13742            let start_offset = ToOffset::to_offset(&start, &buffer);
13743            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13744            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13745            let mut first_line_delimiter = None;
13746            let mut last_line_delimiter = None;
13747            let Some(lines_without_prefixes) = selection_text
13748                .lines()
13749                .enumerate()
13750                .map(|(ix, line)| {
13751                    let line_trimmed = line.trim_start();
13752                    if rewrap_prefix.is_some() && ix > 0 {
13753                        Ok(line_trimmed)
13754                    } else if let Some(
13755                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13756                            start,
13757                            prefix,
13758                            end,
13759                            tab_size,
13760                        })
13761                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13762                            start,
13763                            prefix,
13764                            end,
13765                            tab_size,
13766                        }),
13767                    ) = &comment_prefix
13768                    {
13769                        let line_trimmed = line_trimmed
13770                            .strip_prefix(start.as_ref())
13771                            .map(|s| {
13772                                let mut indent_size = indent_size;
13773                                indent_size.len -= tab_size;
13774                                let indent_prefix: String = indent_size.chars().collect();
13775                                first_line_delimiter = Some((indent_prefix, start));
13776                                s.trim_start()
13777                            })
13778                            .unwrap_or(line_trimmed);
13779                        let line_trimmed = line_trimmed
13780                            .strip_suffix(end.as_ref())
13781                            .map(|s| {
13782                                last_line_delimiter = Some(end);
13783                                s.trim_end()
13784                            })
13785                            .unwrap_or(line_trimmed);
13786                        let line_trimmed = line_trimmed
13787                            .strip_prefix(prefix.as_ref())
13788                            .unwrap_or(line_trimmed);
13789                        Ok(line_trimmed)
13790                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13791                        line_trimmed.strip_prefix(prefix).with_context(|| {
13792                            format!("line did not start with prefix {prefix:?}: {line:?}")
13793                        })
13794                    } else {
13795                        line_trimmed
13796                            .strip_prefix(&line_prefix.trim_start())
13797                            .with_context(|| {
13798                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13799                            })
13800                    }
13801                })
13802                .collect::<Result<Vec<_>, _>>()
13803                .log_err()
13804            else {
13805                continue;
13806            };
13807
13808            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13809                buffer
13810                    .language_settings_at(Point::new(start_row, 0), cx)
13811                    .preferred_line_length as usize
13812            });
13813
13814            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13815                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13816            } else {
13817                line_prefix.clone()
13818            };
13819
13820            let wrapped_text = {
13821                let mut wrapped_text = wrap_with_prefix(
13822                    line_prefix,
13823                    subsequent_lines_prefix,
13824                    lines_without_prefixes.join("\n"),
13825                    wrap_column,
13826                    tab_size,
13827                    options.preserve_existing_whitespace,
13828                );
13829
13830                if let Some((indent, delimiter)) = first_line_delimiter {
13831                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13832                }
13833                if let Some(last_line) = last_line_delimiter {
13834                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13835                }
13836
13837                wrapped_text
13838            };
13839
13840            // TODO: should always use char-based diff while still supporting cursor behavior that
13841            // matches vim.
13842            let mut diff_options = DiffOptions::default();
13843            if options.override_language_settings {
13844                diff_options.max_word_diff_len = 0;
13845                diff_options.max_word_diff_line_count = 0;
13846            } else {
13847                diff_options.max_word_diff_len = usize::MAX;
13848                diff_options.max_word_diff_line_count = usize::MAX;
13849            }
13850
13851            for (old_range, new_text) in
13852                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13853            {
13854                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13855                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13856                edits.push((edit_start..edit_end, new_text));
13857            }
13858
13859            rewrapped_row_ranges.push(start_row..=end_row);
13860        }
13861
13862        self.buffer
13863            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13864    }
13865
13866    pub fn cut_common(
13867        &mut self,
13868        cut_no_selection_line: bool,
13869        window: &mut Window,
13870        cx: &mut Context<Self>,
13871    ) -> ClipboardItem {
13872        let mut text = String::new();
13873        let buffer = self.buffer.read(cx).snapshot(cx);
13874        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13875        let mut clipboard_selections = Vec::with_capacity(selections.len());
13876        {
13877            let max_point = buffer.max_point();
13878            let mut is_first = true;
13879            let mut prev_selection_was_entire_line = false;
13880            for selection in &mut selections {
13881                let is_entire_line =
13882                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13883                if is_entire_line {
13884                    selection.start = Point::new(selection.start.row, 0);
13885                    if !selection.is_empty() && selection.end.column == 0 {
13886                        selection.end = cmp::min(max_point, selection.end);
13887                    } else {
13888                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13889                    }
13890                    selection.goal = SelectionGoal::None;
13891                }
13892                if is_first {
13893                    is_first = false;
13894                } else if !prev_selection_was_entire_line {
13895                    text += "\n";
13896                }
13897                prev_selection_was_entire_line = is_entire_line;
13898                let mut len = 0;
13899                for chunk in buffer.text_for_range(selection.start..selection.end) {
13900                    text.push_str(chunk);
13901                    len += chunk.len();
13902                }
13903
13904                clipboard_selections.push(ClipboardSelection::for_buffer(
13905                    len,
13906                    is_entire_line,
13907                    selection.range(),
13908                    &buffer,
13909                    self.project.as_ref(),
13910                    cx,
13911                ));
13912            }
13913        }
13914
13915        self.transact(window, cx, |this, window, cx| {
13916            this.change_selections(Default::default(), window, cx, |s| {
13917                s.select(selections);
13918            });
13919            this.insert("", window, cx);
13920        });
13921        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13922    }
13923
13924    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13926        let item = self.cut_common(true, window, cx);
13927        cx.write_to_clipboard(item);
13928    }
13929
13930    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13932        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13933            s.move_with(&mut |snapshot, sel| {
13934                if sel.is_empty() {
13935                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13936                }
13937                if sel.is_empty() {
13938                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13939                }
13940            });
13941        });
13942        let item = self.cut_common(false, window, cx);
13943        cx.set_global(KillRing(item))
13944    }
13945
13946    pub fn kill_ring_yank(
13947        &mut self,
13948        _: &KillRingYank,
13949        window: &mut Window,
13950        cx: &mut Context<Self>,
13951    ) {
13952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13953        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13954            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13955                (kill_ring.text().to_string(), kill_ring.metadata_json())
13956            } else {
13957                return;
13958            }
13959        } else {
13960            return;
13961        };
13962        self.do_paste(&text, metadata, false, window, cx);
13963    }
13964
13965    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13966        self.do_copy(true, cx);
13967    }
13968
13969    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13970        self.do_copy(false, cx);
13971    }
13972
13973    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13974        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13975        let buffer = self.buffer.read(cx).read(cx);
13976        let mut text = String::new();
13977        let mut clipboard_selections = Vec::with_capacity(selections.len());
13978
13979        let max_point = buffer.max_point();
13980        let mut is_first = true;
13981        for selection in &selections {
13982            let mut start = selection.start;
13983            let mut end = selection.end;
13984            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13985            let mut add_trailing_newline = false;
13986            if is_entire_line {
13987                start = Point::new(start.row, 0);
13988                let next_line_start = Point::new(end.row + 1, 0);
13989                if next_line_start <= max_point {
13990                    end = next_line_start;
13991                } else {
13992                    // We're on the last line without a trailing newline.
13993                    // Copy to the end of the line and add a newline afterwards.
13994                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13995                    add_trailing_newline = true;
13996                }
13997            }
13998
13999            let mut trimmed_selections = Vec::new();
14000            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
14001                let row = MultiBufferRow(start.row);
14002                let first_indent = buffer.indent_size_for_line(row);
14003                if first_indent.len == 0 || start.column > first_indent.len {
14004                    trimmed_selections.push(start..end);
14005                } else {
14006                    trimmed_selections.push(
14007                        Point::new(row.0, first_indent.len)
14008                            ..Point::new(row.0, buffer.line_len(row)),
14009                    );
14010                    for row in start.row + 1..=end.row {
14011                        let mut line_len = buffer.line_len(MultiBufferRow(row));
14012                        if row == end.row {
14013                            line_len = end.column;
14014                        }
14015                        if line_len == 0 {
14016                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
14017                            continue;
14018                        }
14019                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
14020                        if row_indent_size.len >= first_indent.len {
14021                            trimmed_selections
14022                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
14023                        } else {
14024                            trimmed_selections.clear();
14025                            trimmed_selections.push(start..end);
14026                            break;
14027                        }
14028                    }
14029                }
14030            } else {
14031                trimmed_selections.push(start..end);
14032            }
14033
14034            let is_multiline_trim = trimmed_selections.len() > 1;
14035            let mut selection_len: usize = 0;
14036            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
14037
14038            for trimmed_range in trimmed_selections {
14039                if is_first {
14040                    is_first = false;
14041                } else if is_multiline_trim || !prev_selection_was_entire_line {
14042                    text.push('\n');
14043                    if is_multiline_trim {
14044                        selection_len += 1;
14045                    }
14046                }
14047                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
14048                    text.push_str(chunk);
14049                    selection_len += chunk.len();
14050                }
14051                if add_trailing_newline {
14052                    text.push('\n');
14053                    selection_len += 1;
14054                }
14055            }
14056
14057            clipboard_selections.push(ClipboardSelection::for_buffer(
14058                selection_len,
14059                is_entire_line,
14060                start..end,
14061                &buffer,
14062                self.project.as_ref(),
14063                cx,
14064            ));
14065        }
14066
14067        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
14068            text,
14069            clipboard_selections,
14070        ));
14071    }
14072
14073    pub fn do_paste(
14074        &mut self,
14075        text: &String,
14076        clipboard_selections: Option<Vec<ClipboardSelection>>,
14077        handle_entire_lines: bool,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) {
14081        if self.read_only(cx) {
14082            return;
14083        }
14084
14085        self.finalize_last_transaction(cx);
14086
14087        let clipboard_text = Cow::Borrowed(text.as_str());
14088
14089        self.transact(window, cx, |this, window, cx| {
14090            let had_active_edit_prediction = this.has_active_edit_prediction();
14091            let display_map = this.display_snapshot(cx);
14092            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14093            let cursor_offset = this
14094                .selections
14095                .last::<MultiBufferOffset>(&display_map)
14096                .head();
14097
14098            if let Some(mut clipboard_selections) = clipboard_selections {
14099                let all_selections_were_entire_line =
14100                    clipboard_selections.iter().all(|s| s.is_entire_line);
14101                let first_selection_indent_column =
14102                    clipboard_selections.first().map(|s| s.first_line_indent);
14103                if clipboard_selections.len() != old_selections.len() {
14104                    clipboard_selections.drain(..);
14105                }
14106                let mut auto_indent_on_paste = true;
14107
14108                this.buffer.update(cx, |buffer, cx| {
14109                    let snapshot = buffer.read(cx);
14110                    auto_indent_on_paste = snapshot
14111                        .language_settings_at(cursor_offset, cx)
14112                        .auto_indent_on_paste;
14113
14114                    let mut start_offset = 0;
14115                    let mut edits = Vec::new();
14116                    let mut original_indent_columns = Vec::new();
14117                    for (ix, selection) in old_selections.iter().enumerate() {
14118                        let to_insert;
14119                        let entire_line;
14120                        let original_indent_column;
14121                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14122                            let end_offset = start_offset + clipboard_selection.len;
14123                            to_insert = &clipboard_text[start_offset..end_offset];
14124                            entire_line = clipboard_selection.is_entire_line;
14125                            start_offset = if entire_line {
14126                                end_offset
14127                            } else {
14128                                end_offset + 1
14129                            };
14130                            original_indent_column = Some(clipboard_selection.first_line_indent);
14131                        } else {
14132                            to_insert = &*clipboard_text;
14133                            entire_line = all_selections_were_entire_line;
14134                            original_indent_column = first_selection_indent_column
14135                        }
14136
14137                        let (range, to_insert) =
14138                            if selection.is_empty() && handle_entire_lines && entire_line {
14139                                // If the corresponding selection was empty when this slice of the
14140                                // clipboard text was written, then the entire line containing the
14141                                // selection was copied. If this selection is also currently empty,
14142                                // then paste the line before the current line of the buffer.
14143                                let column = selection.start.to_point(&snapshot).column as usize;
14144                                let line_start = selection.start - column;
14145                                (line_start..line_start, Cow::Borrowed(to_insert))
14146                            } else {
14147                                let language = snapshot.language_at(selection.head());
14148                                let range = selection.range();
14149                                if let Some(language) = language
14150                                    && language.name() == "Markdown"
14151                                {
14152                                    edit_for_markdown_paste(
14153                                        &snapshot,
14154                                        range,
14155                                        to_insert,
14156                                        url::Url::parse(to_insert).ok(),
14157                                    )
14158                                } else {
14159                                    (range, Cow::Borrowed(to_insert))
14160                                }
14161                            };
14162
14163                        edits.push((range, to_insert));
14164                        original_indent_columns.push(original_indent_column);
14165                    }
14166                    drop(snapshot);
14167
14168                    buffer.edit(
14169                        edits,
14170                        if auto_indent_on_paste {
14171                            Some(AutoindentMode::Block {
14172                                original_indent_columns,
14173                            })
14174                        } else {
14175                            None
14176                        },
14177                        cx,
14178                    );
14179                });
14180
14181                let selections = this
14182                    .selections
14183                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14184                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14185            } else {
14186                let url = url::Url::parse(&clipboard_text).ok();
14187
14188                let auto_indent_mode = if !clipboard_text.is_empty() {
14189                    Some(AutoindentMode::Block {
14190                        original_indent_columns: Vec::new(),
14191                    })
14192                } else {
14193                    None
14194                };
14195
14196                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14197                    let snapshot = buffer.snapshot(cx);
14198
14199                    let anchors = old_selections
14200                        .iter()
14201                        .map(|s| {
14202                            let anchor = snapshot.anchor_after(s.head());
14203                            s.map(|_| anchor)
14204                        })
14205                        .collect::<Vec<_>>();
14206
14207                    let mut edits = Vec::new();
14208
14209                    // When pasting text without metadata (e.g. copied from an
14210                    // external editor using multiple cursors) and the number of
14211                    // lines matches the number of selections, distribute one
14212                    // line per cursor instead of pasting the whole text at each.
14213                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14214                    let distribute_lines =
14215                        old_selections.len() > 1 && lines.len() == old_selections.len();
14216
14217                    for (ix, selection) in old_selections.iter().enumerate() {
14218                        let language = snapshot.language_at(selection.head());
14219                        let range = selection.range();
14220
14221                        let text_for_cursor: &str = if distribute_lines {
14222                            lines[ix]
14223                        } else {
14224                            &clipboard_text
14225                        };
14226
14227                        let (edit_range, edit_text) = if let Some(language) = language
14228                            && language.name() == "Markdown"
14229                        {
14230                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14231                        } else {
14232                            (range, Cow::Borrowed(text_for_cursor))
14233                        };
14234
14235                        edits.push((edit_range, edit_text));
14236                    }
14237
14238                    drop(snapshot);
14239                    buffer.edit(edits, auto_indent_mode, cx);
14240
14241                    anchors
14242                });
14243
14244                this.change_selections(Default::default(), window, cx, |s| {
14245                    s.select_anchors(selection_anchors);
14246                });
14247            }
14248
14249            //   🤔                 |    ..     | show_in_menu |
14250            // | ..                  |   true        true
14251            // | had_edit_prediction |   false       true
14252
14253            let trigger_in_words =
14254                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14255
14256            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14257        });
14258    }
14259
14260    pub fn diff_clipboard_with_selection(
14261        &mut self,
14262        _: &DiffClipboardWithSelection,
14263        window: &mut Window,
14264        cx: &mut Context<Self>,
14265    ) {
14266        let selections = self
14267            .selections
14268            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14269
14270        if selections.is_empty() {
14271            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14272            return;
14273        };
14274
14275        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14276            item.entries().iter().find_map(|entry| match entry {
14277                ClipboardEntry::String(text) => Some(text.text().to_string()),
14278                _ => None,
14279            })
14280        });
14281
14282        let Some(clipboard_text) = clipboard_text else {
14283            log::warn!("Clipboard doesn't contain text.");
14284            return;
14285        };
14286
14287        window.dispatch_action(
14288            Box::new(DiffClipboardWithSelectionData {
14289                clipboard_text,
14290                editor: cx.entity(),
14291            }),
14292            cx,
14293        );
14294    }
14295
14296    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14297        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14298        if let Some(item) = cx.read_from_clipboard() {
14299            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14300                ClipboardEntry::String(s) => Some(s),
14301                _ => None,
14302            });
14303            match clipboard_string {
14304                Some(clipboard_string) => self.do_paste(
14305                    clipboard_string.text(),
14306                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14307                    true,
14308                    window,
14309                    cx,
14310                ),
14311                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14312            }
14313        }
14314    }
14315
14316    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14317        if self.read_only(cx) {
14318            return;
14319        }
14320
14321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14322
14323        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14324            if let Some((selections, _)) =
14325                self.selection_history.transaction(transaction_id).cloned()
14326            {
14327                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14328                    s.select_anchors(selections.to_vec());
14329                });
14330            } else {
14331                log::error!(
14332                    "No entry in selection_history found for undo. \
14333                     This may correspond to a bug where undo does not update the selection. \
14334                     If this is occurring, please add details to \
14335                     https://github.com/zed-industries/zed/issues/22692"
14336                );
14337            }
14338            self.request_autoscroll(Autoscroll::fit(), cx);
14339            self.unmark_text(window, cx);
14340            self.refresh_edit_prediction(true, false, window, cx);
14341            cx.emit(EditorEvent::Edited { transaction_id });
14342            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14343        }
14344    }
14345
14346    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14347        if self.read_only(cx) {
14348            return;
14349        }
14350
14351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14352
14353        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14354            if let Some((_, Some(selections))) =
14355                self.selection_history.transaction(transaction_id).cloned()
14356            {
14357                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14358                    s.select_anchors(selections.to_vec());
14359                });
14360            } else {
14361                log::error!(
14362                    "No entry in selection_history found for redo. \
14363                     This may correspond to a bug where undo does not update the selection. \
14364                     If this is occurring, please add details to \
14365                     https://github.com/zed-industries/zed/issues/22692"
14366                );
14367            }
14368            self.request_autoscroll(Autoscroll::fit(), cx);
14369            self.unmark_text(window, cx);
14370            self.refresh_edit_prediction(true, false, window, cx);
14371            cx.emit(EditorEvent::Edited { transaction_id });
14372        }
14373    }
14374
14375    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14376        self.buffer
14377            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14378    }
14379
14380    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14381        self.buffer
14382            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14383    }
14384
14385    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387        self.change_selections(Default::default(), window, cx, |s| {
14388            s.move_with(&mut |map, selection| {
14389                let cursor = if selection.is_empty() {
14390                    movement::left(map, selection.start)
14391                } else {
14392                    selection.start
14393                };
14394                selection.collapse_to(cursor, SelectionGoal::None);
14395            });
14396        })
14397    }
14398
14399    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14401        self.change_selections(Default::default(), window, cx, |s| {
14402            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14403        })
14404    }
14405
14406    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(Default::default(), window, cx, |s| {
14409            s.move_with(&mut |map, selection| {
14410                let cursor = if selection.is_empty() {
14411                    movement::right(map, selection.end)
14412                } else {
14413                    selection.end
14414                };
14415                selection.collapse_to(cursor, SelectionGoal::None)
14416            });
14417        })
14418    }
14419
14420    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14422        self.change_selections(Default::default(), window, cx, |s| {
14423            s.move_heads_with(&mut |map, head, _| {
14424                (movement::right(map, head), SelectionGoal::None)
14425            });
14426        });
14427    }
14428
14429    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14430        if self.take_rename(true, window, cx).is_some() {
14431            return;
14432        }
14433
14434        if self.mode.is_single_line() {
14435            cx.propagate();
14436            return;
14437        }
14438
14439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14440
14441        let text_layout_details = &self.text_layout_details(window, cx);
14442        let selection_count = self.selections.count();
14443        let first_selection = self.selections.first_anchor();
14444
14445        self.change_selections(Default::default(), window, cx, |s| {
14446            s.move_with(&mut |map, selection| {
14447                if !selection.is_empty() {
14448                    selection.goal = SelectionGoal::None;
14449                }
14450                let (cursor, goal) = movement::up(
14451                    map,
14452                    selection.start,
14453                    selection.goal,
14454                    false,
14455                    text_layout_details,
14456                );
14457                selection.collapse_to(cursor, goal);
14458            });
14459        });
14460
14461        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14462        {
14463            cx.propagate();
14464        }
14465    }
14466
14467    pub fn move_up_by_lines(
14468        &mut self,
14469        action: &MoveUpByLines,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) {
14473        if self.take_rename(true, window, cx).is_some() {
14474            return;
14475        }
14476
14477        if self.mode.is_single_line() {
14478            cx.propagate();
14479            return;
14480        }
14481
14482        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14483
14484        let text_layout_details = &self.text_layout_details(window, cx);
14485
14486        self.change_selections(Default::default(), window, cx, |s| {
14487            s.move_with(&mut |map, selection| {
14488                if !selection.is_empty() {
14489                    selection.goal = SelectionGoal::None;
14490                }
14491                let (cursor, goal) = movement::up_by_rows(
14492                    map,
14493                    selection.start,
14494                    action.lines,
14495                    selection.goal,
14496                    false,
14497                    text_layout_details,
14498                );
14499                selection.collapse_to(cursor, goal);
14500            });
14501        })
14502    }
14503
14504    pub fn move_down_by_lines(
14505        &mut self,
14506        action: &MoveDownByLines,
14507        window: &mut Window,
14508        cx: &mut Context<Self>,
14509    ) {
14510        if self.take_rename(true, window, cx).is_some() {
14511            return;
14512        }
14513
14514        if self.mode.is_single_line() {
14515            cx.propagate();
14516            return;
14517        }
14518
14519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14520
14521        let text_layout_details = &self.text_layout_details(window, cx);
14522
14523        self.change_selections(Default::default(), window, cx, |s| {
14524            s.move_with(&mut |map, selection| {
14525                if !selection.is_empty() {
14526                    selection.goal = SelectionGoal::None;
14527                }
14528                let (cursor, goal) = movement::down_by_rows(
14529                    map,
14530                    selection.start,
14531                    action.lines,
14532                    selection.goal,
14533                    false,
14534                    text_layout_details,
14535                );
14536                selection.collapse_to(cursor, goal);
14537            });
14538        })
14539    }
14540
14541    pub fn select_down_by_lines(
14542        &mut self,
14543        action: &SelectDownByLines,
14544        window: &mut Window,
14545        cx: &mut Context<Self>,
14546    ) {
14547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14548        let text_layout_details = &self.text_layout_details(window, cx);
14549        self.change_selections(Default::default(), window, cx, |s| {
14550            s.move_heads_with(&mut |map, head, goal| {
14551                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14552            })
14553        })
14554    }
14555
14556    pub fn select_up_by_lines(
14557        &mut self,
14558        action: &SelectUpByLines,
14559        window: &mut Window,
14560        cx: &mut Context<Self>,
14561    ) {
14562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14563        let text_layout_details = &self.text_layout_details(window, cx);
14564        self.change_selections(Default::default(), window, cx, |s| {
14565            s.move_heads_with(&mut |map, head, goal| {
14566                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14567            })
14568        })
14569    }
14570
14571    pub fn select_page_up(
14572        &mut self,
14573        _: &SelectPageUp,
14574        window: &mut Window,
14575        cx: &mut Context<Self>,
14576    ) {
14577        let Some(row_count) = self.visible_row_count() else {
14578            return;
14579        };
14580
14581        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14582
14583        let text_layout_details = &self.text_layout_details(window, cx);
14584
14585        self.change_selections(Default::default(), window, cx, |s| {
14586            s.move_heads_with(&mut |map, head, goal| {
14587                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14588            })
14589        })
14590    }
14591
14592    pub fn move_page_up(
14593        &mut self,
14594        action: &MovePageUp,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) {
14598        if self.take_rename(true, window, cx).is_some() {
14599            return;
14600        }
14601
14602        if self
14603            .context_menu
14604            .borrow_mut()
14605            .as_mut()
14606            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14607            .unwrap_or(false)
14608        {
14609            return;
14610        }
14611
14612        if matches!(self.mode, EditorMode::SingleLine) {
14613            cx.propagate();
14614            return;
14615        }
14616
14617        let Some(row_count) = self.visible_row_count() else {
14618            return;
14619        };
14620
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622
14623        let effects = if action.center_cursor {
14624            SelectionEffects::scroll(Autoscroll::center())
14625        } else {
14626            SelectionEffects::default()
14627        };
14628
14629        let text_layout_details = &self.text_layout_details(window, cx);
14630
14631        self.change_selections(effects, window, cx, |s| {
14632            s.move_with(&mut |map, selection| {
14633                if !selection.is_empty() {
14634                    selection.goal = SelectionGoal::None;
14635                }
14636                let (cursor, goal) = movement::up_by_rows(
14637                    map,
14638                    selection.end,
14639                    row_count,
14640                    selection.goal,
14641                    false,
14642                    text_layout_details,
14643                );
14644                selection.collapse_to(cursor, goal);
14645            });
14646        });
14647    }
14648
14649    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14651        let text_layout_details = &self.text_layout_details(window, cx);
14652        self.change_selections(Default::default(), window, cx, |s| {
14653            s.move_heads_with(&mut |map, head, goal| {
14654                movement::up(map, head, goal, false, text_layout_details)
14655            })
14656        })
14657    }
14658
14659    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14660        self.take_rename(true, window, cx);
14661
14662        if self.mode.is_single_line() {
14663            cx.propagate();
14664            return;
14665        }
14666
14667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14668
14669        let text_layout_details = &self.text_layout_details(window, cx);
14670        let selection_count = self.selections.count();
14671        let first_selection = self.selections.first_anchor();
14672
14673        self.change_selections(Default::default(), window, cx, |s| {
14674            s.move_with(&mut |map, selection| {
14675                if !selection.is_empty() {
14676                    selection.goal = SelectionGoal::None;
14677                }
14678                let (cursor, goal) = movement::down(
14679                    map,
14680                    selection.end,
14681                    selection.goal,
14682                    false,
14683                    text_layout_details,
14684                );
14685                selection.collapse_to(cursor, goal);
14686            });
14687        });
14688
14689        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14690        {
14691            cx.propagate();
14692        }
14693    }
14694
14695    pub fn select_page_down(
14696        &mut self,
14697        _: &SelectPageDown,
14698        window: &mut Window,
14699        cx: &mut Context<Self>,
14700    ) {
14701        let Some(row_count) = self.visible_row_count() else {
14702            return;
14703        };
14704
14705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14706
14707        let text_layout_details = &self.text_layout_details(window, cx);
14708
14709        self.change_selections(Default::default(), window, cx, |s| {
14710            s.move_heads_with(&mut |map, head, goal| {
14711                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14712            })
14713        })
14714    }
14715
14716    pub fn move_page_down(
14717        &mut self,
14718        action: &MovePageDown,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) {
14722        if self.take_rename(true, window, cx).is_some() {
14723            return;
14724        }
14725
14726        if self
14727            .context_menu
14728            .borrow_mut()
14729            .as_mut()
14730            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14731            .unwrap_or(false)
14732        {
14733            return;
14734        }
14735
14736        if matches!(self.mode, EditorMode::SingleLine) {
14737            cx.propagate();
14738            return;
14739        }
14740
14741        let Some(row_count) = self.visible_row_count() else {
14742            return;
14743        };
14744
14745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14746
14747        let effects = if action.center_cursor {
14748            SelectionEffects::scroll(Autoscroll::center())
14749        } else {
14750            SelectionEffects::default()
14751        };
14752
14753        let text_layout_details = &self.text_layout_details(window, cx);
14754        self.change_selections(effects, window, cx, |s| {
14755            s.move_with(&mut |map, selection| {
14756                if !selection.is_empty() {
14757                    selection.goal = SelectionGoal::None;
14758                }
14759                let (cursor, goal) = movement::down_by_rows(
14760                    map,
14761                    selection.end,
14762                    row_count,
14763                    selection.goal,
14764                    false,
14765                    text_layout_details,
14766                );
14767                selection.collapse_to(cursor, goal);
14768            });
14769        });
14770    }
14771
14772    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14774        let text_layout_details = &self.text_layout_details(window, cx);
14775        self.change_selections(Default::default(), window, cx, |s| {
14776            s.move_heads_with(&mut |map, head, goal| {
14777                movement::down(map, head, goal, false, text_layout_details)
14778            })
14779        });
14780    }
14781
14782    pub fn context_menu_first(
14783        &mut self,
14784        _: &ContextMenuFirst,
14785        window: &mut Window,
14786        cx: &mut Context<Self>,
14787    ) {
14788        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14789            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14790        }
14791    }
14792
14793    pub fn context_menu_prev(
14794        &mut self,
14795        _: &ContextMenuPrevious,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) {
14799        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14800            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14801        }
14802    }
14803
14804    pub fn context_menu_next(
14805        &mut self,
14806        _: &ContextMenuNext,
14807        window: &mut Window,
14808        cx: &mut Context<Self>,
14809    ) {
14810        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14811            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14812        }
14813    }
14814
14815    pub fn context_menu_last(
14816        &mut self,
14817        _: &ContextMenuLast,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14822            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14823        }
14824    }
14825
14826    pub fn signature_help_prev(
14827        &mut self,
14828        _: &SignatureHelpPrevious,
14829        _: &mut Window,
14830        cx: &mut Context<Self>,
14831    ) {
14832        if let Some(popover) = self.signature_help_state.popover_mut() {
14833            if popover.current_signature == 0 {
14834                popover.current_signature = popover.signatures.len() - 1;
14835            } else {
14836                popover.current_signature -= 1;
14837            }
14838            cx.notify();
14839        }
14840    }
14841
14842    pub fn signature_help_next(
14843        &mut self,
14844        _: &SignatureHelpNext,
14845        _: &mut Window,
14846        cx: &mut Context<Self>,
14847    ) {
14848        if let Some(popover) = self.signature_help_state.popover_mut() {
14849            if popover.current_signature + 1 == popover.signatures.len() {
14850                popover.current_signature = 0;
14851            } else {
14852                popover.current_signature += 1;
14853            }
14854            cx.notify();
14855        }
14856    }
14857
14858    pub fn move_to_previous_word_start(
14859        &mut self,
14860        _: &MoveToPreviousWordStart,
14861        window: &mut Window,
14862        cx: &mut Context<Self>,
14863    ) {
14864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14865        self.change_selections(Default::default(), window, cx, |s| {
14866            s.move_cursors_with(&mut |map, head, _| {
14867                (
14868                    movement::previous_word_start(map, head),
14869                    SelectionGoal::None,
14870                )
14871            });
14872        })
14873    }
14874
14875    pub fn move_to_previous_subword_start(
14876        &mut self,
14877        _: &MoveToPreviousSubwordStart,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) {
14881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14882        self.change_selections(Default::default(), window, cx, |s| {
14883            s.move_cursors_with(&mut |map, head, _| {
14884                (
14885                    movement::previous_subword_start(map, head),
14886                    SelectionGoal::None,
14887                )
14888            });
14889        })
14890    }
14891
14892    pub fn select_to_previous_word_start(
14893        &mut self,
14894        _: &SelectToPreviousWordStart,
14895        window: &mut Window,
14896        cx: &mut Context<Self>,
14897    ) {
14898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14899        self.change_selections(Default::default(), window, cx, |s| {
14900            s.move_heads_with(&mut |map, head, _| {
14901                (
14902                    movement::previous_word_start(map, head),
14903                    SelectionGoal::None,
14904                )
14905            });
14906        })
14907    }
14908
14909    pub fn select_to_previous_subword_start(
14910        &mut self,
14911        _: &SelectToPreviousSubwordStart,
14912        window: &mut Window,
14913        cx: &mut Context<Self>,
14914    ) {
14915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14916        self.change_selections(Default::default(), window, cx, |s| {
14917            s.move_heads_with(&mut |map, head, _| {
14918                (
14919                    movement::previous_subword_start(map, head),
14920                    SelectionGoal::None,
14921                )
14922            });
14923        })
14924    }
14925
14926    pub fn delete_to_previous_word_start(
14927        &mut self,
14928        action: &DeleteToPreviousWordStart,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) {
14932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14933        self.transact(window, cx, |this, window, cx| {
14934            this.select_autoclose_pair(window, cx);
14935            this.change_selections(Default::default(), window, cx, |s| {
14936                s.move_with(&mut |map, selection| {
14937                    if selection.is_empty() {
14938                        let mut cursor = if action.ignore_newlines {
14939                            movement::previous_word_start(map, selection.head())
14940                        } else {
14941                            movement::previous_word_start_or_newline(map, selection.head())
14942                        };
14943                        cursor = movement::adjust_greedy_deletion(
14944                            map,
14945                            selection.head(),
14946                            cursor,
14947                            action.ignore_brackets,
14948                        );
14949                        selection.set_head(cursor, SelectionGoal::None);
14950                    }
14951                });
14952            });
14953            this.insert("", window, cx);
14954        });
14955    }
14956
14957    pub fn delete_to_previous_subword_start(
14958        &mut self,
14959        action: &DeleteToPreviousSubwordStart,
14960        window: &mut Window,
14961        cx: &mut Context<Self>,
14962    ) {
14963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14964        self.transact(window, cx, |this, window, cx| {
14965            this.select_autoclose_pair(window, cx);
14966            this.change_selections(Default::default(), window, cx, |s| {
14967                s.move_with(&mut |map, selection| {
14968                    if selection.is_empty() {
14969                        let mut cursor = if action.ignore_newlines {
14970                            movement::previous_subword_start(map, selection.head())
14971                        } else {
14972                            movement::previous_subword_start_or_newline(map, selection.head())
14973                        };
14974                        cursor = movement::adjust_greedy_deletion(
14975                            map,
14976                            selection.head(),
14977                            cursor,
14978                            action.ignore_brackets,
14979                        );
14980                        selection.set_head(cursor, SelectionGoal::None);
14981                    }
14982                });
14983            });
14984            this.insert("", window, cx);
14985        });
14986    }
14987
14988    pub fn move_to_next_word_end(
14989        &mut self,
14990        _: &MoveToNextWordEnd,
14991        window: &mut Window,
14992        cx: &mut Context<Self>,
14993    ) {
14994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14995        self.change_selections(Default::default(), window, cx, |s| {
14996            s.move_cursors_with(&mut |map, head, _| {
14997                (movement::next_word_end(map, head), SelectionGoal::None)
14998            });
14999        })
15000    }
15001
15002    pub fn move_to_next_subword_end(
15003        &mut self,
15004        _: &MoveToNextSubwordEnd,
15005        window: &mut Window,
15006        cx: &mut Context<Self>,
15007    ) {
15008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15009        self.change_selections(Default::default(), window, cx, |s| {
15010            s.move_cursors_with(&mut |map, head, _| {
15011                (movement::next_subword_end(map, head), SelectionGoal::None)
15012            });
15013        })
15014    }
15015
15016    pub fn select_to_next_word_end(
15017        &mut self,
15018        _: &SelectToNextWordEnd,
15019        window: &mut Window,
15020        cx: &mut Context<Self>,
15021    ) {
15022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15023        self.change_selections(Default::default(), window, cx, |s| {
15024            s.move_heads_with(&mut |map, head, _| {
15025                (movement::next_word_end(map, head), SelectionGoal::None)
15026            });
15027        })
15028    }
15029
15030    pub fn select_to_next_subword_end(
15031        &mut self,
15032        _: &SelectToNextSubwordEnd,
15033        window: &mut Window,
15034        cx: &mut Context<Self>,
15035    ) {
15036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15037        self.change_selections(Default::default(), window, cx, |s| {
15038            s.move_heads_with(&mut |map, head, _| {
15039                (movement::next_subword_end(map, head), SelectionGoal::None)
15040            });
15041        })
15042    }
15043
15044    pub fn delete_to_next_word_end(
15045        &mut self,
15046        action: &DeleteToNextWordEnd,
15047        window: &mut Window,
15048        cx: &mut Context<Self>,
15049    ) {
15050        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15051        self.transact(window, cx, |this, window, cx| {
15052            this.change_selections(Default::default(), window, cx, |s| {
15053                s.move_with(&mut |map, selection| {
15054                    if selection.is_empty() {
15055                        let mut cursor = if action.ignore_newlines {
15056                            movement::next_word_end(map, selection.head())
15057                        } else {
15058                            movement::next_word_end_or_newline(map, selection.head())
15059                        };
15060                        cursor = movement::adjust_greedy_deletion(
15061                            map,
15062                            selection.head(),
15063                            cursor,
15064                            action.ignore_brackets,
15065                        );
15066                        selection.set_head(cursor, SelectionGoal::None);
15067                    }
15068                });
15069            });
15070            this.insert("", window, cx);
15071        });
15072    }
15073
15074    pub fn delete_to_next_subword_end(
15075        &mut self,
15076        action: &DeleteToNextSubwordEnd,
15077        window: &mut Window,
15078        cx: &mut Context<Self>,
15079    ) {
15080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15081        self.transact(window, cx, |this, window, cx| {
15082            this.change_selections(Default::default(), window, cx, |s| {
15083                s.move_with(&mut |map, selection| {
15084                    if selection.is_empty() {
15085                        let mut cursor = if action.ignore_newlines {
15086                            movement::next_subword_end(map, selection.head())
15087                        } else {
15088                            movement::next_subword_end_or_newline(map, selection.head())
15089                        };
15090                        cursor = movement::adjust_greedy_deletion(
15091                            map,
15092                            selection.head(),
15093                            cursor,
15094                            action.ignore_brackets,
15095                        );
15096                        selection.set_head(cursor, SelectionGoal::None);
15097                    }
15098                });
15099            });
15100            this.insert("", window, cx);
15101        });
15102    }
15103
15104    pub fn move_to_beginning_of_line(
15105        &mut self,
15106        action: &MoveToBeginningOfLine,
15107        window: &mut Window,
15108        cx: &mut Context<Self>,
15109    ) {
15110        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15112        self.change_selections(Default::default(), window, cx, |s| {
15113            s.move_cursors_with(&mut |map, head, _| {
15114                (
15115                    movement::indented_line_beginning(
15116                        map,
15117                        head,
15118                        action.stop_at_soft_wraps,
15119                        stop_at_indent,
15120                    ),
15121                    SelectionGoal::None,
15122                )
15123            });
15124        })
15125    }
15126
15127    pub fn select_to_beginning_of_line(
15128        &mut self,
15129        action: &SelectToBeginningOfLine,
15130        window: &mut Window,
15131        cx: &mut Context<Self>,
15132    ) {
15133        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15135        self.change_selections(Default::default(), window, cx, |s| {
15136            s.move_heads_with(&mut |map, head, _| {
15137                (
15138                    movement::indented_line_beginning(
15139                        map,
15140                        head,
15141                        action.stop_at_soft_wraps,
15142                        stop_at_indent,
15143                    ),
15144                    SelectionGoal::None,
15145                )
15146            });
15147        });
15148    }
15149
15150    pub fn delete_to_beginning_of_line(
15151        &mut self,
15152        action: &DeleteToBeginningOfLine,
15153        window: &mut Window,
15154        cx: &mut Context<Self>,
15155    ) {
15156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15157        self.transact(window, cx, |this, window, cx| {
15158            this.change_selections(Default::default(), window, cx, |s| {
15159                s.move_with(&mut |_, selection| {
15160                    selection.reversed = true;
15161                });
15162            });
15163
15164            this.select_to_beginning_of_line(
15165                &SelectToBeginningOfLine {
15166                    stop_at_soft_wraps: false,
15167                    stop_at_indent: action.stop_at_indent,
15168                },
15169                window,
15170                cx,
15171            );
15172            this.backspace(&Backspace, window, cx);
15173        });
15174    }
15175
15176    pub fn move_to_end_of_line(
15177        &mut self,
15178        action: &MoveToEndOfLine,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) {
15182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15183        self.change_selections(Default::default(), window, cx, |s| {
15184            s.move_cursors_with(&mut |map, head, _| {
15185                (
15186                    movement::line_end(map, head, action.stop_at_soft_wraps),
15187                    SelectionGoal::None,
15188                )
15189            });
15190        })
15191    }
15192
15193    pub fn select_to_end_of_line(
15194        &mut self,
15195        action: &SelectToEndOfLine,
15196        window: &mut Window,
15197        cx: &mut Context<Self>,
15198    ) {
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200        self.change_selections(Default::default(), window, cx, |s| {
15201            s.move_heads_with(&mut |map, head, _| {
15202                (
15203                    movement::line_end(map, head, action.stop_at_soft_wraps),
15204                    SelectionGoal::None,
15205                )
15206            });
15207        })
15208    }
15209
15210    pub fn delete_to_end_of_line(
15211        &mut self,
15212        _: &DeleteToEndOfLine,
15213        window: &mut Window,
15214        cx: &mut Context<Self>,
15215    ) {
15216        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15217        self.transact(window, cx, |this, window, cx| {
15218            this.select_to_end_of_line(
15219                &SelectToEndOfLine {
15220                    stop_at_soft_wraps: false,
15221                },
15222                window,
15223                cx,
15224            );
15225            this.delete(&Delete, window, cx);
15226        });
15227    }
15228
15229    pub fn cut_to_end_of_line(
15230        &mut self,
15231        action: &CutToEndOfLine,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15236        self.transact(window, cx, |this, window, cx| {
15237            this.select_to_end_of_line(
15238                &SelectToEndOfLine {
15239                    stop_at_soft_wraps: false,
15240                },
15241                window,
15242                cx,
15243            );
15244            if !action.stop_at_newlines {
15245                this.change_selections(Default::default(), window, cx, |s| {
15246                    s.move_with(&mut |_, sel| {
15247                        if sel.is_empty() {
15248                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15249                        }
15250                    });
15251                });
15252            }
15253            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15254            let item = this.cut_common(false, window, cx);
15255            cx.write_to_clipboard(item);
15256        });
15257    }
15258
15259    pub fn move_to_start_of_paragraph(
15260        &mut self,
15261        _: &MoveToStartOfParagraph,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        if matches!(self.mode, EditorMode::SingleLine) {
15266            cx.propagate();
15267            return;
15268        }
15269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15270        self.change_selections(Default::default(), window, cx, |s| {
15271            s.move_with(&mut |map, selection| {
15272                selection.collapse_to(
15273                    movement::start_of_paragraph(map, selection.head(), 1),
15274                    SelectionGoal::None,
15275                )
15276            });
15277        })
15278    }
15279
15280    pub fn move_to_end_of_paragraph(
15281        &mut self,
15282        _: &MoveToEndOfParagraph,
15283        window: &mut Window,
15284        cx: &mut Context<Self>,
15285    ) {
15286        if matches!(self.mode, EditorMode::SingleLine) {
15287            cx.propagate();
15288            return;
15289        }
15290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15291        self.change_selections(Default::default(), window, cx, |s| {
15292            s.move_with(&mut |map, selection| {
15293                selection.collapse_to(
15294                    movement::end_of_paragraph(map, selection.head(), 1),
15295                    SelectionGoal::None,
15296                )
15297            });
15298        })
15299    }
15300
15301    pub fn select_to_start_of_paragraph(
15302        &mut self,
15303        _: &SelectToStartOfParagraph,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        if matches!(self.mode, EditorMode::SingleLine) {
15308            cx.propagate();
15309            return;
15310        }
15311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15312        self.change_selections(Default::default(), window, cx, |s| {
15313            s.move_heads_with(&mut |map, head, _| {
15314                (
15315                    movement::start_of_paragraph(map, head, 1),
15316                    SelectionGoal::None,
15317                )
15318            });
15319        })
15320    }
15321
15322    pub fn select_to_end_of_paragraph(
15323        &mut self,
15324        _: &SelectToEndOfParagraph,
15325        window: &mut Window,
15326        cx: &mut Context<Self>,
15327    ) {
15328        if matches!(self.mode, EditorMode::SingleLine) {
15329            cx.propagate();
15330            return;
15331        }
15332        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15333        self.change_selections(Default::default(), window, cx, |s| {
15334            s.move_heads_with(&mut |map, head, _| {
15335                (
15336                    movement::end_of_paragraph(map, head, 1),
15337                    SelectionGoal::None,
15338                )
15339            });
15340        })
15341    }
15342
15343    pub fn move_to_start_of_excerpt(
15344        &mut self,
15345        _: &MoveToStartOfExcerpt,
15346        window: &mut Window,
15347        cx: &mut Context<Self>,
15348    ) {
15349        if matches!(self.mode, EditorMode::SingleLine) {
15350            cx.propagate();
15351            return;
15352        }
15353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15354        self.change_selections(Default::default(), window, cx, |s| {
15355            s.move_with(&mut |map, selection| {
15356                selection.collapse_to(
15357                    movement::start_of_excerpt(
15358                        map,
15359                        selection.head(),
15360                        workspace::searchable::Direction::Prev,
15361                    ),
15362                    SelectionGoal::None,
15363                )
15364            });
15365        })
15366    }
15367
15368    pub fn move_to_start_of_next_excerpt(
15369        &mut self,
15370        _: &MoveToStartOfNextExcerpt,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) {
15374        if matches!(self.mode, EditorMode::SingleLine) {
15375            cx.propagate();
15376            return;
15377        }
15378
15379        self.change_selections(Default::default(), window, cx, |s| {
15380            s.move_with(&mut |map, selection| {
15381                selection.collapse_to(
15382                    movement::start_of_excerpt(
15383                        map,
15384                        selection.head(),
15385                        workspace::searchable::Direction::Next,
15386                    ),
15387                    SelectionGoal::None,
15388                )
15389            });
15390        })
15391    }
15392
15393    pub fn move_to_end_of_excerpt(
15394        &mut self,
15395        _: &MoveToEndOfExcerpt,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) {
15399        if matches!(self.mode, EditorMode::SingleLine) {
15400            cx.propagate();
15401            return;
15402        }
15403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15404        self.change_selections(Default::default(), window, cx, |s| {
15405            s.move_with(&mut |map, selection| {
15406                selection.collapse_to(
15407                    movement::end_of_excerpt(
15408                        map,
15409                        selection.head(),
15410                        workspace::searchable::Direction::Next,
15411                    ),
15412                    SelectionGoal::None,
15413                )
15414            });
15415        })
15416    }
15417
15418    pub fn move_to_end_of_previous_excerpt(
15419        &mut self,
15420        _: &MoveToEndOfPreviousExcerpt,
15421        window: &mut Window,
15422        cx: &mut Context<Self>,
15423    ) {
15424        if matches!(self.mode, EditorMode::SingleLine) {
15425            cx.propagate();
15426            return;
15427        }
15428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15429        self.change_selections(Default::default(), window, cx, |s| {
15430            s.move_with(&mut |map, selection| {
15431                selection.collapse_to(
15432                    movement::end_of_excerpt(
15433                        map,
15434                        selection.head(),
15435                        workspace::searchable::Direction::Prev,
15436                    ),
15437                    SelectionGoal::None,
15438                )
15439            });
15440        })
15441    }
15442
15443    pub fn select_to_start_of_excerpt(
15444        &mut self,
15445        _: &SelectToStartOfExcerpt,
15446        window: &mut Window,
15447        cx: &mut Context<Self>,
15448    ) {
15449        if matches!(self.mode, EditorMode::SingleLine) {
15450            cx.propagate();
15451            return;
15452        }
15453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15454        self.change_selections(Default::default(), window, cx, |s| {
15455            s.move_heads_with(&mut |map, head, _| {
15456                (
15457                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15458                    SelectionGoal::None,
15459                )
15460            });
15461        })
15462    }
15463
15464    pub fn select_to_start_of_next_excerpt(
15465        &mut self,
15466        _: &SelectToStartOfNextExcerpt,
15467        window: &mut Window,
15468        cx: &mut Context<Self>,
15469    ) {
15470        if matches!(self.mode, EditorMode::SingleLine) {
15471            cx.propagate();
15472            return;
15473        }
15474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15475        self.change_selections(Default::default(), window, cx, |s| {
15476            s.move_heads_with(&mut |map, head, _| {
15477                (
15478                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15479                    SelectionGoal::None,
15480                )
15481            });
15482        })
15483    }
15484
15485    pub fn select_to_end_of_excerpt(
15486        &mut self,
15487        _: &SelectToEndOfExcerpt,
15488        window: &mut Window,
15489        cx: &mut Context<Self>,
15490    ) {
15491        if matches!(self.mode, EditorMode::SingleLine) {
15492            cx.propagate();
15493            return;
15494        }
15495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15496        self.change_selections(Default::default(), window, cx, |s| {
15497            s.move_heads_with(&mut |map, head, _| {
15498                (
15499                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15500                    SelectionGoal::None,
15501                )
15502            });
15503        })
15504    }
15505
15506    pub fn select_to_end_of_previous_excerpt(
15507        &mut self,
15508        _: &SelectToEndOfPreviousExcerpt,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) {
15512        if matches!(self.mode, EditorMode::SingleLine) {
15513            cx.propagate();
15514            return;
15515        }
15516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15517        self.change_selections(Default::default(), window, cx, |s| {
15518            s.move_heads_with(&mut |map, head, _| {
15519                (
15520                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15521                    SelectionGoal::None,
15522                )
15523            });
15524        })
15525    }
15526
15527    pub fn move_to_beginning(
15528        &mut self,
15529        _: &MoveToBeginning,
15530        window: &mut Window,
15531        cx: &mut Context<Self>,
15532    ) {
15533        if matches!(self.mode, EditorMode::SingleLine) {
15534            cx.propagate();
15535            return;
15536        }
15537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15538        self.change_selections(Default::default(), window, cx, |s| {
15539            s.select_ranges(vec![Anchor::Min..Anchor::Min]);
15540        });
15541    }
15542
15543    pub fn select_to_beginning(
15544        &mut self,
15545        _: &SelectToBeginning,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15550        selection.set_head(Point::zero(), SelectionGoal::None);
15551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15552        self.change_selections(Default::default(), window, cx, |s| {
15553            s.select(vec![selection]);
15554        });
15555    }
15556
15557    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15558        if matches!(self.mode, EditorMode::SingleLine) {
15559            cx.propagate();
15560            return;
15561        }
15562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15563        let cursor = self.buffer.read(cx).read(cx).len();
15564        self.change_selections(Default::default(), window, cx, |s| {
15565            s.select_ranges(vec![cursor..cursor])
15566        });
15567    }
15568
15569    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15570        self.nav_history = nav_history;
15571    }
15572
15573    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15574        self.nav_history.as_ref()
15575    }
15576
15577    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15578        self.push_to_nav_history(
15579            self.selections.newest_anchor().head(),
15580            None,
15581            false,
15582            true,
15583            cx,
15584        );
15585    }
15586
15587    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15588        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15589        let buffer = self.buffer.read(cx).read(cx);
15590        let cursor_position = cursor_anchor.to_point(&buffer);
15591        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15592        let scroll_top_row = scroll_anchor.top_row(&buffer);
15593        drop(buffer);
15594
15595        NavigationData {
15596            cursor_anchor,
15597            cursor_position,
15598            scroll_anchor,
15599            scroll_top_row,
15600        }
15601    }
15602
15603    fn navigation_entry(
15604        &self,
15605        cursor_anchor: Anchor,
15606        cx: &mut Context<Self>,
15607    ) -> Option<NavigationEntry> {
15608        let Some(history) = self.nav_history.clone() else {
15609            return None;
15610        };
15611        let data = self.navigation_data(cursor_anchor, cx);
15612        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15613    }
15614
15615    fn push_to_nav_history(
15616        &mut self,
15617        cursor_anchor: Anchor,
15618        new_position: Option<Point>,
15619        is_deactivate: bool,
15620        always: bool,
15621        cx: &mut Context<Self>,
15622    ) {
15623        let data = self.navigation_data(cursor_anchor, cx);
15624        if let Some(nav_history) = self.nav_history.as_mut() {
15625            if let Some(new_position) = new_position {
15626                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15627                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15628                    return;
15629                }
15630            }
15631
15632            let cursor_row = data.cursor_position.row;
15633            nav_history.push(Some(data), Some(cursor_row), cx);
15634            cx.emit(EditorEvent::PushedToNavHistory {
15635                anchor: cursor_anchor,
15636                is_deactivate,
15637            })
15638        }
15639    }
15640
15641    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15643        let buffer = self.buffer.read(cx).snapshot(cx);
15644        let mut selection = self
15645            .selections
15646            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15647        selection.set_head(buffer.len(), SelectionGoal::None);
15648        self.change_selections(Default::default(), window, cx, |s| {
15649            s.select(vec![selection]);
15650        });
15651    }
15652
15653    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15654        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15655        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15656            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
15657        });
15658    }
15659
15660    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15663        let mut selections = self.selections.all::<Point>(&display_map);
15664        let max_point = display_map.buffer_snapshot().max_point();
15665        for selection in &mut selections {
15666            let rows = selection.spanned_rows(true, &display_map);
15667            selection.start = Point::new(rows.start.0, 0);
15668            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15669            selection.reversed = false;
15670        }
15671        self.change_selections(Default::default(), window, cx, |s| {
15672            s.select(selections);
15673        });
15674    }
15675
15676    pub fn split_selection_into_lines(
15677        &mut self,
15678        action: &SplitSelectionIntoLines,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) {
15682        let selections = self
15683            .selections
15684            .all::<Point>(&self.display_snapshot(cx))
15685            .into_iter()
15686            .map(|selection| selection.start..selection.end)
15687            .collect::<Vec<_>>();
15688        self.unfold_ranges(&selections, true, false, cx);
15689
15690        let mut new_selection_ranges = Vec::new();
15691        {
15692            let buffer = self.buffer.read(cx).read(cx);
15693            for selection in selections {
15694                for row in selection.start.row..selection.end.row {
15695                    let line_start = Point::new(row, 0);
15696                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15697
15698                    if action.keep_selections {
15699                        // Keep the selection range for each line
15700                        let selection_start = if row == selection.start.row {
15701                            selection.start
15702                        } else {
15703                            line_start
15704                        };
15705                        new_selection_ranges.push(selection_start..line_end);
15706                    } else {
15707                        // Collapse to cursor at end of line
15708                        new_selection_ranges.push(line_end..line_end);
15709                    }
15710                }
15711
15712                let is_multiline_selection = selection.start.row != selection.end.row;
15713                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15714                // so this action feels more ergonomic when paired with other selection operations
15715                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15716                if !should_skip_last {
15717                    if action.keep_selections {
15718                        if is_multiline_selection {
15719                            let line_start = Point::new(selection.end.row, 0);
15720                            new_selection_ranges.push(line_start..selection.end);
15721                        } else {
15722                            new_selection_ranges.push(selection.start..selection.end);
15723                        }
15724                    } else {
15725                        new_selection_ranges.push(selection.end..selection.end);
15726                    }
15727                }
15728            }
15729        }
15730        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15731            s.select_ranges(new_selection_ranges);
15732        });
15733    }
15734
15735    pub fn add_selection_above(
15736        &mut self,
15737        action: &AddSelectionAbove,
15738        window: &mut Window,
15739        cx: &mut Context<Self>,
15740    ) {
15741        self.add_selection(true, action.skip_soft_wrap, window, cx);
15742    }
15743
15744    pub fn add_selection_below(
15745        &mut self,
15746        action: &AddSelectionBelow,
15747        window: &mut Window,
15748        cx: &mut Context<Self>,
15749    ) {
15750        self.add_selection(false, action.skip_soft_wrap, window, cx);
15751    }
15752
15753    fn add_selection(
15754        &mut self,
15755        above: bool,
15756        skip_soft_wrap: bool,
15757        window: &mut Window,
15758        cx: &mut Context<Self>,
15759    ) {
15760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15761
15762        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15763        let all_selections = self.selections.all::<Point>(&display_map);
15764        let text_layout_details = self.text_layout_details(window, cx);
15765
15766        let (mut columnar_selections, new_selections_to_columnarize) = {
15767            if let Some(state) = self.add_selections_state.as_ref() {
15768                let columnar_selection_ids: HashSet<_> = state
15769                    .groups
15770                    .iter()
15771                    .flat_map(|group| group.stack.iter())
15772                    .copied()
15773                    .collect();
15774
15775                all_selections
15776                    .into_iter()
15777                    .partition(|s| columnar_selection_ids.contains(&s.id))
15778            } else {
15779                (Vec::new(), all_selections)
15780            }
15781        };
15782
15783        let mut state = self
15784            .add_selections_state
15785            .take()
15786            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15787
15788        for selection in new_selections_to_columnarize {
15789            let range = selection.display_range(&display_map).sorted();
15790            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15791            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15792            let positions = start_x.min(end_x)..start_x.max(end_x);
15793            let mut stack = Vec::new();
15794            for row in range.start.row().0..=range.end.row().0 {
15795                if let Some(selection) = self.selections.build_columnar_selection(
15796                    &display_map,
15797                    DisplayRow(row),
15798                    &positions,
15799                    selection.reversed,
15800                    &text_layout_details,
15801                ) {
15802                    stack.push(selection.id);
15803                    columnar_selections.push(selection);
15804                }
15805            }
15806            if !stack.is_empty() {
15807                if above {
15808                    stack.reverse();
15809                }
15810                state.groups.push(AddSelectionsGroup { above, stack });
15811            }
15812        }
15813
15814        let mut final_selections = Vec::new();
15815        let end_row = if above {
15816            DisplayRow(0)
15817        } else {
15818            display_map.max_point().row()
15819        };
15820
15821        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15822        // positions to place new selections, so we need to keep track of the
15823        // column range of the oldest selection in each group, because
15824        // intermediate selections may have been clamped to shorter lines.
15825        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15826            let mut map = HashMap::default();
15827            for group in state.groups.iter() {
15828                if let Some(oldest_id) = group.stack.first() {
15829                    if let Some(oldest_selection) =
15830                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15831                    {
15832                        let snapshot = display_map.buffer_snapshot();
15833                        let start_col =
15834                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15835                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15836                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15837                        for id in &group.stack {
15838                            map.insert(*id, goal_columns.clone());
15839                        }
15840                    }
15841                }
15842            }
15843            map
15844        } else {
15845            HashMap::default()
15846        };
15847
15848        let mut last_added_item_per_group = HashMap::default();
15849        for group in state.groups.iter_mut() {
15850            if let Some(last_id) = group.stack.last() {
15851                last_added_item_per_group.insert(*last_id, group);
15852            }
15853        }
15854
15855        for selection in columnar_selections {
15856            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15857                if above == group.above {
15858                    let range = selection.display_range(&display_map).sorted();
15859                    debug_assert_eq!(range.start.row(), range.end.row());
15860                    let row = range.start.row();
15861                    let positions =
15862                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15863                            Pixels::from(start)..Pixels::from(end)
15864                        } else {
15865                            let start_x =
15866                                display_map.x_for_display_point(range.start, &text_layout_details);
15867                            let end_x =
15868                                display_map.x_for_display_point(range.end, &text_layout_details);
15869                            start_x.min(end_x)..start_x.max(end_x)
15870                        };
15871
15872                    let maybe_new_selection = if skip_soft_wrap {
15873                        let goal_columns = goal_columns_by_selection_id
15874                            .remove(&selection.id)
15875                            .unwrap_or_else(|| {
15876                                let snapshot = display_map.buffer_snapshot();
15877                                let start_col =
15878                                    snapshot.point_to_point_utf16(selection.start).column;
15879                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15880                                start_col.min(end_col)..start_col.max(end_col)
15881                            });
15882                        self.selections.find_next_columnar_selection_by_buffer_row(
15883                            &display_map,
15884                            row,
15885                            end_row,
15886                            above,
15887                            &goal_columns,
15888                            selection.reversed,
15889                            &text_layout_details,
15890                        )
15891                    } else {
15892                        self.selections.find_next_columnar_selection_by_display_row(
15893                            &display_map,
15894                            row,
15895                            end_row,
15896                            above,
15897                            &positions,
15898                            selection.reversed,
15899                            &text_layout_details,
15900                        )
15901                    };
15902
15903                    if let Some(new_selection) = maybe_new_selection {
15904                        group.stack.push(new_selection.id);
15905                        if above {
15906                            final_selections.push(new_selection);
15907                            final_selections.push(selection);
15908                        } else {
15909                            final_selections.push(selection);
15910                            final_selections.push(new_selection);
15911                        }
15912                    } else {
15913                        final_selections.push(selection);
15914                    }
15915                } else {
15916                    group.stack.pop();
15917                }
15918            } else {
15919                final_selections.push(selection);
15920            }
15921        }
15922
15923        self.change_selections(Default::default(), window, cx, |s| {
15924            s.select(final_selections);
15925        });
15926
15927        let final_selection_ids: HashSet<_> = self
15928            .selections
15929            .all::<Point>(&display_map)
15930            .iter()
15931            .map(|s| s.id)
15932            .collect();
15933        state.groups.retain_mut(|group| {
15934            // selections might get merged above so we remove invalid items from stacks
15935            group.stack.retain(|id| final_selection_ids.contains(id));
15936
15937            // single selection in stack can be treated as initial state
15938            group.stack.len() > 1
15939        });
15940
15941        if !state.groups.is_empty() {
15942            self.add_selections_state = Some(state);
15943        }
15944    }
15945
15946    pub fn insert_snippet_at_selections(
15947        &mut self,
15948        action: &InsertSnippet,
15949        window: &mut Window,
15950        cx: &mut Context<Self>,
15951    ) {
15952        self.try_insert_snippet_at_selections(action, window, cx)
15953            .log_err();
15954    }
15955
15956    fn try_insert_snippet_at_selections(
15957        &mut self,
15958        action: &InsertSnippet,
15959        window: &mut Window,
15960        cx: &mut Context<Self>,
15961    ) -> Result<()> {
15962        let insertion_ranges = self
15963            .selections
15964            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15965            .into_iter()
15966            .map(|selection| selection.range())
15967            .collect_vec();
15968
15969        let snippet = if let Some(snippet_body) = &action.snippet {
15970            if action.language.is_none() && action.name.is_none() {
15971                Snippet::parse(snippet_body)?
15972            } else {
15973                bail!("`snippet` is mutually exclusive with `language` and `name`")
15974            }
15975        } else if let Some(name) = &action.name {
15976            let project = self.project().context("no project")?;
15977            let snippet_store = project.read(cx).snippets().read(cx);
15978            let snippet = snippet_store
15979                .snippets_for(action.language.clone(), cx)
15980                .into_iter()
15981                .find(|snippet| snippet.name == *name)
15982                .context("snippet not found")?;
15983            Snippet::parse(&snippet.body)?
15984        } else {
15985            // todo(andrew): open modal to select snippet
15986            bail!("`name` or `snippet` is required")
15987        };
15988
15989        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15990    }
15991
15992    fn select_match_ranges(
15993        &mut self,
15994        range: Range<MultiBufferOffset>,
15995        reversed: bool,
15996        replace_newest: bool,
15997        auto_scroll: Option<Autoscroll>,
15998        window: &mut Window,
15999        cx: &mut Context<Editor>,
16000    ) {
16001        self.unfold_ranges(
16002            std::slice::from_ref(&range),
16003            false,
16004            auto_scroll.is_some(),
16005            cx,
16006        );
16007        let effects = if let Some(scroll) = auto_scroll {
16008            SelectionEffects::scroll(scroll)
16009        } else {
16010            SelectionEffects::no_scroll()
16011        };
16012        self.change_selections(effects, window, cx, |s| {
16013            if replace_newest {
16014                s.delete(s.newest_anchor().id);
16015            }
16016            if reversed {
16017                s.insert_range(range.end..range.start);
16018            } else {
16019                s.insert_range(range);
16020            }
16021        });
16022    }
16023
16024    pub fn select_next_match_internal(
16025        &mut self,
16026        display_map: &DisplaySnapshot,
16027        replace_newest: bool,
16028        autoscroll: Option<Autoscroll>,
16029        window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) -> Result<()> {
16032        let buffer = display_map.buffer_snapshot();
16033        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16034        if let Some(mut select_next_state) = self.select_next_state.take() {
16035            let query = &select_next_state.query;
16036            if !select_next_state.done {
16037                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16038                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16039                let mut next_selected_range = None;
16040
16041                let bytes_after_last_selection =
16042                    buffer.bytes_in_range(last_selection.end..buffer.len());
16043                let bytes_before_first_selection =
16044                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
16045                let query_matches = query
16046                    .stream_find_iter(bytes_after_last_selection)
16047                    .map(|result| (last_selection.end, result))
16048                    .chain(
16049                        query
16050                            .stream_find_iter(bytes_before_first_selection)
16051                            .map(|result| (MultiBufferOffset(0), result)),
16052                    );
16053
16054                for (start_offset, query_match) in query_matches {
16055                    let query_match = query_match.unwrap(); // can only fail due to I/O
16056                    let offset_range =
16057                        start_offset + query_match.start()..start_offset + query_match.end();
16058
16059                    if !select_next_state.wordwise
16060                        || (!buffer.is_inside_word(offset_range.start, None)
16061                            && !buffer.is_inside_word(offset_range.end, None))
16062                    {
16063                        let idx = selections
16064                            .partition_point(|selection| selection.end <= offset_range.start);
16065                        let overlaps = selections
16066                            .get(idx)
16067                            .map_or(false, |selection| selection.start < offset_range.end);
16068
16069                        if !overlaps {
16070                            next_selected_range = Some(offset_range);
16071                            break;
16072                        }
16073                    }
16074                }
16075
16076                if let Some(next_selected_range) = next_selected_range {
16077                    self.select_match_ranges(
16078                        next_selected_range,
16079                        last_selection.reversed,
16080                        replace_newest,
16081                        autoscroll,
16082                        window,
16083                        cx,
16084                    );
16085                } else {
16086                    select_next_state.done = true;
16087                }
16088            }
16089
16090            self.select_next_state = Some(select_next_state);
16091        } else {
16092            let mut only_carets = true;
16093            let mut same_text_selected = true;
16094            let mut selected_text = None;
16095
16096            let mut selections_iter = selections.iter().peekable();
16097            while let Some(selection) = selections_iter.next() {
16098                if selection.start != selection.end {
16099                    only_carets = false;
16100                }
16101
16102                if same_text_selected {
16103                    if selected_text.is_none() {
16104                        selected_text =
16105                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16106                    }
16107
16108                    if let Some(next_selection) = selections_iter.peek() {
16109                        if next_selection.len() == selection.len() {
16110                            let next_selected_text = buffer
16111                                .text_for_range(next_selection.range())
16112                                .collect::<String>();
16113                            if Some(next_selected_text) != selected_text {
16114                                same_text_selected = false;
16115                                selected_text = None;
16116                            }
16117                        } else {
16118                            same_text_selected = false;
16119                            selected_text = None;
16120                        }
16121                    }
16122                }
16123            }
16124
16125            if only_carets {
16126                for selection in &mut selections {
16127                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16128                    selection.start = word_range.start;
16129                    selection.end = word_range.end;
16130                    selection.goal = SelectionGoal::None;
16131                    selection.reversed = false;
16132                    self.select_match_ranges(
16133                        selection.start..selection.end,
16134                        selection.reversed,
16135                        replace_newest,
16136                        autoscroll,
16137                        window,
16138                        cx,
16139                    );
16140                }
16141
16142                if selections.len() == 1 {
16143                    let selection = selections
16144                        .last()
16145                        .expect("ensured that there's only one selection");
16146                    let query = buffer
16147                        .text_for_range(selection.start..selection.end)
16148                        .collect::<String>();
16149                    let is_empty = query.is_empty();
16150                    let select_state = SelectNextState {
16151                        query: self.build_query(&[query], cx)?,
16152                        wordwise: true,
16153                        done: is_empty,
16154                    };
16155                    self.select_next_state = Some(select_state);
16156                } else {
16157                    self.select_next_state = None;
16158                }
16159            } else if let Some(selected_text) = selected_text {
16160                self.select_next_state = Some(SelectNextState {
16161                    query: self.build_query(&[selected_text], cx)?,
16162                    wordwise: false,
16163                    done: false,
16164                });
16165                self.select_next_match_internal(
16166                    display_map,
16167                    replace_newest,
16168                    autoscroll,
16169                    window,
16170                    cx,
16171                )?;
16172            }
16173        }
16174        Ok(())
16175    }
16176
16177    pub fn select_all_matches(
16178        &mut self,
16179        _action: &SelectAllMatches,
16180        window: &mut Window,
16181        cx: &mut Context<Self>,
16182    ) -> Result<()> {
16183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16184
16185        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16186
16187        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16188        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16189        else {
16190            return Ok(());
16191        };
16192
16193        let mut new_selections = Vec::new();
16194        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
16195        let reversed = initial_selection.reversed;
16196        let buffer = display_map.buffer_snapshot();
16197        let query_matches = select_next_state
16198            .query
16199            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16200
16201        for query_match in query_matches.into_iter() {
16202            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16203            let offset_range = if reversed {
16204                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16205            } else {
16206                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16207            };
16208
16209            let is_partial_word_match = select_next_state.wordwise
16210                && (buffer.is_inside_word(offset_range.start, None)
16211                    || buffer.is_inside_word(offset_range.end, None));
16212
16213            let is_initial_selection = MultiBufferOffset(query_match.start())
16214                == initial_selection.start
16215                && MultiBufferOffset(query_match.end()) == initial_selection.end;
16216
16217            if !is_partial_word_match && !is_initial_selection {
16218                new_selections.push(offset_range);
16219            }
16220        }
16221
16222        // Ensure that the initial range is the last selection, as
16223        // `MutableSelectionsCollection::select_ranges` makes the last selection
16224        // the newest selection, which the editor then relies on as the primary
16225        // cursor for scroll targeting. Without this, the last match would then
16226        // be automatically focused when the user started editing the selected
16227        // matches.
16228        let initial_directed_range = if reversed {
16229            initial_selection.end..initial_selection.start
16230        } else {
16231            initial_selection.start..initial_selection.end
16232        };
16233        new_selections.push(initial_directed_range);
16234
16235        select_next_state.done = true;
16236        self.unfold_ranges(&new_selections, false, false, cx);
16237        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16238            selections.select_ranges(new_selections)
16239        });
16240
16241        Ok(())
16242    }
16243
16244    pub fn select_next(
16245        &mut self,
16246        action: &SelectNext,
16247        window: &mut Window,
16248        cx: &mut Context<Self>,
16249    ) -> Result<()> {
16250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16251        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16252        self.select_next_match_internal(
16253            &display_map,
16254            action.replace_newest,
16255            Some(Autoscroll::newest()),
16256            window,
16257            cx,
16258        )
16259    }
16260
16261    pub fn select_previous(
16262        &mut self,
16263        action: &SelectPrevious,
16264        window: &mut Window,
16265        cx: &mut Context<Self>,
16266    ) -> Result<()> {
16267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16269        let buffer = display_map.buffer_snapshot();
16270        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16271        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16272            let query = &select_prev_state.query;
16273            if !select_prev_state.done {
16274                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16275                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16276                let mut next_selected_range = None;
16277                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16278                let bytes_before_last_selection =
16279                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16280                let bytes_after_first_selection =
16281                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16282                let query_matches = query
16283                    .stream_find_iter(bytes_before_last_selection)
16284                    .map(|result| (last_selection.start, result))
16285                    .chain(
16286                        query
16287                            .stream_find_iter(bytes_after_first_selection)
16288                            .map(|result| (buffer.len(), result)),
16289                    );
16290                for (end_offset, query_match) in query_matches {
16291                    let query_match = query_match.unwrap(); // can only fail due to I/O
16292                    let offset_range =
16293                        end_offset - query_match.end()..end_offset - query_match.start();
16294
16295                    if !select_prev_state.wordwise
16296                        || (!buffer.is_inside_word(offset_range.start, None)
16297                            && !buffer.is_inside_word(offset_range.end, None))
16298                    {
16299                        next_selected_range = Some(offset_range);
16300                        break;
16301                    }
16302                }
16303
16304                if let Some(next_selected_range) = next_selected_range {
16305                    self.select_match_ranges(
16306                        next_selected_range,
16307                        last_selection.reversed,
16308                        action.replace_newest,
16309                        Some(Autoscroll::newest()),
16310                        window,
16311                        cx,
16312                    );
16313                } else {
16314                    select_prev_state.done = true;
16315                }
16316            }
16317
16318            self.select_prev_state = Some(select_prev_state);
16319        } else {
16320            let mut only_carets = true;
16321            let mut same_text_selected = true;
16322            let mut selected_text = None;
16323
16324            let mut selections_iter = selections.iter().peekable();
16325            while let Some(selection) = selections_iter.next() {
16326                if selection.start != selection.end {
16327                    only_carets = false;
16328                }
16329
16330                if same_text_selected {
16331                    if selected_text.is_none() {
16332                        selected_text =
16333                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16334                    }
16335
16336                    if let Some(next_selection) = selections_iter.peek() {
16337                        if next_selection.len() == selection.len() {
16338                            let next_selected_text = buffer
16339                                .text_for_range(next_selection.range())
16340                                .collect::<String>();
16341                            if Some(next_selected_text) != selected_text {
16342                                same_text_selected = false;
16343                                selected_text = None;
16344                            }
16345                        } else {
16346                            same_text_selected = false;
16347                            selected_text = None;
16348                        }
16349                    }
16350                }
16351            }
16352
16353            if only_carets {
16354                for selection in &mut selections {
16355                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16356                    selection.start = word_range.start;
16357                    selection.end = word_range.end;
16358                    selection.goal = SelectionGoal::None;
16359                    selection.reversed = false;
16360                    self.select_match_ranges(
16361                        selection.start..selection.end,
16362                        selection.reversed,
16363                        action.replace_newest,
16364                        Some(Autoscroll::newest()),
16365                        window,
16366                        cx,
16367                    );
16368                }
16369                if selections.len() == 1 {
16370                    let selection = selections
16371                        .last()
16372                        .expect("ensured that there's only one selection");
16373                    let query = buffer
16374                        .text_for_range(selection.start..selection.end)
16375                        .collect::<String>();
16376                    let is_empty = query.is_empty();
16377                    let select_state = SelectNextState {
16378                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16379                        wordwise: true,
16380                        done: is_empty,
16381                    };
16382                    self.select_prev_state = Some(select_state);
16383                } else {
16384                    self.select_prev_state = None;
16385                }
16386            } else if let Some(selected_text) = selected_text {
16387                self.select_prev_state = Some(SelectNextState {
16388                    query: self
16389                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16390                    wordwise: false,
16391                    done: false,
16392                });
16393                self.select_previous(action, window, cx)?;
16394            }
16395        }
16396        Ok(())
16397    }
16398
16399    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16400    /// setting the case sensitivity based on the global
16401    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16402    /// editor's settings.
16403    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16404    where
16405        I: IntoIterator<Item = P>,
16406        P: AsRef<[u8]>,
16407    {
16408        let case_sensitive = self
16409            .select_next_is_case_sensitive
16410            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16411
16412        let mut builder = AhoCorasickBuilder::new();
16413        builder.ascii_case_insensitive(!case_sensitive);
16414        builder.build(patterns)
16415    }
16416
16417    pub fn find_next_match(
16418        &mut self,
16419        _: &FindNextMatch,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Result<()> {
16423        let selections = self.selections.disjoint_anchors_arc();
16424        match selections.first() {
16425            Some(first) if selections.len() >= 2 => {
16426                self.change_selections(Default::default(), window, cx, |s| {
16427                    s.select_ranges([first.range()]);
16428                });
16429            }
16430            _ => self.select_next(
16431                &SelectNext {
16432                    replace_newest: true,
16433                },
16434                window,
16435                cx,
16436            )?,
16437        }
16438        Ok(())
16439    }
16440
16441    pub fn find_previous_match(
16442        &mut self,
16443        _: &FindPreviousMatch,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) -> Result<()> {
16447        let selections = self.selections.disjoint_anchors_arc();
16448        match selections.last() {
16449            Some(last) if selections.len() >= 2 => {
16450                self.change_selections(Default::default(), window, cx, |s| {
16451                    s.select_ranges([last.range()]);
16452                });
16453            }
16454            _ => self.select_previous(
16455                &SelectPrevious {
16456                    replace_newest: true,
16457                },
16458                window,
16459                cx,
16460            )?,
16461        }
16462        Ok(())
16463    }
16464
16465    pub fn toggle_comments(
16466        &mut self,
16467        action: &ToggleComments,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) {
16471        if self.read_only(cx) {
16472            return;
16473        }
16474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16475        let text_layout_details = &self.text_layout_details(window, cx);
16476        self.transact(window, cx, |this, window, cx| {
16477            let mut selections = this
16478                .selections
16479                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16480            let mut edits = Vec::new();
16481            let mut selection_edit_ranges = Vec::new();
16482            let mut last_toggled_row = None;
16483            let snapshot = this.buffer.read(cx).read(cx);
16484            let empty_str: Arc<str> = Arc::default();
16485            let mut suffixes_inserted = Vec::new();
16486            let ignore_indent = action.ignore_indent;
16487
16488            fn comment_prefix_range(
16489                snapshot: &MultiBufferSnapshot,
16490                row: MultiBufferRow,
16491                comment_prefix: &str,
16492                comment_prefix_whitespace: &str,
16493                ignore_indent: bool,
16494            ) -> Range<Point> {
16495                let indent_size = if ignore_indent {
16496                    0
16497                } else {
16498                    snapshot.indent_size_for_line(row).len
16499                };
16500
16501                let start = Point::new(row.0, indent_size);
16502
16503                let mut line_bytes = snapshot
16504                    .bytes_in_range(start..snapshot.max_point())
16505                    .flatten()
16506                    .copied();
16507
16508                // If this line currently begins with the line comment prefix, then record
16509                // the range containing the prefix.
16510                if line_bytes
16511                    .by_ref()
16512                    .take(comment_prefix.len())
16513                    .eq(comment_prefix.bytes())
16514                {
16515                    // Include any whitespace that matches the comment prefix.
16516                    let matching_whitespace_len = line_bytes
16517                        .zip(comment_prefix_whitespace.bytes())
16518                        .take_while(|(a, b)| a == b)
16519                        .count() as u32;
16520                    let end = Point::new(
16521                        start.row,
16522                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16523                    );
16524                    start..end
16525                } else {
16526                    start..start
16527                }
16528            }
16529
16530            fn comment_suffix_range(
16531                snapshot: &MultiBufferSnapshot,
16532                row: MultiBufferRow,
16533                comment_suffix: &str,
16534                comment_suffix_has_leading_space: bool,
16535            ) -> Range<Point> {
16536                let end = Point::new(row.0, snapshot.line_len(row));
16537                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16538
16539                let mut line_end_bytes = snapshot
16540                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16541                    .flatten()
16542                    .copied();
16543
16544                let leading_space_len = if suffix_start_column > 0
16545                    && line_end_bytes.next() == Some(b' ')
16546                    && comment_suffix_has_leading_space
16547                {
16548                    1
16549                } else {
16550                    0
16551                };
16552
16553                // If this line currently begins with the line comment prefix, then record
16554                // the range containing the prefix.
16555                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16556                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16557                    start..end
16558                } else {
16559                    end..end
16560                }
16561            }
16562
16563            // TODO: Handle selections that cross excerpts
16564            for selection in &mut selections {
16565                let start_column = snapshot
16566                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16567                    .len;
16568                let language = if let Some(language) =
16569                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16570                {
16571                    language
16572                } else {
16573                    continue;
16574                };
16575
16576                selection_edit_ranges.clear();
16577
16578                // If multiple selections contain a given row, avoid processing that
16579                // row more than once.
16580                let mut start_row = MultiBufferRow(selection.start.row);
16581                if last_toggled_row == Some(start_row) {
16582                    start_row = start_row.next_row();
16583                }
16584                let end_row =
16585                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16586                        MultiBufferRow(selection.end.row - 1)
16587                    } else {
16588                        MultiBufferRow(selection.end.row)
16589                    };
16590                last_toggled_row = Some(end_row);
16591
16592                if start_row > end_row {
16593                    continue;
16594                }
16595
16596                // If the language has line comments, toggle those.
16597                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16598
16599                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16600                if ignore_indent {
16601                    full_comment_prefixes = full_comment_prefixes
16602                        .into_iter()
16603                        .map(|s| Arc::from(s.trim_end()))
16604                        .collect();
16605                }
16606
16607                if !full_comment_prefixes.is_empty() {
16608                    let first_prefix = full_comment_prefixes
16609                        .first()
16610                        .expect("prefixes is non-empty");
16611                    let prefix_trimmed_lengths = full_comment_prefixes
16612                        .iter()
16613                        .map(|p| p.trim_end_matches(' ').len())
16614                        .collect::<SmallVec<[usize; 4]>>();
16615
16616                    let mut all_selection_lines_are_comments = true;
16617
16618                    for row in start_row.0..=end_row.0 {
16619                        let row = MultiBufferRow(row);
16620                        if start_row < end_row && snapshot.is_line_blank(row) {
16621                            continue;
16622                        }
16623
16624                        let prefix_range = full_comment_prefixes
16625                            .iter()
16626                            .zip(prefix_trimmed_lengths.iter().copied())
16627                            .map(|(prefix, trimmed_prefix_len)| {
16628                                comment_prefix_range(
16629                                    snapshot.deref(),
16630                                    row,
16631                                    &prefix[..trimmed_prefix_len],
16632                                    &prefix[trimmed_prefix_len..],
16633                                    ignore_indent,
16634                                )
16635                            })
16636                            .max_by_key(|range| range.end.column - range.start.column)
16637                            .expect("prefixes is non-empty");
16638
16639                        if prefix_range.is_empty() {
16640                            all_selection_lines_are_comments = false;
16641                        }
16642
16643                        selection_edit_ranges.push(prefix_range);
16644                    }
16645
16646                    if all_selection_lines_are_comments {
16647                        edits.extend(
16648                            selection_edit_ranges
16649                                .iter()
16650                                .cloned()
16651                                .map(|range| (range, empty_str.clone())),
16652                        );
16653                    } else {
16654                        let min_column = selection_edit_ranges
16655                            .iter()
16656                            .map(|range| range.start.column)
16657                            .min()
16658                            .unwrap_or(0);
16659                        edits.extend(selection_edit_ranges.iter().map(|range| {
16660                            let position = Point::new(range.start.row, min_column);
16661                            (position..position, first_prefix.clone())
16662                        }));
16663                    }
16664                } else if let Some(BlockCommentConfig {
16665                    start: full_comment_prefix,
16666                    end: comment_suffix,
16667                    ..
16668                }) = language.block_comment()
16669                {
16670                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16671                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16672                    let prefix_range = comment_prefix_range(
16673                        snapshot.deref(),
16674                        start_row,
16675                        comment_prefix,
16676                        comment_prefix_whitespace,
16677                        ignore_indent,
16678                    );
16679                    let suffix_range = comment_suffix_range(
16680                        snapshot.deref(),
16681                        end_row,
16682                        comment_suffix.trim_start_matches(' '),
16683                        comment_suffix.starts_with(' '),
16684                    );
16685
16686                    if prefix_range.is_empty() || suffix_range.is_empty() {
16687                        edits.push((
16688                            prefix_range.start..prefix_range.start,
16689                            full_comment_prefix.clone(),
16690                        ));
16691                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16692                        suffixes_inserted.push((end_row, comment_suffix.len()));
16693                    } else {
16694                        edits.push((prefix_range, empty_str.clone()));
16695                        edits.push((suffix_range, empty_str.clone()));
16696                    }
16697                } else {
16698                    continue;
16699                }
16700            }
16701
16702            drop(snapshot);
16703            this.buffer.update(cx, |buffer, cx| {
16704                buffer.edit(edits, None, cx);
16705            });
16706
16707            // Adjust selections so that they end before any comment suffixes that
16708            // were inserted.
16709            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16710            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16711            let snapshot = this.buffer.read(cx).read(cx);
16712            for selection in &mut selections {
16713                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16714                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16715                        Ordering::Less => {
16716                            suffixes_inserted.next();
16717                            continue;
16718                        }
16719                        Ordering::Greater => break,
16720                        Ordering::Equal => {
16721                            if selection.end.column == snapshot.line_len(row) {
16722                                if selection.is_empty() {
16723                                    selection.start.column -= suffix_len as u32;
16724                                }
16725                                selection.end.column -= suffix_len as u32;
16726                            }
16727                            break;
16728                        }
16729                    }
16730                }
16731            }
16732
16733            drop(snapshot);
16734            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16735
16736            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16737            let selections_on_single_row = selections.windows(2).all(|selections| {
16738                selections[0].start.row == selections[1].start.row
16739                    && selections[0].end.row == selections[1].end.row
16740                    && selections[0].start.row == selections[0].end.row
16741            });
16742            let selections_selecting = selections
16743                .iter()
16744                .any(|selection| selection.start != selection.end);
16745            let advance_downwards = action.advance_downwards
16746                && selections_on_single_row
16747                && !selections_selecting
16748                && !matches!(this.mode, EditorMode::SingleLine);
16749
16750            if advance_downwards {
16751                let snapshot = this.buffer.read(cx).snapshot(cx);
16752
16753                this.change_selections(Default::default(), window, cx, |s| {
16754                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16755                        let mut point = display_point.to_point(display_snapshot);
16756                        point.row += 1;
16757                        point = snapshot.clip_point(point, Bias::Left);
16758                        let display_point = point.to_display_point(display_snapshot);
16759                        let goal = SelectionGoal::HorizontalPosition(
16760                            display_snapshot
16761                                .x_for_display_point(display_point, text_layout_details)
16762                                .into(),
16763                        );
16764                        (display_point, goal)
16765                    })
16766                });
16767            }
16768        });
16769    }
16770
16771    pub fn select_enclosing_symbol(
16772        &mut self,
16773        _: &SelectEnclosingSymbol,
16774        window: &mut Window,
16775        cx: &mut Context<Self>,
16776    ) {
16777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16778
16779        let buffer = self.buffer.read(cx).snapshot(cx);
16780        let old_selections = self
16781            .selections
16782            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16783            .into_boxed_slice();
16784
16785        fn update_selection(
16786            selection: &Selection<MultiBufferOffset>,
16787            buffer_snap: &MultiBufferSnapshot,
16788        ) -> Option<Selection<MultiBufferOffset>> {
16789            let cursor = selection.head();
16790            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16791            for symbol in symbols.iter().rev() {
16792                let start = symbol.range.start.to_offset(buffer_snap);
16793                let end = symbol.range.end.to_offset(buffer_snap);
16794                let new_range = start..end;
16795                if start < selection.start || end > selection.end {
16796                    return Some(Selection {
16797                        id: selection.id,
16798                        start: new_range.start,
16799                        end: new_range.end,
16800                        goal: SelectionGoal::None,
16801                        reversed: selection.reversed,
16802                    });
16803                }
16804            }
16805            None
16806        }
16807
16808        let mut selected_larger_symbol = false;
16809        let new_selections = old_selections
16810            .iter()
16811            .map(|selection| match update_selection(selection, &buffer) {
16812                Some(new_selection) => {
16813                    if new_selection.range() != selection.range() {
16814                        selected_larger_symbol = true;
16815                    }
16816                    new_selection
16817                }
16818                None => selection.clone(),
16819            })
16820            .collect::<Vec<_>>();
16821
16822        if selected_larger_symbol {
16823            self.change_selections(Default::default(), window, cx, |s| {
16824                s.select(new_selections);
16825            });
16826        }
16827    }
16828
16829    pub fn select_larger_syntax_node(
16830        &mut self,
16831        _: &SelectLargerSyntaxNode,
16832        window: &mut Window,
16833        cx: &mut Context<Self>,
16834    ) {
16835        let Some(visible_row_count) = self.visible_row_count() else {
16836            return;
16837        };
16838        let old_selections: Box<[_]> = self
16839            .selections
16840            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16841            .into();
16842        if old_selections.is_empty() {
16843            return;
16844        }
16845
16846        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16847
16848        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16849        let buffer = self.buffer.read(cx).snapshot(cx);
16850
16851        let mut selected_larger_node = false;
16852        let mut new_selections = old_selections
16853            .iter()
16854            .map(|selection| {
16855                let old_range = selection.start..selection.end;
16856
16857                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16858                    // manually select word at selection
16859                    if ["string_content", "inline"].contains(&node.kind()) {
16860                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16861                        // ignore if word is already selected
16862                        if !word_range.is_empty() && old_range != word_range {
16863                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16864                            // only select word if start and end point belongs to same word
16865                            if word_range == last_word_range {
16866                                selected_larger_node = true;
16867                                return Selection {
16868                                    id: selection.id,
16869                                    start: word_range.start,
16870                                    end: word_range.end,
16871                                    goal: SelectionGoal::None,
16872                                    reversed: selection.reversed,
16873                                };
16874                            }
16875                        }
16876                    }
16877                }
16878
16879                let mut new_range = old_range.clone();
16880                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16881                    new_range = range;
16882                    if !node.is_named() {
16883                        continue;
16884                    }
16885                    if !display_map.intersects_fold(new_range.start)
16886                        && !display_map.intersects_fold(new_range.end)
16887                    {
16888                        break;
16889                    }
16890                }
16891
16892                selected_larger_node |= new_range != old_range;
16893                Selection {
16894                    id: selection.id,
16895                    start: new_range.start,
16896                    end: new_range.end,
16897                    goal: SelectionGoal::None,
16898                    reversed: selection.reversed,
16899                }
16900            })
16901            .collect::<Vec<_>>();
16902
16903        if !selected_larger_node {
16904            return; // don't put this call in the history
16905        }
16906
16907        // scroll based on transformation done to the last selection created by the user
16908        let (last_old, last_new) = old_selections
16909            .last()
16910            .zip(new_selections.last().cloned())
16911            .expect("old_selections isn't empty");
16912
16913        let is_selection_reversed = if new_selections.len() == 1 {
16914            let should_be_reversed = last_old.start != last_new.start;
16915            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
16916            should_be_reversed
16917        } else {
16918            last_new.reversed
16919        };
16920
16921        if selected_larger_node {
16922            self.select_syntax_node_history.disable_clearing = true;
16923            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16924                s.select(new_selections.clone());
16925            });
16926            self.select_syntax_node_history.disable_clearing = false;
16927        }
16928
16929        let start_row = last_new.start.to_display_point(&display_map).row().0;
16930        let end_row = last_new.end.to_display_point(&display_map).row().0;
16931        let selection_height = end_row - start_row + 1;
16932        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16933
16934        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16935        let scroll_behavior = if fits_on_the_screen {
16936            self.request_autoscroll(Autoscroll::fit(), cx);
16937            SelectSyntaxNodeScrollBehavior::FitSelection
16938        } else if is_selection_reversed {
16939            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16940            SelectSyntaxNodeScrollBehavior::CursorTop
16941        } else {
16942            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16943            SelectSyntaxNodeScrollBehavior::CursorBottom
16944        };
16945
16946        let old_selections: Box<[Selection<Anchor>]> = old_selections
16947            .iter()
16948            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16949            .collect();
16950        self.select_syntax_node_history.push((
16951            old_selections,
16952            scroll_behavior,
16953            is_selection_reversed,
16954        ));
16955    }
16956
16957    pub fn select_smaller_syntax_node(
16958        &mut self,
16959        _: &SelectSmallerSyntaxNode,
16960        window: &mut Window,
16961        cx: &mut Context<Self>,
16962    ) {
16963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16964
16965        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16966            self.select_syntax_node_history.pop()
16967        {
16968            if let Some(selection) = selections.last_mut() {
16969                selection.reversed = is_selection_reversed;
16970            }
16971
16972            let snapshot = self.buffer.read(cx).snapshot(cx);
16973            let selections: Vec<Selection<MultiBufferOffset>> = selections
16974                .iter()
16975                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16976                .collect();
16977
16978            self.select_syntax_node_history.disable_clearing = true;
16979            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16980                s.select(selections);
16981            });
16982            self.select_syntax_node_history.disable_clearing = false;
16983
16984            match scroll_behavior {
16985                SelectSyntaxNodeScrollBehavior::CursorTop => {
16986                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16987                }
16988                SelectSyntaxNodeScrollBehavior::FitSelection => {
16989                    self.request_autoscroll(Autoscroll::fit(), cx);
16990                }
16991                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16992                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16993                }
16994            }
16995        }
16996    }
16997
16998    pub fn unwrap_syntax_node(
16999        &mut self,
17000        _: &UnwrapSyntaxNode,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17005
17006        let buffer = self.buffer.read(cx).snapshot(cx);
17007        let selections = self
17008            .selections
17009            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17010            .into_iter()
17011            // subtracting the offset requires sorting
17012            .sorted_by_key(|i| i.start);
17013
17014        let full_edits = selections
17015            .into_iter()
17016            .filter_map(|selection| {
17017                let child = if selection.is_empty()
17018                    && let Some((_, ancestor_range)) =
17019                        buffer.syntax_ancestor(selection.start..selection.end)
17020                {
17021                    ancestor_range
17022                } else {
17023                    selection.range()
17024                };
17025
17026                let mut parent = child.clone();
17027                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
17028                    parent = ancestor_range;
17029                    if parent.start < child.start || parent.end > child.end {
17030                        break;
17031                    }
17032                }
17033
17034                if parent == child {
17035                    return None;
17036                }
17037                let text = buffer.text_for_range(child).collect::<String>();
17038                Some((selection.id, parent, text))
17039            })
17040            .collect::<Vec<_>>();
17041        if full_edits.is_empty() {
17042            return;
17043        }
17044
17045        self.transact(window, cx, |this, window, cx| {
17046            this.buffer.update(cx, |buffer, cx| {
17047                buffer.edit(
17048                    full_edits
17049                        .iter()
17050                        .map(|(_, p, t)| (p.clone(), t.clone()))
17051                        .collect::<Vec<_>>(),
17052                    None,
17053                    cx,
17054                );
17055            });
17056            this.change_selections(Default::default(), window, cx, |s| {
17057                let mut offset = 0;
17058                let mut selections = vec![];
17059                for (id, parent, text) in full_edits {
17060                    let start = parent.start - offset;
17061                    offset += (parent.end - parent.start) - text.len();
17062                    selections.push(Selection {
17063                        id,
17064                        start,
17065                        end: start + text.len(),
17066                        reversed: false,
17067                        goal: Default::default(),
17068                    });
17069                }
17070                s.select(selections);
17071            });
17072        });
17073    }
17074
17075    pub fn select_next_syntax_node(
17076        &mut self,
17077        _: &SelectNextSyntaxNode,
17078        window: &mut Window,
17079        cx: &mut Context<Self>,
17080    ) {
17081        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
17082        if old_selections.is_empty() {
17083            return;
17084        }
17085
17086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17087
17088        let buffer = self.buffer.read(cx).snapshot(cx);
17089        let mut selected_sibling = false;
17090
17091        let new_selections = old_selections
17092            .iter()
17093            .map(|selection| {
17094                let old_range =
17095                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
17096                if let Some(results) = buffer.map_excerpt_ranges(
17097                    old_range,
17098                    |buf, _excerpt_range, input_buffer_range| {
17099                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
17100                            return Vec::new();
17101                        };
17102                        vec![(
17103                            BufferOffset(node.byte_range().start)
17104                                ..BufferOffset(node.byte_range().end),
17105                            (),
17106                        )]
17107                    },
17108                ) && let [(new_range, _)] = results.as_slice()
17109                {
17110                    selected_sibling = true;
17111                    let new_range =
17112                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
17113                    Selection {
17114                        id: selection.id,
17115                        start: new_range.start,
17116                        end: new_range.end,
17117                        goal: SelectionGoal::None,
17118                        reversed: selection.reversed,
17119                    }
17120                } else {
17121                    selection.clone()
17122                }
17123            })
17124            .collect::<Vec<_>>();
17125
17126        if selected_sibling {
17127            self.change_selections(
17128                SelectionEffects::scroll(Autoscroll::fit()),
17129                window,
17130                cx,
17131                |s| {
17132                    s.select(new_selections);
17133                },
17134            );
17135        }
17136    }
17137
17138    pub fn select_prev_syntax_node(
17139        &mut self,
17140        _: &SelectPreviousSyntaxNode,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) {
17144        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
17145
17146        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17147
17148        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
17149        let mut selected_sibling = false;
17150
17151        let new_selections = old_selections
17152            .iter()
17153            .map(|selection| {
17154                let old_range = selection.start.to_offset(&multibuffer_snapshot)
17155                    ..selection.end.to_offset(&multibuffer_snapshot);
17156                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
17157                    old_range,
17158                    |buf, _excerpt_range, input_buffer_range| {
17159                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
17160                            return Vec::new();
17161                        };
17162                        vec![(
17163                            BufferOffset(node.byte_range().start)
17164                                ..BufferOffset(node.byte_range().end),
17165                            (),
17166                        )]
17167                    },
17168                ) && let [(new_range, _)] = results.as_slice()
17169                {
17170                    selected_sibling = true;
17171                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
17172                        ..multibuffer_snapshot.anchor_before(new_range.end);
17173                    Selection {
17174                        id: selection.id,
17175                        start: new_range.start,
17176                        end: new_range.end,
17177                        goal: SelectionGoal::None,
17178                        reversed: selection.reversed,
17179                    }
17180                } else {
17181                    selection.clone()
17182                }
17183            })
17184            .collect::<Vec<_>>();
17185
17186        if selected_sibling {
17187            self.change_selections(
17188                SelectionEffects::scroll(Autoscroll::fit()),
17189                window,
17190                cx,
17191                |s| {
17192                    s.select(new_selections);
17193                },
17194            );
17195        }
17196    }
17197
17198    pub fn move_to_start_of_larger_syntax_node(
17199        &mut self,
17200        _: &MoveToStartOfLargerSyntaxNode,
17201        window: &mut Window,
17202        cx: &mut Context<Self>,
17203    ) {
17204        self.move_cursors_to_syntax_nodes(window, cx, false);
17205    }
17206
17207    pub fn move_to_end_of_larger_syntax_node(
17208        &mut self,
17209        _: &MoveToEndOfLargerSyntaxNode,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) {
17213        self.move_cursors_to_syntax_nodes(window, cx, true);
17214    }
17215
17216    fn find_syntax_node_boundary(
17217        &self,
17218        selection_pos: MultiBufferOffset,
17219        move_to_end: bool,
17220        display_map: &DisplaySnapshot,
17221        buffer: &MultiBufferSnapshot,
17222    ) -> MultiBufferOffset {
17223        let old_range = selection_pos..selection_pos;
17224        let mut new_pos = selection_pos;
17225        let mut search_range = old_range;
17226        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17227            search_range = range.clone();
17228            if !node.is_named()
17229                || display_map.intersects_fold(range.start)
17230                || display_map.intersects_fold(range.end)
17231                // If cursor is already at the end of the syntax node, continue searching
17232                || (move_to_end && range.end == selection_pos)
17233                // If cursor is already at the start of the syntax node, continue searching
17234                || (!move_to_end && range.start == selection_pos)
17235            {
17236                continue;
17237            }
17238
17239            // If we found a string_content node, find the largest parent that is still string_content
17240            // Enables us to skip to the end of strings without taking multiple steps inside the string
17241            let (_, final_range) = if node.kind() == "string_content" {
17242                let mut current_node = node;
17243                let mut current_range = range;
17244                while let Some((parent, parent_range)) =
17245                    buffer.syntax_ancestor(current_range.clone())
17246                {
17247                    if parent.kind() == "string_content" {
17248                        current_node = parent;
17249                        current_range = parent_range;
17250                    } else {
17251                        break;
17252                    }
17253                }
17254
17255                (current_node, current_range)
17256            } else {
17257                (node, range)
17258            };
17259
17260            new_pos = if move_to_end {
17261                final_range.end
17262            } else {
17263                final_range.start
17264            };
17265
17266            break;
17267        }
17268
17269        new_pos
17270    }
17271
17272    fn move_cursors_to_syntax_nodes(
17273        &mut self,
17274        window: &mut Window,
17275        cx: &mut Context<Self>,
17276        move_to_end: bool,
17277    ) -> bool {
17278        let old_selections: Box<[_]> = self
17279            .selections
17280            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17281            .into();
17282        if old_selections.is_empty() {
17283            return false;
17284        }
17285
17286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17287
17288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17289        let buffer = self.buffer.read(cx).snapshot(cx);
17290
17291        let mut any_cursor_moved = false;
17292        let new_selections = old_selections
17293            .iter()
17294            .map(|selection| {
17295                if !selection.is_empty() {
17296                    return selection.clone();
17297                }
17298
17299                let selection_pos = selection.head();
17300                let new_pos = self.find_syntax_node_boundary(
17301                    selection_pos,
17302                    move_to_end,
17303                    &display_map,
17304                    &buffer,
17305                );
17306
17307                any_cursor_moved |= new_pos != selection_pos;
17308
17309                Selection {
17310                    id: selection.id,
17311                    start: new_pos,
17312                    end: new_pos,
17313                    goal: SelectionGoal::None,
17314                    reversed: false,
17315                }
17316            })
17317            .collect::<Vec<_>>();
17318
17319        self.change_selections(Default::default(), window, cx, |s| {
17320            s.select(new_selections);
17321        });
17322        self.request_autoscroll(Autoscroll::newest(), cx);
17323
17324        any_cursor_moved
17325    }
17326
17327    pub fn select_to_start_of_larger_syntax_node(
17328        &mut self,
17329        _: &SelectToStartOfLargerSyntaxNode,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) {
17333        self.select_to_syntax_nodes(window, cx, false);
17334    }
17335
17336    pub fn select_to_end_of_larger_syntax_node(
17337        &mut self,
17338        _: &SelectToEndOfLargerSyntaxNode,
17339        window: &mut Window,
17340        cx: &mut Context<Self>,
17341    ) {
17342        self.select_to_syntax_nodes(window, cx, true);
17343    }
17344
17345    fn select_to_syntax_nodes(
17346        &mut self,
17347        window: &mut Window,
17348        cx: &mut Context<Self>,
17349        move_to_end: bool,
17350    ) {
17351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17352
17353        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17354        let buffer = self.buffer.read(cx).snapshot(cx);
17355        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17356
17357        let new_selections = old_selections
17358            .iter()
17359            .map(|selection| {
17360                let new_pos = self.find_syntax_node_boundary(
17361                    selection.head(),
17362                    move_to_end,
17363                    &display_map,
17364                    &buffer,
17365                );
17366
17367                let mut new_selection = selection.clone();
17368                new_selection.set_head(new_pos, SelectionGoal::None);
17369                new_selection
17370            })
17371            .collect::<Vec<_>>();
17372
17373        self.change_selections(Default::default(), window, cx, |s| {
17374            s.select(new_selections);
17375        });
17376    }
17377
17378    pub fn move_to_enclosing_bracket(
17379        &mut self,
17380        _: &MoveToEnclosingBracket,
17381        window: &mut Window,
17382        cx: &mut Context<Self>,
17383    ) {
17384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17385        self.change_selections(Default::default(), window, cx, |s| {
17386            s.move_offsets_with(&mut |snapshot, selection| {
17387                let Some(enclosing_bracket_ranges) =
17388                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17389                else {
17390                    return;
17391                };
17392
17393                let mut best_length = usize::MAX;
17394                let mut best_inside = false;
17395                let mut best_in_bracket_range = false;
17396                let mut best_destination = None;
17397                for (open, close) in enclosing_bracket_ranges {
17398                    let close = close.to_inclusive();
17399                    let length = *close.end() - open.start;
17400                    let inside = selection.start >= open.end && selection.end <= *close.start();
17401                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17402                        || close.contains(&selection.head());
17403
17404                    // If best is next to a bracket and current isn't, skip
17405                    if !in_bracket_range && best_in_bracket_range {
17406                        continue;
17407                    }
17408
17409                    // Prefer smaller lengths unless best is inside and current isn't
17410                    if length > best_length && (best_inside || !inside) {
17411                        continue;
17412                    }
17413
17414                    best_length = length;
17415                    best_inside = inside;
17416                    best_in_bracket_range = in_bracket_range;
17417                    best_destination = Some(
17418                        if close.contains(&selection.start) && close.contains(&selection.end) {
17419                            if inside { open.end } else { open.start }
17420                        } else if inside {
17421                            *close.start()
17422                        } else {
17423                            *close.end()
17424                        },
17425                    );
17426                }
17427
17428                if let Some(destination) = best_destination {
17429                    selection.collapse_to(destination, SelectionGoal::None);
17430                }
17431            })
17432        });
17433    }
17434
17435    pub fn undo_selection(
17436        &mut self,
17437        _: &UndoSelection,
17438        window: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17442        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17443            self.selection_history.mode = SelectionHistoryMode::Undoing;
17444            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17445                this.end_selection(window, cx);
17446                this.change_selections(
17447                    SelectionEffects::scroll(Autoscroll::newest()),
17448                    window,
17449                    cx,
17450                    |s| s.select_anchors(entry.selections.to_vec()),
17451                );
17452            });
17453            self.selection_history.mode = SelectionHistoryMode::Normal;
17454
17455            self.select_next_state = entry.select_next_state;
17456            self.select_prev_state = entry.select_prev_state;
17457            self.add_selections_state = entry.add_selections_state;
17458        }
17459    }
17460
17461    pub fn redo_selection(
17462        &mut self,
17463        _: &RedoSelection,
17464        window: &mut Window,
17465        cx: &mut Context<Self>,
17466    ) {
17467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17468        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17469            self.selection_history.mode = SelectionHistoryMode::Redoing;
17470            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17471                this.end_selection(window, cx);
17472                this.change_selections(
17473                    SelectionEffects::scroll(Autoscroll::newest()),
17474                    window,
17475                    cx,
17476                    |s| s.select_anchors(entry.selections.to_vec()),
17477                );
17478            });
17479            self.selection_history.mode = SelectionHistoryMode::Normal;
17480
17481            self.select_next_state = entry.select_next_state;
17482            self.select_prev_state = entry.select_prev_state;
17483            self.add_selections_state = entry.add_selections_state;
17484        }
17485    }
17486
17487    pub fn expand_excerpts(
17488        &mut self,
17489        action: &ExpandExcerpts,
17490        _: &mut Window,
17491        cx: &mut Context<Self>,
17492    ) {
17493        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17494    }
17495
17496    pub fn expand_excerpts_down(
17497        &mut self,
17498        action: &ExpandExcerptsDown,
17499        _: &mut Window,
17500        cx: &mut Context<Self>,
17501    ) {
17502        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17503    }
17504
17505    pub fn expand_excerpts_up(
17506        &mut self,
17507        action: &ExpandExcerptsUp,
17508        _: &mut Window,
17509        cx: &mut Context<Self>,
17510    ) {
17511        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17512    }
17513
17514    pub fn expand_excerpts_for_direction(
17515        &mut self,
17516        lines: u32,
17517        direction: ExpandExcerptDirection,
17518        cx: &mut Context<Self>,
17519    ) {
17520        let selections = self.selections.disjoint_anchors_arc();
17521
17522        let lines = if lines == 0 {
17523            EditorSettings::get_global(cx).expand_excerpt_lines
17524        } else {
17525            lines
17526        };
17527
17528        let snapshot = self.buffer.read(cx).snapshot(cx);
17529        let excerpt_anchors = selections
17530            .iter()
17531            .flat_map(|selection| {
17532                snapshot
17533                    .range_to_buffer_ranges(selection.range())
17534                    .into_iter()
17535                    .filter_map(|(buffer_snapshot, range, _)| {
17536                        snapshot.anchor_in_excerpt(buffer_snapshot.anchor_after(range.start))
17537                    })
17538            })
17539            .collect::<Vec<_>>();
17540
17541        if self.delegate_expand_excerpts {
17542            cx.emit(EditorEvent::ExpandExcerptsRequested {
17543                excerpt_anchors,
17544                lines,
17545                direction,
17546            });
17547            return;
17548        }
17549
17550        self.buffer.update(cx, |buffer, cx| {
17551            buffer.expand_excerpts(excerpt_anchors, lines, direction, cx)
17552        })
17553    }
17554
17555    pub(crate) fn expand_excerpt(
17556        &mut self,
17557        excerpt_anchor: Anchor,
17558        direction: ExpandExcerptDirection,
17559        window: &mut Window,
17560        cx: &mut Context<Self>,
17561    ) {
17562        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17563
17564        if self.delegate_expand_excerpts {
17565            cx.emit(EditorEvent::ExpandExcerptsRequested {
17566                excerpt_anchors: vec![excerpt_anchor],
17567                lines: lines_to_expand,
17568                direction,
17569            });
17570            return;
17571        }
17572
17573        let current_scroll_position = self.scroll_position(cx);
17574        let mut scroll = None;
17575
17576        if direction == ExpandExcerptDirection::Down {
17577            let multi_buffer = self.buffer.read(cx);
17578            let snapshot = multi_buffer.snapshot(cx);
17579            if let Some((buffer_snapshot, excerpt_range)) =
17580                snapshot.excerpt_containing(excerpt_anchor..excerpt_anchor)
17581            {
17582                let excerpt_end_row =
17583                    Point::from_anchor(&excerpt_range.context.end, &buffer_snapshot).row;
17584                let last_row = buffer_snapshot.max_point().row;
17585                let lines_below = last_row.saturating_sub(excerpt_end_row);
17586                if lines_below >= lines_to_expand {
17587                    scroll = Some(
17588                        current_scroll_position
17589                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17590                    );
17591                }
17592            }
17593        }
17594        if direction == ExpandExcerptDirection::Up
17595            && self
17596                .buffer
17597                .read(cx)
17598                .snapshot(cx)
17599                .excerpt_before(excerpt_anchor)
17600                .is_none()
17601        {
17602            scroll = Some(current_scroll_position);
17603        }
17604
17605        self.buffer.update(cx, |buffer, cx| {
17606            buffer.expand_excerpts([excerpt_anchor], lines_to_expand, direction, cx)
17607        });
17608
17609        if let Some(new_scroll_position) = scroll {
17610            self.set_scroll_position(new_scroll_position, window, cx);
17611        }
17612    }
17613
17614    pub fn go_to_singleton_buffer_point(
17615        &mut self,
17616        point: Point,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        self.go_to_singleton_buffer_range(point..point, window, cx);
17621    }
17622
17623    pub fn go_to_singleton_buffer_range(
17624        &mut self,
17625        range: Range<Point>,
17626        window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        let multibuffer = self.buffer().read(cx);
17630        if !multibuffer.is_singleton() {
17631            return;
17632        };
17633        let anchor_range = range.to_anchors(&multibuffer.snapshot(cx));
17634        self.change_selections(
17635            SelectionEffects::default().nav_history(true),
17636            window,
17637            cx,
17638            |s| s.select_anchor_ranges([anchor_range]),
17639        );
17640    }
17641
17642    pub fn go_to_diagnostic(
17643        &mut self,
17644        action: &GoToDiagnostic,
17645        window: &mut Window,
17646        cx: &mut Context<Self>,
17647    ) {
17648        if !self.diagnostics_enabled() {
17649            return;
17650        }
17651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17652        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17653    }
17654
17655    pub fn go_to_prev_diagnostic(
17656        &mut self,
17657        action: &GoToPreviousDiagnostic,
17658        window: &mut Window,
17659        cx: &mut Context<Self>,
17660    ) {
17661        if !self.diagnostics_enabled() {
17662            return;
17663        }
17664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17665        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17666    }
17667
17668    pub fn go_to_diagnostic_impl(
17669        &mut self,
17670        direction: Direction,
17671        severity: GoToDiagnosticSeverityFilter,
17672        window: &mut Window,
17673        cx: &mut Context<Self>,
17674    ) {
17675        let buffer = self.buffer.read(cx).snapshot(cx);
17676        let selection = self
17677            .selections
17678            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17679
17680        let mut active_group_id = None;
17681        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17682            && active_group.active_range.start.to_offset(&buffer) == selection.start
17683        {
17684            active_group_id = Some(active_group.group_id);
17685        }
17686
17687        fn filtered<'a>(
17688            severity: GoToDiagnosticSeverityFilter,
17689            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17690        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17691            diagnostics
17692                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17693                .filter(|entry| entry.range.start != entry.range.end)
17694                .filter(|entry| !entry.diagnostic.is_unnecessary)
17695        }
17696
17697        let before = filtered(
17698            severity,
17699            buffer
17700                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17701                .filter(|entry| entry.range.start <= selection.start),
17702        );
17703        let after = filtered(
17704            severity,
17705            buffer
17706                .diagnostics_in_range(selection.start..buffer.len())
17707                .filter(|entry| entry.range.start >= selection.start),
17708        );
17709
17710        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17711        if direction == Direction::Prev {
17712            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17713            {
17714                for diagnostic in prev_diagnostics.into_iter().rev() {
17715                    if diagnostic.range.start != selection.start
17716                        || active_group_id
17717                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17718                    {
17719                        found = Some(diagnostic);
17720                        break 'outer;
17721                    }
17722                }
17723            }
17724        } else {
17725            for diagnostic in after.chain(before) {
17726                if diagnostic.range.start != selection.start
17727                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17728                {
17729                    found = Some(diagnostic);
17730                    break;
17731                }
17732            }
17733        }
17734        let Some(next_diagnostic) = found else {
17735            return;
17736        };
17737
17738        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17739        let Some((buffer_anchor, _)) = buffer.anchor_to_buffer_anchor(next_diagnostic_start) else {
17740            return;
17741        };
17742        let buffer_id = buffer_anchor.buffer_id;
17743        let snapshot = self.snapshot(window, cx);
17744        if snapshot.intersects_fold(next_diagnostic.range.start) {
17745            self.unfold_ranges(
17746                std::slice::from_ref(&next_diagnostic.range),
17747                true,
17748                false,
17749                cx,
17750            );
17751        }
17752        self.change_selections(Default::default(), window, cx, |s| {
17753            s.select_ranges(vec![
17754                next_diagnostic.range.start..next_diagnostic.range.start,
17755            ])
17756        });
17757        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17758        self.refresh_edit_prediction(false, true, window, cx);
17759    }
17760
17761    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17763        let snapshot = self.snapshot(window, cx);
17764        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17765        self.go_to_hunk_before_or_after_position(
17766            &snapshot,
17767            selection.head(),
17768            Direction::Next,
17769            true,
17770            window,
17771            cx,
17772        );
17773    }
17774
17775    pub fn go_to_hunk_before_or_after_position(
17776        &mut self,
17777        snapshot: &EditorSnapshot,
17778        position: Point,
17779        direction: Direction,
17780        wrap_around: bool,
17781        window: &mut Window,
17782        cx: &mut Context<Editor>,
17783    ) {
17784        let row = if direction == Direction::Next {
17785            self.hunk_after_position(snapshot, position, wrap_around)
17786                .map(|hunk| hunk.row_range.start)
17787        } else {
17788            self.hunk_before_position(snapshot, position, wrap_around)
17789        };
17790
17791        if let Some(row) = row {
17792            let destination = Point::new(row.0, 0);
17793            let autoscroll = Autoscroll::center();
17794
17795            self.unfold_ranges(&[destination..destination], false, false, cx);
17796            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17797                s.select_ranges([destination..destination]);
17798            });
17799        }
17800    }
17801
17802    fn hunk_after_position(
17803        &mut self,
17804        snapshot: &EditorSnapshot,
17805        position: Point,
17806        wrap_around: bool,
17807    ) -> Option<MultiBufferDiffHunk> {
17808        let result = snapshot
17809            .buffer_snapshot()
17810            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17811            .find(|hunk| hunk.row_range.start.0 > position.row);
17812
17813        if wrap_around {
17814            result.or_else(|| {
17815                snapshot
17816                    .buffer_snapshot()
17817                    .diff_hunks_in_range(Point::zero()..position)
17818                    .find(|hunk| hunk.row_range.end.0 < position.row)
17819            })
17820        } else {
17821            result
17822        }
17823    }
17824
17825    fn go_to_prev_hunk(
17826        &mut self,
17827        _: &GoToPreviousHunk,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) {
17831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17832        let snapshot = self.snapshot(window, cx);
17833        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17834        self.go_to_hunk_before_or_after_position(
17835            &snapshot,
17836            selection.head(),
17837            Direction::Prev,
17838            true,
17839            window,
17840            cx,
17841        );
17842    }
17843
17844    fn hunk_before_position(
17845        &mut self,
17846        snapshot: &EditorSnapshot,
17847        position: Point,
17848        wrap_around: bool,
17849    ) -> Option<MultiBufferRow> {
17850        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17851
17852        if wrap_around {
17853            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17854        } else {
17855            result
17856        }
17857    }
17858
17859    fn go_to_next_change(
17860        &mut self,
17861        _: &GoToNextChange,
17862        window: &mut Window,
17863        cx: &mut Context<Self>,
17864    ) {
17865        if let Some(selections) = self
17866            .change_list
17867            .next_change(1, Direction::Next)
17868            .map(|s| s.to_vec())
17869        {
17870            self.change_selections(Default::default(), window, cx, |s| {
17871                let map = s.display_snapshot();
17872                s.select_display_ranges(selections.iter().map(|a| {
17873                    let point = a.to_display_point(&map);
17874                    point..point
17875                }))
17876            })
17877        }
17878    }
17879
17880    fn go_to_previous_change(
17881        &mut self,
17882        _: &GoToPreviousChange,
17883        window: &mut Window,
17884        cx: &mut Context<Self>,
17885    ) {
17886        if let Some(selections) = self
17887            .change_list
17888            .next_change(1, Direction::Prev)
17889            .map(|s| s.to_vec())
17890        {
17891            self.change_selections(Default::default(), window, cx, |s| {
17892                let map = s.display_snapshot();
17893                s.select_display_ranges(selections.iter().map(|a| {
17894                    let point = a.to_display_point(&map);
17895                    point..point
17896                }))
17897            })
17898        }
17899    }
17900
17901    pub fn go_to_next_document_highlight(
17902        &mut self,
17903        _: &GoToNextDocumentHighlight,
17904        window: &mut Window,
17905        cx: &mut Context<Self>,
17906    ) {
17907        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17908    }
17909
17910    pub fn go_to_prev_document_highlight(
17911        &mut self,
17912        _: &GoToPreviousDocumentHighlight,
17913        window: &mut Window,
17914        cx: &mut Context<Self>,
17915    ) {
17916        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17917    }
17918
17919    pub fn go_to_document_highlight_before_or_after_position(
17920        &mut self,
17921        direction: Direction,
17922        window: &mut Window,
17923        cx: &mut Context<Editor>,
17924    ) {
17925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17926        let snapshot = self.snapshot(window, cx);
17927        let buffer = &snapshot.buffer_snapshot();
17928        let position = self
17929            .selections
17930            .newest::<Point>(&snapshot.display_snapshot)
17931            .head();
17932        let anchor_position = buffer.anchor_after(position);
17933
17934        // Get all document highlights (both read and write)
17935        let mut all_highlights = Vec::new();
17936
17937        if let Some((_, read_highlights)) = self
17938            .background_highlights
17939            .get(&HighlightKey::DocumentHighlightRead)
17940        {
17941            all_highlights.extend(read_highlights.iter());
17942        }
17943
17944        if let Some((_, write_highlights)) = self
17945            .background_highlights
17946            .get(&HighlightKey::DocumentHighlightWrite)
17947        {
17948            all_highlights.extend(write_highlights.iter());
17949        }
17950
17951        if all_highlights.is_empty() {
17952            return;
17953        }
17954
17955        // Sort highlights by position
17956        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17957
17958        let target_highlight = match direction {
17959            Direction::Next => {
17960                // Find the first highlight after the current position
17961                all_highlights
17962                    .iter()
17963                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17964            }
17965            Direction::Prev => {
17966                // Find the last highlight before the current position
17967                all_highlights
17968                    .iter()
17969                    .rev()
17970                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17971            }
17972        };
17973
17974        if let Some(highlight) = target_highlight {
17975            let destination = highlight.start.to_point(buffer);
17976            let autoscroll = Autoscroll::center();
17977
17978            self.unfold_ranges(&[destination..destination], false, false, cx);
17979            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17980                s.select_ranges([destination..destination]);
17981            });
17982        }
17983    }
17984
17985    fn go_to_line<T: 'static>(
17986        &mut self,
17987        position: Anchor,
17988        highlight_color: Option<Hsla>,
17989        window: &mut Window,
17990        cx: &mut Context<Self>,
17991    ) {
17992        let snapshot = self.snapshot(window, cx).display_snapshot;
17993        let position = position.to_point(&snapshot.buffer_snapshot());
17994        let start = snapshot
17995            .buffer_snapshot()
17996            .clip_point(Point::new(position.row, 0), Bias::Left);
17997        let end = start + Point::new(1, 0);
17998        let start = snapshot.buffer_snapshot().anchor_before(start);
17999        let end = snapshot.buffer_snapshot().anchor_before(end);
18000
18001        self.highlight_rows::<T>(
18002            start..end,
18003            highlight_color
18004                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
18005            Default::default(),
18006            cx,
18007        );
18008
18009        if self.buffer.read(cx).is_singleton() {
18010            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
18011        }
18012    }
18013
18014    pub fn go_to_definition(
18015        &mut self,
18016        _: &GoToDefinition,
18017        window: &mut Window,
18018        cx: &mut Context<Self>,
18019    ) -> Task<Result<Navigated>> {
18020        let definition =
18021            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
18022        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
18023        cx.spawn_in(window, async move |editor, cx| {
18024            if definition.await? == Navigated::Yes {
18025                return Ok(Navigated::Yes);
18026            }
18027            match fallback_strategy {
18028                GoToDefinitionFallback::None => Ok(Navigated::No),
18029                GoToDefinitionFallback::FindAllReferences => {
18030                    match editor.update_in(cx, |editor, window, cx| {
18031                        editor.find_all_references(&FindAllReferences::default(), window, cx)
18032                    })? {
18033                        Some(references) => references.await,
18034                        None => Ok(Navigated::No),
18035                    }
18036                }
18037            }
18038        })
18039    }
18040
18041    pub fn go_to_declaration(
18042        &mut self,
18043        _: &GoToDeclaration,
18044        window: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) -> Task<Result<Navigated>> {
18047        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
18048    }
18049
18050    pub fn go_to_declaration_split(
18051        &mut self,
18052        _: &GoToDeclaration,
18053        window: &mut Window,
18054        cx: &mut Context<Self>,
18055    ) -> Task<Result<Navigated>> {
18056        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
18057    }
18058
18059    pub fn go_to_implementation(
18060        &mut self,
18061        _: &GoToImplementation,
18062        window: &mut Window,
18063        cx: &mut Context<Self>,
18064    ) -> Task<Result<Navigated>> {
18065        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
18066    }
18067
18068    pub fn go_to_implementation_split(
18069        &mut self,
18070        _: &GoToImplementationSplit,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) -> Task<Result<Navigated>> {
18074        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
18075    }
18076
18077    pub fn go_to_type_definition(
18078        &mut self,
18079        _: &GoToTypeDefinition,
18080        window: &mut Window,
18081        cx: &mut Context<Self>,
18082    ) -> Task<Result<Navigated>> {
18083        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
18084    }
18085
18086    pub fn go_to_definition_split(
18087        &mut self,
18088        _: &GoToDefinitionSplit,
18089        window: &mut Window,
18090        cx: &mut Context<Self>,
18091    ) -> Task<Result<Navigated>> {
18092        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18093    }
18094
18095    pub fn go_to_type_definition_split(
18096        &mut self,
18097        _: &GoToTypeDefinitionSplit,
18098        window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) -> Task<Result<Navigated>> {
18101        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18102    }
18103
18104    fn go_to_definition_of_kind(
18105        &mut self,
18106        kind: GotoDefinitionKind,
18107        split: bool,
18108        window: &mut Window,
18109        cx: &mut Context<Self>,
18110    ) -> Task<Result<Navigated>> {
18111        let Some(provider) = self.semantics_provider.clone() else {
18112            return Task::ready(Ok(Navigated::No));
18113        };
18114        let head = self
18115            .selections
18116            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18117            .head();
18118        let buffer = self.buffer.read(cx);
18119        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18120            return Task::ready(Ok(Navigated::No));
18121        };
18122        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18123            return Task::ready(Ok(Navigated::No));
18124        };
18125
18126        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18127
18128        cx.spawn_in(window, async move |editor, cx| {
18129            let Some(definitions) = definitions.await? else {
18130                return Ok(Navigated::No);
18131            };
18132            let navigated = editor
18133                .update_in(cx, |editor, window, cx| {
18134                    editor.navigate_to_hover_links(
18135                        Some(kind),
18136                        definitions
18137                            .into_iter()
18138                            .filter(|location| {
18139                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18140                            })
18141                            .map(HoverLink::Text)
18142                            .collect::<Vec<_>>(),
18143                        nav_entry,
18144                        split,
18145                        window,
18146                        cx,
18147                    )
18148                })?
18149                .await?;
18150            anyhow::Ok(navigated)
18151        })
18152    }
18153
18154    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18155        let selection = self.selections.newest_anchor();
18156        let head = selection.head();
18157        let tail = selection.tail();
18158
18159        let Some((buffer, start_position)) =
18160            self.buffer.read(cx).text_anchor_for_position(head, cx)
18161        else {
18162            return;
18163        };
18164
18165        let end_position = if head != tail {
18166            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18167                return;
18168            };
18169            Some(pos)
18170        } else {
18171            None
18172        };
18173
18174        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18175            let url = if let Some(end_pos) = end_position {
18176                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18177            } else {
18178                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18179            };
18180
18181            if let Some(url) = url {
18182                cx.update(|window, cx| {
18183                    if parse_zed_link(&url, cx).is_some() {
18184                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18185                    } else {
18186                        cx.open_url(&url);
18187                    }
18188                })?;
18189            }
18190
18191            anyhow::Ok(())
18192        });
18193
18194        url_finder.detach();
18195    }
18196
18197    pub fn open_selected_filename(
18198        &mut self,
18199        _: &OpenSelectedFilename,
18200        window: &mut Window,
18201        cx: &mut Context<Self>,
18202    ) {
18203        let Some(workspace) = self.workspace() else {
18204            return;
18205        };
18206
18207        let position = self.selections.newest_anchor().head();
18208
18209        let Some((buffer, buffer_position)) =
18210            self.buffer.read(cx).text_anchor_for_position(position, cx)
18211        else {
18212            return;
18213        };
18214
18215        let project = self.project.clone();
18216
18217        cx.spawn_in(window, async move |_, cx| {
18218            let result = find_file(&buffer, project, buffer_position, cx).await;
18219
18220            if let Some((_, path)) = result {
18221                workspace
18222                    .update_in(cx, |workspace, window, cx| {
18223                        workspace.open_resolved_path(path, window, cx)
18224                    })?
18225                    .await?;
18226            }
18227            anyhow::Ok(())
18228        })
18229        .detach();
18230    }
18231
18232    pub(crate) fn navigate_to_hover_links(
18233        &mut self,
18234        kind: Option<GotoDefinitionKind>,
18235        definitions: Vec<HoverLink>,
18236        origin: Option<NavigationEntry>,
18237        split: bool,
18238        window: &mut Window,
18239        cx: &mut Context<Editor>,
18240    ) -> Task<Result<Navigated>> {
18241        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18242        let mut first_url_or_file = None;
18243        let definitions: Vec<_> = definitions
18244            .into_iter()
18245            .filter_map(|def| match def {
18246                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18247                HoverLink::InlayHint(lsp_location, server_id) => {
18248                    let computation =
18249                        self.compute_target_location(lsp_location, server_id, window, cx);
18250                    Some(cx.background_spawn(computation))
18251                }
18252                HoverLink::Url(url) => {
18253                    first_url_or_file = Some(Either::Left(url));
18254                    None
18255                }
18256                HoverLink::File(path) => {
18257                    first_url_or_file = Some(Either::Right(path));
18258                    None
18259                }
18260            })
18261            .collect();
18262
18263        let workspace = self.workspace();
18264
18265        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18266        cx.spawn_in(window, async move |editor, cx| {
18267            let locations: Vec<Location> = future::join_all(definitions)
18268                .await
18269                .into_iter()
18270                .filter_map(|location| location.transpose())
18271                .collect::<Result<_>>()
18272                .context("location tasks")?;
18273            let mut locations = cx.update(|_, cx| {
18274                locations
18275                    .into_iter()
18276                    .map(|location| {
18277                        let buffer = location.buffer.read(cx);
18278                        (location.buffer, location.range.to_point(buffer))
18279                    })
18280                    .into_group_map()
18281            })?;
18282            let mut num_locations = 0;
18283            for ranges in locations.values_mut() {
18284                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18285                ranges.dedup();
18286                // Merge overlapping or contained ranges. After sorting by
18287                // (start, Reverse(end)), we can merge in a single pass:
18288                // if the next range starts before the current one ends,
18289                // extend the current range's end if needed.
18290                let mut i = 0;
18291                while i + 1 < ranges.len() {
18292                    if ranges[i + 1].start <= ranges[i].end {
18293                        let merged_end = ranges[i].end.max(ranges[i + 1].end);
18294                        ranges[i].end = merged_end;
18295                        ranges.remove(i + 1);
18296                    } else {
18297                        i += 1;
18298                    }
18299                }
18300                let fits_in_one_excerpt = ranges
18301                    .iter()
18302                    .tuple_windows()
18303                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18304                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18305            }
18306
18307            if num_locations > 1 {
18308                let tab_kind = match kind {
18309                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18310                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18311                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18312                    Some(GotoDefinitionKind::Type) => "Types",
18313                };
18314                let title = editor
18315                    .update_in(cx, |_, _, cx| {
18316                        let target = locations
18317                            .iter()
18318                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18319                            .map(|(buffer, location)| {
18320                                buffer
18321                                    .read(cx)
18322                                    .text_for_range(location.clone())
18323                                    .collect::<String>()
18324                            })
18325                            .filter(|text| !text.contains('\n'))
18326                            .unique()
18327                            .take(3)
18328                            .join(", ");
18329                        if target.is_empty() {
18330                            tab_kind.to_owned()
18331                        } else {
18332                            format!("{tab_kind} for {target}")
18333                        }
18334                    })
18335                    .context("buffer title")?;
18336
18337                let Some(workspace) = workspace else {
18338                    return Ok(Navigated::No);
18339                };
18340
18341                let opened = workspace
18342                    .update_in(cx, |workspace, window, cx| {
18343                        let allow_preview = PreviewTabsSettings::get_global(cx)
18344                            .enable_preview_multibuffer_from_code_navigation;
18345                        if let Some((target_editor, target_pane)) =
18346                            Self::open_locations_in_multibuffer(
18347                                workspace,
18348                                locations,
18349                                title,
18350                                split,
18351                                allow_preview,
18352                                MultibufferSelectionMode::First,
18353                                window,
18354                                cx,
18355                            )
18356                        {
18357                            // We create our own nav history instead of using
18358                            // `target_editor.nav_history` because `nav_history`
18359                            // seems to be populated asynchronously when an item
18360                            // is added to a pane
18361                            let mut nav_history = target_pane
18362                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18363                            target_editor.update(cx, |editor, cx| {
18364                                let nav_data = editor
18365                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18366                                let target =
18367                                    Some(nav_history.navigation_entry(Some(
18368                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18369                                    )));
18370                                nav_history.push_tag(origin, target);
18371                            })
18372                        }
18373                    })
18374                    .is_ok();
18375
18376                anyhow::Ok(Navigated::from_bool(opened))
18377            } else if num_locations == 0 {
18378                // If there is one url or file, open it directly
18379                match first_url_or_file {
18380                    Some(Either::Left(url)) => {
18381                        cx.update(|window, cx| {
18382                            if parse_zed_link(&url, cx).is_some() {
18383                                window
18384                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18385                            } else {
18386                                cx.open_url(&url);
18387                            }
18388                        })?;
18389                        Ok(Navigated::Yes)
18390                    }
18391                    Some(Either::Right(path)) => {
18392                        // TODO(andrew): respect preview tab settings
18393                        //               `enable_keep_preview_on_code_navigation` and
18394                        //               `enable_preview_file_from_code_navigation`
18395                        let Some(workspace) = workspace else {
18396                            return Ok(Navigated::No);
18397                        };
18398                        workspace
18399                            .update_in(cx, |workspace, window, cx| {
18400                                workspace.open_resolved_path(path, window, cx)
18401                            })?
18402                            .await?;
18403                        Ok(Navigated::Yes)
18404                    }
18405                    None => Ok(Navigated::No),
18406                }
18407            } else {
18408                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18409
18410                editor.update_in(cx, |editor, window, cx| {
18411                    let target_ranges = target_ranges
18412                        .into_iter()
18413                        .map(|r| editor.range_for_match(&r))
18414                        .map(collapse_multiline_range)
18415                        .collect::<Vec<_>>();
18416                    if !split
18417                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18418                    {
18419                        let multibuffer = editor.buffer.read(cx);
18420                        let target_ranges = target_ranges
18421                            .into_iter()
18422                            .filter_map(|r| {
18423                                let start = multibuffer.buffer_point_to_anchor(
18424                                    &target_buffer,
18425                                    r.start,
18426                                    cx,
18427                                )?;
18428                                let end = multibuffer.buffer_point_to_anchor(
18429                                    &target_buffer,
18430                                    r.end,
18431                                    cx,
18432                                )?;
18433                                Some(start..end)
18434                            })
18435                            .collect::<Vec<_>>();
18436                        if target_ranges.is_empty() {
18437                            return Navigated::No;
18438                        }
18439
18440                        editor.change_selections(
18441                            SelectionEffects::default().nav_history(true),
18442                            window,
18443                            cx,
18444                            |s| s.select_anchor_ranges(target_ranges),
18445                        );
18446
18447                        let target =
18448                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18449                        if let Some(mut nav_history) = editor.nav_history.clone() {
18450                            nav_history.push_tag(origin, target);
18451                        }
18452                    } else {
18453                        let Some(workspace) = workspace else {
18454                            return Navigated::No;
18455                        };
18456                        let pane = workspace.read(cx).active_pane().clone();
18457                        window.defer(cx, move |window, cx| {
18458                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18459                                workspace.update(cx, |workspace, cx| {
18460                                    let pane = if split {
18461                                        workspace.adjacent_pane(window, cx)
18462                                    } else {
18463                                        workspace.active_pane().clone()
18464                                    };
18465
18466                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18467                                    let keep_old_preview = preview_tabs_settings
18468                                        .enable_keep_preview_on_code_navigation;
18469                                    let allow_new_preview = preview_tabs_settings
18470                                        .enable_preview_file_from_code_navigation;
18471
18472                                    let editor = workspace.open_project_item(
18473                                        pane.clone(),
18474                                        target_buffer.clone(),
18475                                        true,
18476                                        true,
18477                                        keep_old_preview,
18478                                        allow_new_preview,
18479                                        window,
18480                                        cx,
18481                                    );
18482                                    (editor, pane)
18483                                });
18484                            // We create our own nav history instead of using
18485                            // `target_editor.nav_history` because `nav_history`
18486                            // seems to be populated asynchronously when an item
18487                            // is added to a pane
18488                            let mut nav_history = target_pane
18489                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18490                            target_editor.update(cx, |target_editor, cx| {
18491                                // When selecting a definition in a different buffer, disable the nav history
18492                                // to avoid creating a history entry at the previous cursor location.
18493                                pane.update(cx, |pane, _| pane.disable_history());
18494
18495                                let multibuffer = target_editor.buffer.read(cx);
18496                                let Some(target_buffer) = multibuffer.as_singleton() else {
18497                                    return Navigated::No;
18498                                };
18499                                let target_ranges = target_ranges
18500                                    .into_iter()
18501                                    .filter_map(|r| {
18502                                        let start = multibuffer.buffer_point_to_anchor(
18503                                            &target_buffer,
18504                                            r.start,
18505                                            cx,
18506                                        )?;
18507                                        let end = multibuffer.buffer_point_to_anchor(
18508                                            &target_buffer,
18509                                            r.end,
18510                                            cx,
18511                                        )?;
18512                                        Some(start..end)
18513                                    })
18514                                    .collect::<Vec<_>>();
18515                                if target_ranges.is_empty() {
18516                                    return Navigated::No;
18517                                }
18518
18519                                target_editor.change_selections(
18520                                    SelectionEffects::default().nav_history(true),
18521                                    window,
18522                                    cx,
18523                                    |s| s.select_anchor_ranges(target_ranges),
18524                                );
18525
18526                                let nav_data = target_editor.navigation_data(
18527                                    target_editor.selections.newest_anchor().head(),
18528                                    cx,
18529                                );
18530                                let target =
18531                                    Some(nav_history.navigation_entry(Some(
18532                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18533                                    )));
18534                                nav_history.push_tag(origin, target);
18535                                pane.update(cx, |pane, _| pane.enable_history());
18536                                Navigated::Yes
18537                            });
18538                        });
18539                    }
18540                    Navigated::Yes
18541                })
18542            }
18543        })
18544    }
18545
18546    fn compute_target_location(
18547        &self,
18548        lsp_location: lsp::Location,
18549        server_id: LanguageServerId,
18550        window: &mut Window,
18551        cx: &mut Context<Self>,
18552    ) -> Task<anyhow::Result<Option<Location>>> {
18553        let Some(project) = self.project.clone() else {
18554            return Task::ready(Ok(None));
18555        };
18556
18557        cx.spawn_in(window, async move |editor, cx| {
18558            let location_task = editor.update(cx, |_, cx| {
18559                project.update(cx, |project, cx| {
18560                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18561                })
18562            })?;
18563            let location = Some({
18564                let target_buffer_handle = location_task.await.context("open local buffer")?;
18565                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18566                    let target_start = target_buffer
18567                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18568                    let target_end = target_buffer
18569                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18570                    target_buffer.anchor_after(target_start)
18571                        ..target_buffer.anchor_before(target_end)
18572                });
18573                Location {
18574                    buffer: target_buffer_handle,
18575                    range,
18576                }
18577            });
18578            Ok(location)
18579        })
18580    }
18581
18582    fn go_to_next_reference(
18583        &mut self,
18584        _: &GoToNextReference,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18589        if let Some(task) = task {
18590            task.detach();
18591        };
18592    }
18593
18594    fn go_to_prev_reference(
18595        &mut self,
18596        _: &GoToPreviousReference,
18597        window: &mut Window,
18598        cx: &mut Context<Self>,
18599    ) {
18600        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18601        if let Some(task) = task {
18602            task.detach();
18603        };
18604    }
18605
18606    fn go_to_symbol_by_offset(
18607        &mut self,
18608        window: &mut Window,
18609        cx: &mut Context<Self>,
18610        offset: i8,
18611    ) -> Task<Result<()>> {
18612        let editor_snapshot = self.snapshot(window, cx);
18613
18614        // We don't care about multi-buffer symbols
18615        if !editor_snapshot.is_singleton() {
18616            return Task::ready(Ok(()));
18617        }
18618
18619        let cursor_offset = self
18620            .selections
18621            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18622            .head();
18623
18624        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18625            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18626                let buffer = ed.buffer.read(cx).as_singleton()?;
18627                Some(buffer.read(cx).remote_id())
18628            }) else {
18629                return Ok(());
18630            };
18631
18632            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18633            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18634
18635            let multi_snapshot = editor_snapshot.buffer();
18636            let buffer_range = |range: &Range<_>| {
18637                Some(
18638                    multi_snapshot
18639                        .buffer_anchor_range_to_anchor_range(range.clone())?
18640                        .to_offset(multi_snapshot),
18641                )
18642            };
18643
18644            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18645                let current_idx = outline_items
18646                    .iter()
18647                    .enumerate()
18648                    .filter_map(|(idx, item)| {
18649                        // Find the closest outline item by distance between outline text and cursor location
18650                        let source_range = buffer_range(&item.source_range_for_text)?;
18651                        let distance_to_closest_endpoint = cmp::min(
18652                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18653                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18654                        );
18655
18656                        let item_towards_offset =
18657                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18658                                == (offset as isize).signum();
18659
18660                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18661
18662                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18663                        // we should not already be within the outline's source range. We then pick the closest outline
18664                        // item.
18665                        (item_towards_offset && !source_range_contains_cursor)
18666                            .then_some((distance_to_closest_endpoint, idx))
18667                    })
18668                    .min()
18669                    .map(|(_, idx)| idx);
18670
18671                let Some(idx) = current_idx else {
18672                    return;
18673                };
18674
18675                let Some(range) = buffer_range(&outline_items[idx].source_range_for_text) else {
18676                    return;
18677                };
18678                let selection = [range.start..range.start];
18679
18680                let _ = editor
18681                    .update(acx, |editor, ecx| {
18682                        editor.change_selections(
18683                            SelectionEffects::scroll(Autoscroll::newest()),
18684                            window,
18685                            ecx,
18686                            |s| s.select_ranges(selection),
18687                        );
18688                    })
18689                    .ok();
18690            })?;
18691
18692            Ok(())
18693        })
18694    }
18695
18696    fn go_to_next_symbol(
18697        &mut self,
18698        _: &GoToNextSymbol,
18699        window: &mut Window,
18700        cx: &mut Context<Self>,
18701    ) {
18702        self.go_to_symbol_by_offset(window, cx, 1).detach();
18703    }
18704
18705    fn go_to_previous_symbol(
18706        &mut self,
18707        _: &GoToPreviousSymbol,
18708        window: &mut Window,
18709        cx: &mut Context<Self>,
18710    ) {
18711        self.go_to_symbol_by_offset(window, cx, -1).detach();
18712    }
18713
18714    pub fn go_to_reference_before_or_after_position(
18715        &mut self,
18716        direction: Direction,
18717        count: usize,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) -> Option<Task<Result<()>>> {
18721        let selection = self.selections.newest_anchor();
18722        let head = selection.head();
18723
18724        let multi_buffer = self.buffer.read(cx);
18725
18726        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18727        let workspace = self.workspace()?;
18728        let project = workspace.read(cx).project().clone();
18729        let references =
18730            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18731        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18732            let Some(locations) = references.await? else {
18733                return Ok(());
18734            };
18735
18736            if locations.is_empty() {
18737                // totally normal - the cursor may be on something which is not
18738                // a symbol (e.g. a keyword)
18739                log::info!("no references found under cursor");
18740                return Ok(());
18741            }
18742
18743            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18744
18745            let (locations, current_location_index) =
18746                multi_buffer.update(cx, |multi_buffer, cx| {
18747                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18748                    let mut locations = locations
18749                        .into_iter()
18750                        .filter_map(|loc| {
18751                            let start = multi_buffer_snapshot.anchor_in_excerpt(loc.range.start)?;
18752                            let end = multi_buffer_snapshot.anchor_in_excerpt(loc.range.end)?;
18753                            Some(start..end)
18754                        })
18755                        .collect::<Vec<_>>();
18756                    // There is an O(n) implementation, but given this list will be
18757                    // small (usually <100 items), the extra O(log(n)) factor isn't
18758                    // worth the (surprisingly large amount of) extra complexity.
18759                    locations
18760                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18761
18762                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18763
18764                    let current_location_index = locations.iter().position(|loc| {
18765                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18766                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18767                    });
18768
18769                    (locations, current_location_index)
18770                });
18771
18772            let Some(current_location_index) = current_location_index else {
18773                // This indicates something has gone wrong, because we already
18774                // handle the "no references" case above
18775                log::error!(
18776                    "failed to find current reference under cursor. Total references: {}",
18777                    locations.len()
18778                );
18779                return Ok(());
18780            };
18781
18782            let destination_location_index = match direction {
18783                Direction::Next => (current_location_index + count) % locations.len(),
18784                Direction::Prev => {
18785                    (current_location_index + locations.len() - count % locations.len())
18786                        % locations.len()
18787                }
18788            };
18789
18790            // TODO(cameron): is this needed?
18791            // the thinking is to avoid "jumping to the current location" (avoid
18792            // polluting "jumplist" in vim terms)
18793            if current_location_index == destination_location_index {
18794                return Ok(());
18795            }
18796
18797            let Range { start, end } = locations[destination_location_index];
18798
18799            editor.update_in(cx, |editor, window, cx| {
18800                let effects = SelectionEffects::default();
18801
18802                editor.unfold_ranges(&[start..end], false, false, cx);
18803                editor.change_selections(effects, window, cx, |s| {
18804                    s.select_ranges([start..start]);
18805                });
18806            })?;
18807
18808            Ok(())
18809        }))
18810    }
18811
18812    pub fn find_all_references(
18813        &mut self,
18814        action: &FindAllReferences,
18815        window: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) -> Option<Task<Result<Navigated>>> {
18818        let always_open_multibuffer = action.always_open_multibuffer;
18819        let selection = self.selections.newest_anchor();
18820        let multi_buffer = self.buffer.read(cx);
18821        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18822        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18823        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18824        let head = selection_offset.head();
18825
18826        let head_anchor = multi_buffer_snapshot.anchor_at(
18827            head,
18828            if head < selection_offset.tail() {
18829                Bias::Right
18830            } else {
18831                Bias::Left
18832            },
18833        );
18834
18835        match self
18836            .find_all_references_task_sources
18837            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18838        {
18839            Ok(_) => {
18840                log::info!(
18841                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18842                );
18843                return None;
18844            }
18845            Err(i) => {
18846                self.find_all_references_task_sources.insert(i, head_anchor);
18847            }
18848        }
18849
18850        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18851        let workspace = self.workspace()?;
18852        let project = workspace.read(cx).project().clone();
18853        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18854        Some(cx.spawn_in(window, async move |editor, cx| {
18855            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18856                if let Ok(i) = editor
18857                    .find_all_references_task_sources
18858                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18859                {
18860                    editor.find_all_references_task_sources.remove(i);
18861                }
18862            });
18863
18864            let Some(locations) = references.await? else {
18865                return anyhow::Ok(Navigated::No);
18866            };
18867            let mut locations = cx.update(|_, cx| {
18868                locations
18869                    .into_iter()
18870                    .map(|location| {
18871                        let buffer = location.buffer.read(cx);
18872                        (location.buffer, location.range.to_point(buffer))
18873                    })
18874                    // if special-casing the single-match case, remove ranges
18875                    // that intersect current selection
18876                    .filter(|(location_buffer, location)| {
18877                        if always_open_multibuffer || &buffer != location_buffer {
18878                            return true;
18879                        }
18880
18881                        !location.contains_inclusive(&selection_point.range())
18882                    })
18883                    .into_group_map()
18884            })?;
18885            if locations.is_empty() {
18886                return anyhow::Ok(Navigated::No);
18887            }
18888            for ranges in locations.values_mut() {
18889                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18890                ranges.dedup();
18891            }
18892            let mut num_locations = 0;
18893            for ranges in locations.values_mut() {
18894                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18895                ranges.dedup();
18896                num_locations += ranges.len();
18897            }
18898
18899            if num_locations == 1 && !always_open_multibuffer {
18900                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18901                let target_range = target_ranges.first().unwrap().clone();
18902
18903                return editor.update_in(cx, |editor, window, cx| {
18904                    let range = target_range.to_point(target_buffer.read(cx));
18905                    let range = editor.range_for_match(&range);
18906                    let range = range.start..range.start;
18907
18908                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18909                        editor.go_to_singleton_buffer_range(range, window, cx);
18910                    } else {
18911                        let pane = workspace.read(cx).active_pane().clone();
18912                        window.defer(cx, move |window, cx| {
18913                            let target_editor: Entity<Self> =
18914                                workspace.update(cx, |workspace, cx| {
18915                                    let pane = workspace.active_pane().clone();
18916
18917                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18918                                    let keep_old_preview = preview_tabs_settings
18919                                        .enable_keep_preview_on_code_navigation;
18920                                    let allow_new_preview = preview_tabs_settings
18921                                        .enable_preview_file_from_code_navigation;
18922
18923                                    workspace.open_project_item(
18924                                        pane,
18925                                        target_buffer.clone(),
18926                                        true,
18927                                        true,
18928                                        keep_old_preview,
18929                                        allow_new_preview,
18930                                        window,
18931                                        cx,
18932                                    )
18933                                });
18934                            target_editor.update(cx, |target_editor, cx| {
18935                                // When selecting a definition in a different buffer, disable the nav history
18936                                // to avoid creating a history entry at the previous cursor location.
18937                                pane.update(cx, |pane, _| pane.disable_history());
18938                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18939                                pane.update(cx, |pane, _| pane.enable_history());
18940                            });
18941                        });
18942                    }
18943                    Navigated::No
18944                });
18945            }
18946
18947            workspace.update_in(cx, |workspace, window, cx| {
18948                let target = locations
18949                    .iter()
18950                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18951                    .map(|(buffer, location)| {
18952                        buffer
18953                            .read(cx)
18954                            .text_for_range(location.clone())
18955                            .collect::<String>()
18956                    })
18957                    .filter(|text| !text.contains('\n'))
18958                    .unique()
18959                    .take(3)
18960                    .join(", ");
18961                let title = if target.is_empty() {
18962                    "References".to_owned()
18963                } else {
18964                    format!("References to {target}")
18965                };
18966                let allow_preview = PreviewTabsSettings::get_global(cx)
18967                    .enable_preview_multibuffer_from_code_navigation;
18968                Self::open_locations_in_multibuffer(
18969                    workspace,
18970                    locations,
18971                    title,
18972                    false,
18973                    allow_preview,
18974                    MultibufferSelectionMode::First,
18975                    window,
18976                    cx,
18977                );
18978                Navigated::Yes
18979            })
18980        }))
18981    }
18982
18983    /// Opens a multibuffer with the given project locations in it.
18984    pub fn open_locations_in_multibuffer(
18985        workspace: &mut Workspace,
18986        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18987        title: String,
18988        split: bool,
18989        allow_preview: bool,
18990        multibuffer_selection_mode: MultibufferSelectionMode,
18991        window: &mut Window,
18992        cx: &mut Context<Workspace>,
18993    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18994        if locations.is_empty() {
18995            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18996            return None;
18997        }
18998
18999        let capability = workspace.project().read(cx).capability();
19000        let mut ranges = <Vec<Range<Anchor>>>::new();
19001
19002        // a key to find existing multibuffer editors with the same set of locations
19003        // to prevent us from opening more and more multibuffer tabs for searches and the like
19004        let mut key = (title.clone(), vec![]);
19005        let excerpt_buffer = cx.new(|cx| {
19006            let key = &mut key.1;
19007            let mut multibuffer = MultiBuffer::new(capability);
19008            for (buffer, mut ranges_for_buffer) in locations {
19009                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
19010                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
19011                multibuffer.set_excerpts_for_path(
19012                    PathKey::for_buffer(&buffer, cx),
19013                    buffer.clone(),
19014                    ranges_for_buffer.clone(),
19015                    multibuffer_context_lines(cx),
19016                    cx,
19017                );
19018                let snapshot = multibuffer.snapshot(cx);
19019                let buffer_snapshot = buffer.read(cx).snapshot();
19020                ranges.extend(ranges_for_buffer.into_iter().filter_map(|range| {
19021                    let text_range = buffer_snapshot.anchor_range_inside(range);
19022                    let start = snapshot.anchor_in_buffer(text_range.start)?;
19023                    let end = snapshot.anchor_in_buffer(text_range.end)?;
19024                    Some(start..end)
19025                }))
19026            }
19027
19028            multibuffer.with_title(title)
19029        });
19030        let existing = workspace.active_pane().update(cx, |pane, cx| {
19031            pane.items()
19032                .filter_map(|item| item.downcast::<Editor>())
19033                .find(|editor| {
19034                    editor
19035                        .read(cx)
19036                        .lookup_key
19037                        .as_ref()
19038                        .and_then(|it| {
19039                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
19040                        })
19041                        .is_some_and(|it| *it == key)
19042                })
19043        });
19044        let was_existing = existing.is_some();
19045        let editor = existing.unwrap_or_else(|| {
19046            cx.new(|cx| {
19047                let mut editor = Editor::for_multibuffer(
19048                    excerpt_buffer,
19049                    Some(workspace.project().clone()),
19050                    window,
19051                    cx,
19052                );
19053                editor.lookup_key = Some(Box::new(key));
19054                editor
19055            })
19056        });
19057        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
19058            MultibufferSelectionMode::First => {
19059                if let Some(first_range) = ranges.first() {
19060                    editor.change_selections(
19061                        SelectionEffects::no_scroll(),
19062                        window,
19063                        cx,
19064                        |selections| {
19065                            selections.clear_disjoint();
19066                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
19067                        },
19068                    );
19069                }
19070                editor.highlight_background(
19071                    HighlightKey::Editor,
19072                    &ranges,
19073                    |_, theme| theme.colors().editor_highlighted_line_background,
19074                    cx,
19075                );
19076            }
19077            MultibufferSelectionMode::All => {
19078                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
19079                    selections.clear_disjoint();
19080                    selections.select_anchor_ranges(ranges);
19081                });
19082            }
19083        });
19084
19085        let item = Box::new(editor.clone());
19086
19087        let pane = if split {
19088            workspace.adjacent_pane(window, cx)
19089        } else {
19090            workspace.active_pane().clone()
19091        };
19092        let activate_pane = split;
19093
19094        let mut destination_index = None;
19095        pane.update(cx, |pane, cx| {
19096            if allow_preview && !was_existing {
19097                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
19098            }
19099            if was_existing && !allow_preview {
19100                pane.unpreview_item_if_preview(item.item_id());
19101            }
19102            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19103        });
19104
19105        Some((editor, pane))
19106    }
19107
19108    pub fn rename(
19109        &mut self,
19110        _: &Rename,
19111        window: &mut Window,
19112        cx: &mut Context<Self>,
19113    ) -> Option<Task<Result<()>>> {
19114        use language::ToOffset as _;
19115
19116        let provider = self.semantics_provider.clone()?;
19117        let selection = self.selections.newest_anchor().clone();
19118        let (cursor_buffer, cursor_buffer_position) = self
19119            .buffer
19120            .read(cx)
19121            .text_anchor_for_position(selection.head(), cx)?;
19122        let (tail_buffer, cursor_buffer_position_end) = self
19123            .buffer
19124            .read(cx)
19125            .text_anchor_for_position(selection.tail(), cx)?;
19126        if tail_buffer != cursor_buffer {
19127            return None;
19128        }
19129
19130        let snapshot = cursor_buffer.read(cx).snapshot();
19131        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19132        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19133        let prepare_rename = provider.range_for_rename(&cursor_buffer, cursor_buffer_position, cx);
19134        drop(snapshot);
19135
19136        Some(cx.spawn_in(window, async move |this, cx| {
19137            let rename_range = prepare_rename.await?;
19138            if let Some(rename_range) = rename_range {
19139                this.update_in(cx, |this, window, cx| {
19140                    let snapshot = cursor_buffer.read(cx).snapshot();
19141                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19142                    let cursor_offset_in_rename_range =
19143                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19144                    let cursor_offset_in_rename_range_end =
19145                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19146
19147                    this.take_rename(false, window, cx);
19148                    let buffer = this.buffer.read(cx).read(cx);
19149                    let cursor_offset = selection.head().to_offset(&buffer);
19150                    let rename_start =
19151                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19152                    let rename_end = rename_start + rename_buffer_range.len();
19153                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19154                    let mut old_highlight_id = None;
19155                    let old_name: Arc<str> = buffer
19156                        .chunks(
19157                            rename_start..rename_end,
19158                            LanguageAwareStyling {
19159                                tree_sitter: true,
19160                                diagnostics: true,
19161                            },
19162                        )
19163                        .map(|chunk| {
19164                            if old_highlight_id.is_none() {
19165                                old_highlight_id = chunk.syntax_highlight_id;
19166                            }
19167                            chunk.text
19168                        })
19169                        .collect::<String>()
19170                        .into();
19171
19172                    drop(buffer);
19173
19174                    // Position the selection in the rename editor so that it matches the current selection.
19175                    this.show_local_selections = false;
19176                    let rename_editor = cx.new(|cx| {
19177                        let mut editor = Editor::single_line(window, cx);
19178                        editor.buffer.update(cx, |buffer, cx| {
19179                            buffer.edit(
19180                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19181                                None,
19182                                cx,
19183                            )
19184                        });
19185                        let cursor_offset_in_rename_range =
19186                            MultiBufferOffset(cursor_offset_in_rename_range);
19187                        let cursor_offset_in_rename_range_end =
19188                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19189                        let rename_selection_range = match cursor_offset_in_rename_range
19190                            .cmp(&cursor_offset_in_rename_range_end)
19191                        {
19192                            Ordering::Equal => {
19193                                editor.select_all(&SelectAll, window, cx);
19194                                return editor;
19195                            }
19196                            Ordering::Less => {
19197                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19198                            }
19199                            Ordering::Greater => {
19200                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19201                            }
19202                        };
19203                        if rename_selection_range.end.0 > old_name.len() {
19204                            editor.select_all(&SelectAll, window, cx);
19205                        } else {
19206                            editor.change_selections(Default::default(), window, cx, |s| {
19207                                s.select_ranges([rename_selection_range]);
19208                            });
19209                        }
19210                        editor
19211                    });
19212                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19213                        if e == &EditorEvent::Focused {
19214                            cx.emit(EditorEvent::FocusedIn)
19215                        }
19216                    })
19217                    .detach();
19218
19219                    let write_highlights =
19220                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19221                    let read_highlights =
19222                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19223                    let ranges = write_highlights
19224                        .iter()
19225                        .flat_map(|(_, ranges)| ranges.iter())
19226                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19227                        .cloned()
19228                        .collect();
19229
19230                    this.highlight_text(
19231                        HighlightKey::Rename,
19232                        ranges,
19233                        HighlightStyle {
19234                            fade_out: Some(0.6),
19235                            ..Default::default()
19236                        },
19237                        cx,
19238                    );
19239                    let rename_focus_handle = rename_editor.focus_handle(cx);
19240                    window.focus(&rename_focus_handle, cx);
19241                    let block_id = this.insert_blocks(
19242                        [BlockProperties {
19243                            style: BlockStyle::Flex,
19244                            placement: BlockPlacement::Below(range.start),
19245                            height: Some(1),
19246                            render: Arc::new({
19247                                let rename_editor = rename_editor.clone();
19248                                move |cx: &mut BlockContext| {
19249                                    let mut text_style = cx.editor_style.text.clone();
19250                                    if let Some(highlight_style) = old_highlight_id
19251                                        .and_then(|h| cx.editor_style.syntax.get(h).cloned())
19252                                    {
19253                                        text_style = text_style.highlight(highlight_style);
19254                                    }
19255                                    div()
19256                                        .block_mouse_except_scroll()
19257                                        .pl(cx.anchor_x)
19258                                        .child(EditorElement::new(
19259                                            &rename_editor,
19260                                            EditorStyle {
19261                                                background: cx.theme().system().transparent,
19262                                                local_player: cx.editor_style.local_player,
19263                                                text: text_style,
19264                                                scrollbar_width: cx.editor_style.scrollbar_width,
19265                                                syntax: cx.editor_style.syntax.clone(),
19266                                                status: cx.editor_style.status.clone(),
19267                                                inlay_hints_style: HighlightStyle {
19268                                                    font_weight: Some(FontWeight::BOLD),
19269                                                    ..make_inlay_hints_style(cx.app)
19270                                                },
19271                                                edit_prediction_styles: make_suggestion_styles(
19272                                                    cx.app,
19273                                                ),
19274                                                ..EditorStyle::default()
19275                                            },
19276                                        ))
19277                                        .into_any_element()
19278                                }
19279                            }),
19280                            priority: 0,
19281                        }],
19282                        Some(Autoscroll::fit()),
19283                        cx,
19284                    )[0];
19285                    this.pending_rename = Some(RenameState {
19286                        range,
19287                        old_name,
19288                        editor: rename_editor,
19289                        block_id,
19290                    });
19291                })?;
19292            }
19293
19294            Ok(())
19295        }))
19296    }
19297
19298    pub fn confirm_rename(
19299        &mut self,
19300        _: &ConfirmRename,
19301        window: &mut Window,
19302        cx: &mut Context<Self>,
19303    ) -> Option<Task<Result<()>>> {
19304        let rename = self.take_rename(false, window, cx)?;
19305        let workspace = self.workspace()?.downgrade();
19306        let (buffer, start) = self
19307            .buffer
19308            .read(cx)
19309            .text_anchor_for_position(rename.range.start, cx)?;
19310        let (end_buffer, _) = self
19311            .buffer
19312            .read(cx)
19313            .text_anchor_for_position(rename.range.end, cx)?;
19314        if buffer != end_buffer {
19315            return None;
19316        }
19317
19318        let old_name = rename.old_name;
19319        let new_name = rename.editor.read(cx).text(cx);
19320
19321        let rename = self.semantics_provider.as_ref()?.perform_rename(
19322            &buffer,
19323            start,
19324            new_name.clone(),
19325            cx,
19326        )?;
19327
19328        Some(cx.spawn_in(window, async move |editor, cx| {
19329            let project_transaction = rename.await?;
19330            Self::open_project_transaction(
19331                &editor,
19332                workspace,
19333                project_transaction,
19334                format!("Rename: {}{}", old_name, new_name),
19335                cx,
19336            )
19337            .await?;
19338
19339            editor.update(cx, |editor, cx| {
19340                editor.refresh_document_highlights(cx);
19341            })?;
19342            Ok(())
19343        }))
19344    }
19345
19346    fn take_rename(
19347        &mut self,
19348        moving_cursor: bool,
19349        window: &mut Window,
19350        cx: &mut Context<Self>,
19351    ) -> Option<RenameState> {
19352        let rename = self.pending_rename.take()?;
19353        if rename.editor.focus_handle(cx).is_focused(window) {
19354            window.focus(&self.focus_handle, cx);
19355        }
19356
19357        self.remove_blocks(
19358            [rename.block_id].into_iter().collect(),
19359            Some(Autoscroll::fit()),
19360            cx,
19361        );
19362        self.clear_highlights(HighlightKey::Rename, cx);
19363        self.show_local_selections = true;
19364
19365        if moving_cursor {
19366            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19367                editor
19368                    .selections
19369                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19370                    .head()
19371            });
19372
19373            // Update the selection to match the position of the selection inside
19374            // the rename editor.
19375            let snapshot = self.buffer.read(cx).read(cx);
19376            let rename_range = rename.range.to_offset(&snapshot);
19377            let cursor_in_editor = snapshot
19378                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19379                .min(rename_range.end);
19380            drop(snapshot);
19381
19382            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19383                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19384            });
19385        } else {
19386            self.refresh_document_highlights(cx);
19387        }
19388
19389        Some(rename)
19390    }
19391
19392    pub fn pending_rename(&self) -> Option<&RenameState> {
19393        self.pending_rename.as_ref()
19394    }
19395
19396    fn format(
19397        &mut self,
19398        _: &Format,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) -> Option<Task<Result<()>>> {
19402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19403
19404        let project = match &self.project {
19405            Some(project) => project.clone(),
19406            None => return None,
19407        };
19408
19409        Some(self.perform_format(
19410            project,
19411            FormatTrigger::Manual,
19412            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19413            window,
19414            cx,
19415        ))
19416    }
19417
19418    fn format_selections(
19419        &mut self,
19420        _: &FormatSelections,
19421        window: &mut Window,
19422        cx: &mut Context<Self>,
19423    ) -> Option<Task<Result<()>>> {
19424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19425
19426        let project = match &self.project {
19427            Some(project) => project.clone(),
19428            None => return None,
19429        };
19430
19431        let ranges = self
19432            .selections
19433            .all_adjusted(&self.display_snapshot(cx))
19434            .into_iter()
19435            .map(|selection| selection.range())
19436            .collect_vec();
19437
19438        Some(self.perform_format(
19439            project,
19440            FormatTrigger::Manual,
19441            FormatTarget::Ranges(ranges),
19442            window,
19443            cx,
19444        ))
19445    }
19446
19447    fn perform_format(
19448        &mut self,
19449        project: Entity<Project>,
19450        trigger: FormatTrigger,
19451        target: FormatTarget,
19452        window: &mut Window,
19453        cx: &mut Context<Self>,
19454    ) -> Task<Result<()>> {
19455        let buffer = self.buffer.clone();
19456        let (buffers, target) = match target {
19457            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19458            FormatTarget::Ranges(selection_ranges) => {
19459                let multi_buffer = buffer.read(cx);
19460                let snapshot = multi_buffer.read(cx);
19461                let mut buffers = HashSet::default();
19462                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19463                    BTreeMap::new();
19464                for selection_range in selection_ranges {
19465                    for (buffer_snapshot, buffer_range, _) in
19466                        snapshot.range_to_buffer_ranges(selection_range.start..selection_range.end)
19467                    {
19468                        let buffer_id = buffer_snapshot.remote_id();
19469                        let start = buffer_snapshot.anchor_before(buffer_range.start);
19470                        let end = buffer_snapshot.anchor_after(buffer_range.end);
19471                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19472                        buffer_id_to_ranges
19473                            .entry(buffer_id)
19474                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19475                            .or_insert_with(|| vec![start..end]);
19476                    }
19477                }
19478                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19479            }
19480        };
19481
19482        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19483        let selections_prev = transaction_id_prev
19484            .and_then(|transaction_id_prev| {
19485                // default to selections as they were after the last edit, if we have them,
19486                // instead of how they are now.
19487                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19488                // will take you back to where you made the last edit, instead of staying where you scrolled
19489                self.selection_history
19490                    .transaction(transaction_id_prev)
19491                    .map(|t| t.0.clone())
19492            })
19493            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19494
19495        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19496        let format = project.update(cx, |project, cx| {
19497            project.format(buffers, target, true, trigger, cx)
19498        });
19499
19500        cx.spawn_in(window, async move |editor, cx| {
19501            let transaction = futures::select_biased! {
19502                transaction = format.log_err().fuse() => transaction,
19503                () = timeout => {
19504                    log::warn!("timed out waiting for formatting");
19505                    None
19506                }
19507            };
19508
19509            buffer.update(cx, |buffer, cx| {
19510                if let Some(transaction) = transaction
19511                    && !buffer.is_singleton()
19512                {
19513                    buffer.push_transaction(&transaction.0, cx);
19514                }
19515                cx.notify();
19516            });
19517
19518            if let Some(transaction_id_now) =
19519                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19520            {
19521                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19522                if has_new_transaction {
19523                    editor
19524                        .update(cx, |editor, _| {
19525                            editor
19526                                .selection_history
19527                                .insert_transaction(transaction_id_now, selections_prev);
19528                        })
19529                        .ok();
19530                }
19531            }
19532
19533            Ok(())
19534        })
19535    }
19536
19537    fn organize_imports(
19538        &mut self,
19539        _: &OrganizeImports,
19540        window: &mut Window,
19541        cx: &mut Context<Self>,
19542    ) -> Option<Task<Result<()>>> {
19543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19544        let project = match &self.project {
19545            Some(project) => project.clone(),
19546            None => return None,
19547        };
19548        Some(self.perform_code_action_kind(
19549            project,
19550            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19551            window,
19552            cx,
19553        ))
19554    }
19555
19556    fn perform_code_action_kind(
19557        &mut self,
19558        project: Entity<Project>,
19559        kind: CodeActionKind,
19560        window: &mut Window,
19561        cx: &mut Context<Self>,
19562    ) -> Task<Result<()>> {
19563        let buffer = self.buffer.clone();
19564        let buffers = buffer.read(cx).all_buffers();
19565        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19566        let apply_action = project.update(cx, |project, cx| {
19567            project.apply_code_action_kind(buffers, kind, true, cx)
19568        });
19569        cx.spawn_in(window, async move |_, cx| {
19570            let transaction = futures::select_biased! {
19571                () = timeout => {
19572                    log::warn!("timed out waiting for executing code action");
19573                    None
19574                }
19575                transaction = apply_action.log_err().fuse() => transaction,
19576            };
19577            buffer.update(cx, |buffer, cx| {
19578                // check if we need this
19579                if let Some(transaction) = transaction
19580                    && !buffer.is_singleton()
19581                {
19582                    buffer.push_transaction(&transaction.0, cx);
19583                }
19584                cx.notify();
19585            });
19586            Ok(())
19587        })
19588    }
19589
19590    pub fn restart_language_server(
19591        &mut self,
19592        _: &RestartLanguageServer,
19593        _: &mut Window,
19594        cx: &mut Context<Self>,
19595    ) {
19596        if let Some(project) = self.project.clone() {
19597            self.buffer.update(cx, |multi_buffer, cx| {
19598                project.update(cx, |project, cx| {
19599                    project.restart_language_servers_for_buffers(
19600                        multi_buffer.all_buffers().into_iter().collect(),
19601                        HashSet::default(),
19602                        cx,
19603                    );
19604                });
19605            })
19606        }
19607    }
19608
19609    pub fn stop_language_server(
19610        &mut self,
19611        _: &StopLanguageServer,
19612        _: &mut Window,
19613        cx: &mut Context<Self>,
19614    ) {
19615        if let Some(project) = self.project.clone() {
19616            self.buffer.update(cx, |multi_buffer, cx| {
19617                project.update(cx, |project, cx| {
19618                    project.stop_language_servers_for_buffers(
19619                        multi_buffer.all_buffers().into_iter().collect(),
19620                        HashSet::default(),
19621                        cx,
19622                    );
19623                });
19624            });
19625        }
19626    }
19627
19628    fn cancel_language_server_work(
19629        workspace: &mut Workspace,
19630        _: &actions::CancelLanguageServerWork,
19631        _: &mut Window,
19632        cx: &mut Context<Workspace>,
19633    ) {
19634        let project = workspace.project();
19635        let buffers = workspace
19636            .active_item(cx)
19637            .and_then(|item| item.act_as::<Editor>(cx))
19638            .map_or(HashSet::default(), |editor| {
19639                editor.read(cx).buffer.read(cx).all_buffers()
19640            });
19641        project.update(cx, |project, cx| {
19642            project.cancel_language_server_work_for_buffers(buffers, cx);
19643        });
19644    }
19645
19646    fn show_character_palette(
19647        &mut self,
19648        _: &ShowCharacterPalette,
19649        window: &mut Window,
19650        _: &mut Context<Self>,
19651    ) {
19652        window.show_character_palette();
19653    }
19654
19655    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19656        if !self.diagnostics_enabled() {
19657            return;
19658        }
19659
19660        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19661            let buffer = self.buffer.read(cx).snapshot(cx);
19662            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19663            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19664            let is_valid = buffer
19665                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19666                .any(|entry| {
19667                    entry.diagnostic.is_primary
19668                        && !entry.range.is_empty()
19669                        && entry.range.start == primary_range_start
19670                        && entry.diagnostic.message == active_diagnostics.active_message
19671                });
19672
19673            if !is_valid {
19674                self.dismiss_diagnostics(cx);
19675            }
19676        }
19677    }
19678
19679    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19680        match &self.active_diagnostics {
19681            ActiveDiagnostic::Group(group) => Some(group),
19682            _ => None,
19683        }
19684    }
19685
19686    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19687        if !self.diagnostics_enabled() {
19688            return;
19689        }
19690        self.dismiss_diagnostics(cx);
19691        self.active_diagnostics = ActiveDiagnostic::All;
19692    }
19693
19694    fn activate_diagnostics(
19695        &mut self,
19696        buffer_id: BufferId,
19697        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19698        window: &mut Window,
19699        cx: &mut Context<Self>,
19700    ) {
19701        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19702            return;
19703        }
19704        self.dismiss_diagnostics(cx);
19705        let snapshot = self.snapshot(window, cx);
19706        let buffer = self.buffer.read(cx).snapshot(cx);
19707        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19708            return;
19709        };
19710
19711        let diagnostic_group = buffer
19712            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19713            .collect::<Vec<_>>();
19714
19715        let language_registry = self
19716            .project()
19717            .map(|project| project.read(cx).languages().clone());
19718
19719        let blocks = renderer.render_group(
19720            diagnostic_group,
19721            buffer_id,
19722            snapshot,
19723            cx.weak_entity(),
19724            language_registry,
19725            cx,
19726        );
19727
19728        let blocks = self.display_map.update(cx, |display_map, cx| {
19729            display_map.insert_blocks(blocks, cx).into_iter().collect()
19730        });
19731        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19732            active_range: buffer.anchor_before(diagnostic.range.start)
19733                ..buffer.anchor_after(diagnostic.range.end),
19734            active_message: diagnostic.diagnostic.message.clone(),
19735            group_id: diagnostic.diagnostic.group_id,
19736            blocks,
19737        });
19738        cx.notify();
19739    }
19740
19741    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19742        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19743            return;
19744        };
19745
19746        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19747        if let ActiveDiagnostic::Group(group) = prev {
19748            self.display_map.update(cx, |display_map, cx| {
19749                display_map.remove_blocks(group.blocks, cx);
19750            });
19751            cx.notify();
19752        }
19753    }
19754
19755    /// Disable inline diagnostics rendering for this editor.
19756    pub fn disable_inline_diagnostics(&mut self) {
19757        self.inline_diagnostics_enabled = false;
19758        self.inline_diagnostics_update = Task::ready(());
19759        self.inline_diagnostics.clear();
19760    }
19761
19762    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19763        self.diagnostics_enabled = false;
19764        self.dismiss_diagnostics(cx);
19765        self.inline_diagnostics_update = Task::ready(());
19766        self.inline_diagnostics.clear();
19767    }
19768
19769    pub fn disable_word_completions(&mut self) {
19770        self.word_completions_enabled = false;
19771    }
19772
19773    pub fn diagnostics_enabled(&self) -> bool {
19774        self.diagnostics_enabled && self.lsp_data_enabled()
19775    }
19776
19777    pub fn inline_diagnostics_enabled(&self) -> bool {
19778        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19779    }
19780
19781    pub fn show_inline_diagnostics(&self) -> bool {
19782        self.show_inline_diagnostics
19783    }
19784
19785    pub fn toggle_inline_diagnostics(
19786        &mut self,
19787        _: &ToggleInlineDiagnostics,
19788        window: &mut Window,
19789        cx: &mut Context<Editor>,
19790    ) {
19791        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19792        self.refresh_inline_diagnostics(false, window, cx);
19793    }
19794
19795    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19796        self.diagnostics_max_severity = severity;
19797        self.display_map.update(cx, |display_map, _| {
19798            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19799        });
19800    }
19801
19802    pub fn toggle_diagnostics(
19803        &mut self,
19804        _: &ToggleDiagnostics,
19805        window: &mut Window,
19806        cx: &mut Context<Editor>,
19807    ) {
19808        if !self.diagnostics_enabled() {
19809            return;
19810        }
19811
19812        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19813            EditorSettings::get_global(cx)
19814                .diagnostics_max_severity
19815                .filter(|severity| severity != &DiagnosticSeverity::Off)
19816                .unwrap_or(DiagnosticSeverity::Hint)
19817        } else {
19818            DiagnosticSeverity::Off
19819        };
19820        self.set_max_diagnostics_severity(new_severity, cx);
19821        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19822            self.active_diagnostics = ActiveDiagnostic::None;
19823            self.inline_diagnostics_update = Task::ready(());
19824            self.inline_diagnostics.clear();
19825        } else {
19826            self.refresh_inline_diagnostics(false, window, cx);
19827        }
19828
19829        cx.notify();
19830    }
19831
19832    pub fn toggle_minimap(
19833        &mut self,
19834        _: &ToggleMinimap,
19835        window: &mut Window,
19836        cx: &mut Context<Editor>,
19837    ) {
19838        if self.supports_minimap(cx) {
19839            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19840        }
19841    }
19842
19843    fn refresh_inline_diagnostics(
19844        &mut self,
19845        debounce: bool,
19846        window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        let max_severity = ProjectSettings::get_global(cx)
19850            .diagnostics
19851            .inline
19852            .max_severity
19853            .unwrap_or(self.diagnostics_max_severity);
19854
19855        if !self.inline_diagnostics_enabled()
19856            || !self.diagnostics_enabled()
19857            || !self.show_inline_diagnostics
19858            || max_severity == DiagnosticSeverity::Off
19859        {
19860            self.inline_diagnostics_update = Task::ready(());
19861            self.inline_diagnostics.clear();
19862            return;
19863        }
19864
19865        let debounce_ms = ProjectSettings::get_global(cx)
19866            .diagnostics
19867            .inline
19868            .update_debounce_ms;
19869        let debounce = if debounce && debounce_ms > 0 {
19870            Some(Duration::from_millis(debounce_ms))
19871        } else {
19872            None
19873        };
19874        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19875            if let Some(debounce) = debounce {
19876                cx.background_executor().timer(debounce).await;
19877            }
19878            let Some(snapshot) = editor.upgrade().map(|editor| {
19879                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19880            }) else {
19881                return;
19882            };
19883
19884            let new_inline_diagnostics = cx
19885                .background_spawn(async move {
19886                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19887                    for diagnostic_entry in
19888                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19889                    {
19890                        let message = diagnostic_entry
19891                            .diagnostic
19892                            .message
19893                            .split_once('\n')
19894                            .map(|(line, _)| line)
19895                            .map(SharedString::new)
19896                            .unwrap_or_else(|| {
19897                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19898                            });
19899                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19900                        let (Ok(i) | Err(i)) = inline_diagnostics
19901                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19902                        inline_diagnostics.insert(
19903                            i,
19904                            (
19905                                start_anchor,
19906                                InlineDiagnostic {
19907                                    message,
19908                                    group_id: diagnostic_entry.diagnostic.group_id,
19909                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19910                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19911                                    severity: diagnostic_entry.diagnostic.severity,
19912                                },
19913                            ),
19914                        );
19915                    }
19916                    inline_diagnostics
19917                })
19918                .await;
19919
19920            editor
19921                .update(cx, |editor, cx| {
19922                    editor.inline_diagnostics = new_inline_diagnostics;
19923                    cx.notify();
19924                })
19925                .ok();
19926        });
19927    }
19928
19929    fn pull_diagnostics(
19930        &mut self,
19931        buffer_id: BufferId,
19932        _window: &Window,
19933        cx: &mut Context<Self>,
19934    ) -> Option<()> {
19935        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19936        // skip any LSP updates for it.
19937
19938        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19939            return None;
19940        }
19941        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19942            .diagnostics
19943            .lsp_pull_diagnostics;
19944        if !pull_diagnostics_settings.enabled {
19945            return None;
19946        }
19947        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19948        let project = self.project()?.downgrade();
19949        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19950
19951        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19952            cx.background_executor().timer(debounce).await;
19953            if let Ok(task) = project.update(cx, |project, cx| {
19954                project.lsp_store().update(cx, |lsp_store, cx| {
19955                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19956                })
19957            }) {
19958                task.await.log_err();
19959            }
19960            project
19961                .update(cx, |project, cx| {
19962                    project.lsp_store().update(cx, |lsp_store, cx| {
19963                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19964                    })
19965                })
19966                .log_err();
19967        });
19968
19969        Some(())
19970    }
19971
19972    pub fn set_selections_from_remote(
19973        &mut self,
19974        selections: Vec<Selection<Anchor>>,
19975        pending_selection: Option<Selection<Anchor>>,
19976        window: &mut Window,
19977        cx: &mut Context<Self>,
19978    ) {
19979        let old_cursor_position = self.selections.newest_anchor().head();
19980        self.selections
19981            .change_with(&self.display_snapshot(cx), |s| {
19982                s.select_anchors(selections);
19983                if let Some(pending_selection) = pending_selection {
19984                    s.set_pending(pending_selection, SelectMode::Character);
19985                } else {
19986                    s.clear_pending();
19987                }
19988            });
19989        self.selections_did_change(
19990            false,
19991            &old_cursor_position,
19992            SelectionEffects::default(),
19993            window,
19994            cx,
19995        );
19996    }
19997
19998    pub fn transact(
19999        &mut self,
20000        window: &mut Window,
20001        cx: &mut Context<Self>,
20002        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
20003    ) -> Option<TransactionId> {
20004        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
20005            this.start_transaction_at(Instant::now(), window, cx);
20006            update(this, window, cx);
20007            this.end_transaction_at(Instant::now(), cx)
20008        })
20009    }
20010
20011    pub fn start_transaction_at(
20012        &mut self,
20013        now: Instant,
20014        window: &mut Window,
20015        cx: &mut Context<Self>,
20016    ) -> Option<TransactionId> {
20017        self.end_selection(window, cx);
20018        if let Some(tx_id) = self
20019            .buffer
20020            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
20021        {
20022            self.selection_history
20023                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
20024            cx.emit(EditorEvent::TransactionBegun {
20025                transaction_id: tx_id,
20026            });
20027            Some(tx_id)
20028        } else {
20029            None
20030        }
20031    }
20032
20033    pub fn end_transaction_at(
20034        &mut self,
20035        now: Instant,
20036        cx: &mut Context<Self>,
20037    ) -> Option<TransactionId> {
20038        if let Some(transaction_id) = self
20039            .buffer
20040            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
20041        {
20042            if let Some((_, end_selections)) =
20043                self.selection_history.transaction_mut(transaction_id)
20044            {
20045                *end_selections = Some(self.selections.disjoint_anchors_arc());
20046            } else {
20047                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
20048            }
20049
20050            cx.emit(EditorEvent::Edited { transaction_id });
20051            Some(transaction_id)
20052        } else {
20053            None
20054        }
20055    }
20056
20057    pub fn modify_transaction_selection_history(
20058        &mut self,
20059        transaction_id: TransactionId,
20060        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
20061    ) -> bool {
20062        self.selection_history
20063            .transaction_mut(transaction_id)
20064            .map(modify)
20065            .is_some()
20066    }
20067
20068    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
20069        if self.selection_mark_mode {
20070            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20071                s.move_with(&mut |_, sel| {
20072                    sel.collapse_to(sel.head(), SelectionGoal::None);
20073                });
20074            })
20075        }
20076        self.selection_mark_mode = true;
20077        cx.notify();
20078    }
20079
20080    pub fn swap_selection_ends(
20081        &mut self,
20082        _: &actions::SwapSelectionEnds,
20083        window: &mut Window,
20084        cx: &mut Context<Self>,
20085    ) {
20086        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20087            s.move_with(&mut |_, sel| {
20088                if sel.start != sel.end {
20089                    sel.reversed = !sel.reversed
20090                }
20091            });
20092        });
20093        self.request_autoscroll(Autoscroll::newest(), cx);
20094        cx.notify();
20095    }
20096
20097    pub fn toggle_focus(
20098        workspace: &mut Workspace,
20099        _: &actions::ToggleFocus,
20100        window: &mut Window,
20101        cx: &mut Context<Workspace>,
20102    ) {
20103        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20104            return;
20105        };
20106        workspace.activate_item(&item, true, true, window, cx);
20107    }
20108
20109    pub fn toggle_fold(
20110        &mut self,
20111        _: &actions::ToggleFold,
20112        window: &mut Window,
20113        cx: &mut Context<Self>,
20114    ) {
20115        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20116            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20117            let selection = self.selections.newest::<Point>(&display_map);
20118
20119            let range = if selection.is_empty() {
20120                let point = selection.head().to_display_point(&display_map);
20121                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20122                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20123                    .to_point(&display_map);
20124                start..end
20125            } else {
20126                selection.range()
20127            };
20128            if display_map.folds_in_range(range).next().is_some() {
20129                self.unfold_lines(&Default::default(), window, cx)
20130            } else {
20131                self.fold(&Default::default(), window, cx)
20132            }
20133        } else {
20134            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20135            let buffer_ids: HashSet<_> = self
20136                .selections
20137                .disjoint_anchor_ranges()
20138                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20139                .collect();
20140
20141            let should_unfold = buffer_ids
20142                .iter()
20143                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20144
20145            for buffer_id in buffer_ids {
20146                if should_unfold {
20147                    self.unfold_buffer(buffer_id, cx);
20148                } else {
20149                    self.fold_buffer(buffer_id, cx);
20150                }
20151            }
20152        }
20153    }
20154
20155    pub fn toggle_fold_recursive(
20156        &mut self,
20157        _: &actions::ToggleFoldRecursive,
20158        window: &mut Window,
20159        cx: &mut Context<Self>,
20160    ) {
20161        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20162
20163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20164        let range = if selection.is_empty() {
20165            let point = selection.head().to_display_point(&display_map);
20166            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20167            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20168                .to_point(&display_map);
20169            start..end
20170        } else {
20171            selection.range()
20172        };
20173        if display_map.folds_in_range(range).next().is_some() {
20174            self.unfold_recursive(&Default::default(), window, cx)
20175        } else {
20176            self.fold_recursive(&Default::default(), window, cx)
20177        }
20178    }
20179
20180    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20181        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20182            let mut to_fold = Vec::new();
20183            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20184            let selections = self.selections.all_adjusted(&display_map);
20185
20186            for selection in selections {
20187                let range = selection.range().sorted();
20188                let buffer_start_row = range.start.row;
20189
20190                if range.start.row != range.end.row {
20191                    let mut found = false;
20192                    let mut row = range.start.row;
20193                    while row <= range.end.row {
20194                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20195                        {
20196                            found = true;
20197                            row = crease.range().end.row + 1;
20198                            to_fold.push(crease);
20199                        } else {
20200                            row += 1
20201                        }
20202                    }
20203                    if found {
20204                        continue;
20205                    }
20206                }
20207
20208                for row in (0..=range.start.row).rev() {
20209                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20210                        && crease.range().end.row >= buffer_start_row
20211                    {
20212                        to_fold.push(crease);
20213                        if row <= range.start.row {
20214                            break;
20215                        }
20216                    }
20217                }
20218            }
20219
20220            self.fold_creases(to_fold, true, window, cx);
20221        } else {
20222            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20223            let buffer_ids = self
20224                .selections
20225                .disjoint_anchor_ranges()
20226                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20227                .collect::<HashSet<_>>();
20228            for buffer_id in buffer_ids {
20229                self.fold_buffer(buffer_id, cx);
20230            }
20231        }
20232    }
20233
20234    pub fn toggle_fold_all(
20235        &mut self,
20236        _: &actions::ToggleFoldAll,
20237        window: &mut Window,
20238        cx: &mut Context<Self>,
20239    ) {
20240        let has_folds = if self.buffer.read(cx).is_singleton() {
20241            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20242            let has_folds = display_map
20243                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20244                .next()
20245                .is_some();
20246            has_folds
20247        } else {
20248            let snapshot = self.buffer.read(cx).snapshot(cx);
20249            let has_folds = snapshot
20250                .all_buffer_ids()
20251                .any(|buffer_id| self.is_buffer_folded(buffer_id, cx));
20252            has_folds
20253        };
20254
20255        if has_folds {
20256            self.unfold_all(&actions::UnfoldAll, window, cx);
20257        } else {
20258            self.fold_all(&actions::FoldAll, window, cx);
20259        }
20260    }
20261
20262    fn fold_at_level(
20263        &mut self,
20264        fold_at: &FoldAtLevel,
20265        window: &mut Window,
20266        cx: &mut Context<Self>,
20267    ) {
20268        if !self.buffer.read(cx).is_singleton() {
20269            return;
20270        }
20271
20272        let fold_at_level = fold_at.0;
20273        let snapshot = self.buffer.read(cx).snapshot(cx);
20274        let mut to_fold = Vec::new();
20275        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20276
20277        let row_ranges_to_keep: Vec<Range<u32>> = self
20278            .selections
20279            .all::<Point>(&self.display_snapshot(cx))
20280            .into_iter()
20281            .map(|sel| sel.start.row..sel.end.row)
20282            .collect();
20283
20284        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20285            while start_row < end_row {
20286                match self
20287                    .snapshot(window, cx)
20288                    .crease_for_buffer_row(MultiBufferRow(start_row))
20289                {
20290                    Some(crease) => {
20291                        let nested_start_row = crease.range().start.row + 1;
20292                        let nested_end_row = crease.range().end.row;
20293
20294                        if current_level < fold_at_level {
20295                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20296                        } else if current_level == fold_at_level {
20297                            // Fold iff there is no selection completely contained within the fold region
20298                            if !row_ranges_to_keep.iter().any(|selection| {
20299                                selection.end >= nested_start_row
20300                                    && selection.start <= nested_end_row
20301                            }) {
20302                                to_fold.push(crease);
20303                            }
20304                        }
20305
20306                        start_row = nested_end_row + 1;
20307                    }
20308                    None => start_row += 1,
20309                }
20310            }
20311        }
20312
20313        self.fold_creases(to_fold, true, window, cx);
20314    }
20315
20316    pub fn fold_at_level_1(
20317        &mut self,
20318        _: &actions::FoldAtLevel1,
20319        window: &mut Window,
20320        cx: &mut Context<Self>,
20321    ) {
20322        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20323    }
20324
20325    pub fn fold_at_level_2(
20326        &mut self,
20327        _: &actions::FoldAtLevel2,
20328        window: &mut Window,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20332    }
20333
20334    pub fn fold_at_level_3(
20335        &mut self,
20336        _: &actions::FoldAtLevel3,
20337        window: &mut Window,
20338        cx: &mut Context<Self>,
20339    ) {
20340        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20341    }
20342
20343    pub fn fold_at_level_4(
20344        &mut self,
20345        _: &actions::FoldAtLevel4,
20346        window: &mut Window,
20347        cx: &mut Context<Self>,
20348    ) {
20349        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20350    }
20351
20352    pub fn fold_at_level_5(
20353        &mut self,
20354        _: &actions::FoldAtLevel5,
20355        window: &mut Window,
20356        cx: &mut Context<Self>,
20357    ) {
20358        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20359    }
20360
20361    pub fn fold_at_level_6(
20362        &mut self,
20363        _: &actions::FoldAtLevel6,
20364        window: &mut Window,
20365        cx: &mut Context<Self>,
20366    ) {
20367        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20368    }
20369
20370    pub fn fold_at_level_7(
20371        &mut self,
20372        _: &actions::FoldAtLevel7,
20373        window: &mut Window,
20374        cx: &mut Context<Self>,
20375    ) {
20376        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20377    }
20378
20379    pub fn fold_at_level_8(
20380        &mut self,
20381        _: &actions::FoldAtLevel8,
20382        window: &mut Window,
20383        cx: &mut Context<Self>,
20384    ) {
20385        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20386    }
20387
20388    pub fn fold_at_level_9(
20389        &mut self,
20390        _: &actions::FoldAtLevel9,
20391        window: &mut Window,
20392        cx: &mut Context<Self>,
20393    ) {
20394        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20395    }
20396
20397    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20398        if self.buffer.read(cx).is_singleton() {
20399            let mut fold_ranges = Vec::new();
20400            let snapshot = self.buffer.read(cx).snapshot(cx);
20401
20402            for row in 0..snapshot.max_row().0 {
20403                if let Some(foldable_range) = self
20404                    .snapshot(window, cx)
20405                    .crease_for_buffer_row(MultiBufferRow(row))
20406                {
20407                    fold_ranges.push(foldable_range);
20408                }
20409            }
20410
20411            self.fold_creases(fold_ranges, true, window, cx);
20412        } else {
20413            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20414                editor
20415                    .update_in(cx, |editor, _, cx| {
20416                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20417                        for buffer_id in snapshot.all_buffer_ids() {
20418                            editor.fold_buffer(buffer_id, cx);
20419                        }
20420                    })
20421                    .ok();
20422            });
20423        }
20424    }
20425
20426    pub fn fold_function_bodies(
20427        &mut self,
20428        _: &actions::FoldFunctionBodies,
20429        window: &mut Window,
20430        cx: &mut Context<Self>,
20431    ) {
20432        let snapshot = self.buffer.read(cx).snapshot(cx);
20433
20434        let ranges = snapshot
20435            .text_object_ranges(
20436                MultiBufferOffset(0)..snapshot.len(),
20437                TreeSitterOptions::default(),
20438            )
20439            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20440            .collect::<Vec<_>>();
20441
20442        let creases = ranges
20443            .into_iter()
20444            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20445            .collect();
20446
20447        self.fold_creases(creases, true, window, cx);
20448    }
20449
20450    pub fn fold_recursive(
20451        &mut self,
20452        _: &actions::FoldRecursive,
20453        window: &mut Window,
20454        cx: &mut Context<Self>,
20455    ) {
20456        let mut to_fold = Vec::new();
20457        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20458        let selections = self.selections.all_adjusted(&display_map);
20459
20460        for selection in selections {
20461            let range = selection.range().sorted();
20462            let buffer_start_row = range.start.row;
20463
20464            if range.start.row != range.end.row {
20465                let mut found = false;
20466                for row in range.start.row..=range.end.row {
20467                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20468                        found = true;
20469                        to_fold.push(crease);
20470                    }
20471                }
20472                if found {
20473                    continue;
20474                }
20475            }
20476
20477            for row in (0..=range.start.row).rev() {
20478                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20479                    if crease.range().end.row >= buffer_start_row {
20480                        to_fold.push(crease);
20481                    } else {
20482                        break;
20483                    }
20484                }
20485            }
20486        }
20487
20488        self.fold_creases(to_fold, true, window, cx);
20489    }
20490
20491    pub fn fold_at(
20492        &mut self,
20493        buffer_row: MultiBufferRow,
20494        window: &mut Window,
20495        cx: &mut Context<Self>,
20496    ) {
20497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20498
20499        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20500            let autoscroll = self
20501                .selections
20502                .all::<Point>(&display_map)
20503                .iter()
20504                .any(|selection| crease.range().overlaps(&selection.range()));
20505
20506            self.fold_creases(vec![crease], autoscroll, window, cx);
20507        }
20508    }
20509
20510    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20511        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20512            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20513            let buffer = display_map.buffer_snapshot();
20514            let selections = self.selections.all::<Point>(&display_map);
20515            let ranges = selections
20516                .iter()
20517                .map(|s| {
20518                    let range = s.display_range(&display_map).sorted();
20519                    let mut start = range.start.to_point(&display_map);
20520                    let mut end = range.end.to_point(&display_map);
20521                    start.column = 0;
20522                    end.column = buffer.line_len(MultiBufferRow(end.row));
20523                    start..end
20524                })
20525                .collect::<Vec<_>>();
20526
20527            self.unfold_ranges(&ranges, true, true, cx);
20528        } else {
20529            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20530            let buffer_ids = self
20531                .selections
20532                .disjoint_anchor_ranges()
20533                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20534                .collect::<HashSet<_>>();
20535            for buffer_id in buffer_ids {
20536                self.unfold_buffer(buffer_id, cx);
20537            }
20538        }
20539    }
20540
20541    pub fn unfold_recursive(
20542        &mut self,
20543        _: &UnfoldRecursive,
20544        _window: &mut Window,
20545        cx: &mut Context<Self>,
20546    ) {
20547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20548        let selections = self.selections.all::<Point>(&display_map);
20549        let ranges = selections
20550            .iter()
20551            .map(|s| {
20552                let mut range = s.display_range(&display_map).sorted();
20553                *range.start.column_mut() = 0;
20554                *range.end.column_mut() = display_map.line_len(range.end.row());
20555                let start = range.start.to_point(&display_map);
20556                let end = range.end.to_point(&display_map);
20557                start..end
20558            })
20559            .collect::<Vec<_>>();
20560
20561        self.unfold_ranges(&ranges, true, true, cx);
20562    }
20563
20564    pub fn unfold_at(
20565        &mut self,
20566        buffer_row: MultiBufferRow,
20567        _window: &mut Window,
20568        cx: &mut Context<Self>,
20569    ) {
20570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20571
20572        let intersection_range = Point::new(buffer_row.0, 0)
20573            ..Point::new(
20574                buffer_row.0,
20575                display_map.buffer_snapshot().line_len(buffer_row),
20576            );
20577
20578        let autoscroll = self
20579            .selections
20580            .all::<Point>(&display_map)
20581            .iter()
20582            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20583
20584        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20585    }
20586
20587    pub fn unfold_all(
20588        &mut self,
20589        _: &actions::UnfoldAll,
20590        _window: &mut Window,
20591        cx: &mut Context<Self>,
20592    ) {
20593        if self.buffer.read(cx).is_singleton() {
20594            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20595            self.unfold_ranges(
20596                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20597                true,
20598                true,
20599                cx,
20600            );
20601        } else {
20602            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20603                editor
20604                    .update(cx, |editor, cx| {
20605                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20606                        for buffer_id in snapshot.all_buffer_ids() {
20607                            editor.unfold_buffer(buffer_id, cx);
20608                        }
20609                    })
20610                    .ok();
20611            });
20612        }
20613    }
20614
20615    pub fn fold_selected_ranges(
20616        &mut self,
20617        _: &FoldSelectedRanges,
20618        window: &mut Window,
20619        cx: &mut Context<Self>,
20620    ) {
20621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20622        let selections = self.selections.all_adjusted(&display_map);
20623        let ranges = selections
20624            .into_iter()
20625            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20626            .collect::<Vec<_>>();
20627        self.fold_creases(ranges, true, window, cx);
20628    }
20629
20630    pub fn fold_ranges<T: ToOffset + Clone>(
20631        &mut self,
20632        ranges: Vec<Range<T>>,
20633        auto_scroll: bool,
20634        window: &mut Window,
20635        cx: &mut Context<Self>,
20636    ) {
20637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20638        let ranges = ranges
20639            .into_iter()
20640            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20641            .collect::<Vec<_>>();
20642        self.fold_creases(ranges, auto_scroll, window, cx);
20643    }
20644
20645    pub fn fold_creases<T: ToOffset + Clone>(
20646        &mut self,
20647        creases: Vec<Crease<T>>,
20648        auto_scroll: bool,
20649        window: &mut Window,
20650        cx: &mut Context<Self>,
20651    ) {
20652        if creases.is_empty() {
20653            return;
20654        }
20655
20656        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20657
20658        if auto_scroll {
20659            self.request_autoscroll(Autoscroll::fit(), cx);
20660        }
20661
20662        cx.notify();
20663
20664        self.scrollbar_marker_state.dirty = true;
20665        self.update_data_on_scroll(window, cx);
20666        self.folds_did_change(cx);
20667    }
20668
20669    /// Removes any folds whose ranges intersect any of the given ranges.
20670    pub fn unfold_ranges<T: ToOffset + Clone>(
20671        &mut self,
20672        ranges: &[Range<T>],
20673        inclusive: bool,
20674        auto_scroll: bool,
20675        cx: &mut Context<Self>,
20676    ) {
20677        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20678            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20679        });
20680        self.folds_did_change(cx);
20681    }
20682
20683    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20684        self.fold_buffers([buffer_id], cx);
20685    }
20686
20687    pub fn fold_buffers(
20688        &mut self,
20689        buffer_ids: impl IntoIterator<Item = BufferId>,
20690        cx: &mut Context<Self>,
20691    ) {
20692        if self.buffer().read(cx).is_singleton() {
20693            return;
20694        }
20695
20696        let ids_to_fold: Vec<BufferId> = buffer_ids
20697            .into_iter()
20698            .filter(|id| !self.is_buffer_folded(*id, cx))
20699            .collect();
20700
20701        if ids_to_fold.is_empty() {
20702            return;
20703        }
20704
20705        self.display_map.update(cx, |display_map, cx| {
20706            display_map.fold_buffers(ids_to_fold.clone(), cx)
20707        });
20708
20709        let snapshot = self.display_snapshot(cx);
20710        self.selections.change_with(&snapshot, |selections| {
20711            for buffer_id in ids_to_fold.iter().copied() {
20712                selections.remove_selections_from_buffer(buffer_id);
20713            }
20714        });
20715
20716        cx.emit(EditorEvent::BufferFoldToggled {
20717            ids: ids_to_fold,
20718            folded: true,
20719        });
20720        cx.notify();
20721    }
20722
20723    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20724        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20725            return;
20726        }
20727        self.display_map.update(cx, |display_map, cx| {
20728            display_map.unfold_buffers([buffer_id], cx);
20729        });
20730        cx.emit(EditorEvent::BufferFoldToggled {
20731            ids: vec![buffer_id],
20732            folded: false,
20733        });
20734        cx.notify();
20735    }
20736
20737    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20738        self.display_map.read(cx).is_buffer_folded(buffer)
20739    }
20740
20741    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20742        if self.buffer().read(cx).is_singleton() {
20743            return false;
20744        }
20745        !self.folded_buffers(cx).is_empty()
20746    }
20747
20748    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20749        self.display_map.read(cx).folded_buffers()
20750    }
20751
20752    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20753        self.display_map.update(cx, |display_map, cx| {
20754            display_map.disable_header_for_buffer(buffer_id, cx);
20755        });
20756        cx.notify();
20757    }
20758
20759    /// Removes any folds with the given ranges.
20760    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20761        &mut self,
20762        ranges: &[Range<T>],
20763        type_id: TypeId,
20764        auto_scroll: bool,
20765        cx: &mut Context<Self>,
20766    ) {
20767        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20768            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20769        });
20770        self.folds_did_change(cx);
20771    }
20772
20773    fn remove_folds_with<T: ToOffset + Clone>(
20774        &mut self,
20775        ranges: &[Range<T>],
20776        auto_scroll: bool,
20777        cx: &mut Context<Self>,
20778        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20779    ) {
20780        if ranges.is_empty() {
20781            return;
20782        }
20783
20784        self.display_map.update(cx, update);
20785
20786        if auto_scroll {
20787            self.request_autoscroll(Autoscroll::fit(), cx);
20788        }
20789
20790        cx.notify();
20791        self.scrollbar_marker_state.dirty = true;
20792        self.active_indent_guides_state.dirty = true;
20793    }
20794
20795    pub fn update_renderer_widths(
20796        &mut self,
20797        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20798        cx: &mut Context<Self>,
20799    ) -> bool {
20800        self.display_map
20801            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20802    }
20803
20804    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20805        self.display_map.read(cx).fold_placeholder.clone()
20806    }
20807
20808    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20809        self.buffer.update(cx, |buffer, cx| {
20810            buffer.set_all_diff_hunks_expanded(cx);
20811        });
20812    }
20813
20814    pub fn expand_all_diff_hunks(
20815        &mut self,
20816        _: &ExpandAllDiffHunks,
20817        _window: &mut Window,
20818        cx: &mut Context<Self>,
20819    ) {
20820        self.buffer.update(cx, |buffer, cx| {
20821            buffer.expand_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20822        });
20823    }
20824
20825    pub fn collapse_all_diff_hunks(
20826        &mut self,
20827        _: &CollapseAllDiffHunks,
20828        _window: &mut Window,
20829        cx: &mut Context<Self>,
20830    ) {
20831        self.buffer.update(cx, |buffer, cx| {
20832            buffer.collapse_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20833        });
20834    }
20835
20836    pub fn toggle_selected_diff_hunks(
20837        &mut self,
20838        _: &ToggleSelectedDiffHunks,
20839        _window: &mut Window,
20840        cx: &mut Context<Self>,
20841    ) {
20842        let ranges: Vec<_> = self
20843            .selections
20844            .disjoint_anchors()
20845            .iter()
20846            .map(|s| s.range())
20847            .collect();
20848        self.toggle_diff_hunks_in_ranges(ranges, cx);
20849    }
20850
20851    pub fn diff_hunks_in_ranges<'a>(
20852        &'a self,
20853        ranges: &'a [Range<Anchor>],
20854        buffer: &'a MultiBufferSnapshot,
20855    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20856        ranges.iter().flat_map(move |range| {
20857            let end_excerpt = buffer.excerpt_containing(range.end..range.end);
20858            let range = range.to_point(buffer);
20859            let mut peek_end = range.end;
20860            if range.end.row < buffer.max_row().0 {
20861                peek_end = Point::new(range.end.row + 1, 0);
20862            }
20863            buffer
20864                .diff_hunks_in_range(range.start..peek_end)
20865                .filter(move |hunk| {
20866                    if let Some((_, excerpt_range)) = &end_excerpt
20867                        && let Some(end_anchor) =
20868                            buffer.anchor_in_excerpt(excerpt_range.context.end)
20869                        && let Some(hunk_end_anchor) =
20870                            buffer.anchor_in_excerpt(hunk.excerpt_range.context.end)
20871                        && hunk_end_anchor.cmp(&end_anchor, buffer).is_gt()
20872                    {
20873                        false
20874                    } else {
20875                        true
20876                    }
20877                })
20878        })
20879    }
20880
20881    pub fn has_stageable_diff_hunks_in_ranges(
20882        &self,
20883        ranges: &[Range<Anchor>],
20884        snapshot: &MultiBufferSnapshot,
20885    ) -> bool {
20886        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20887        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20888    }
20889
20890    pub fn toggle_staged_selected_diff_hunks(
20891        &mut self,
20892        _: &::git::ToggleStaged,
20893        _: &mut Window,
20894        cx: &mut Context<Self>,
20895    ) {
20896        let snapshot = self.buffer.read(cx).snapshot(cx);
20897        let ranges: Vec<_> = self
20898            .selections
20899            .disjoint_anchors()
20900            .iter()
20901            .map(|s| s.range())
20902            .collect();
20903        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20904        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20905    }
20906
20907    pub fn set_render_diff_hunk_controls(
20908        &mut self,
20909        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20910        cx: &mut Context<Self>,
20911    ) {
20912        self.render_diff_hunk_controls = render_diff_hunk_controls;
20913        cx.notify();
20914    }
20915
20916    pub fn stage_and_next(
20917        &mut self,
20918        _: &::git::StageAndNext,
20919        window: &mut Window,
20920        cx: &mut Context<Self>,
20921    ) {
20922        self.do_stage_or_unstage_and_next(true, window, cx);
20923    }
20924
20925    pub fn unstage_and_next(
20926        &mut self,
20927        _: &::git::UnstageAndNext,
20928        window: &mut Window,
20929        cx: &mut Context<Self>,
20930    ) {
20931        self.do_stage_or_unstage_and_next(false, window, cx);
20932    }
20933
20934    pub fn stage_or_unstage_diff_hunks(
20935        &mut self,
20936        stage: bool,
20937        ranges: Vec<Range<Anchor>>,
20938        cx: &mut Context<Self>,
20939    ) {
20940        if self.delegate_stage_and_restore {
20941            let snapshot = self.buffer.read(cx).snapshot(cx);
20942            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20943            if !hunks.is_empty() {
20944                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20945            }
20946            return;
20947        }
20948        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20949        cx.spawn(async move |this, cx| {
20950            task.await?;
20951            this.update(cx, |this, cx| {
20952                let snapshot = this.buffer.read(cx).snapshot(cx);
20953                let chunk_by = this
20954                    .diff_hunks_in_ranges(&ranges, &snapshot)
20955                    .chunk_by(|hunk| hunk.buffer_id);
20956                for (buffer_id, hunks) in &chunk_by {
20957                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20958                }
20959            })
20960        })
20961        .detach_and_log_err(cx);
20962    }
20963
20964    fn save_buffers_for_ranges_if_needed(
20965        &mut self,
20966        ranges: &[Range<Anchor>],
20967        cx: &mut Context<Editor>,
20968    ) -> Task<Result<()>> {
20969        let multibuffer = self.buffer.read(cx);
20970        let snapshot = multibuffer.read(cx);
20971        let buffer_ids: HashSet<_> = ranges
20972            .iter()
20973            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20974            .collect();
20975        drop(snapshot);
20976
20977        let mut buffers = HashSet::default();
20978        for buffer_id in buffer_ids {
20979            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20980                let buffer = buffer_entity.read(cx);
20981                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20982                {
20983                    buffers.insert(buffer_entity);
20984                }
20985            }
20986        }
20987
20988        if let Some(project) = &self.project {
20989            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20990        } else {
20991            Task::ready(Ok(()))
20992        }
20993    }
20994
20995    fn do_stage_or_unstage_and_next(
20996        &mut self,
20997        stage: bool,
20998        window: &mut Window,
20999        cx: &mut Context<Self>,
21000    ) {
21001        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
21002
21003        if ranges.iter().any(|range| range.start != range.end) {
21004            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21005            return;
21006        }
21007
21008        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21009
21010        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
21011        let wrap_around = !all_diff_hunks_expanded;
21012        let snapshot = self.snapshot(window, cx);
21013        let position = self
21014            .selections
21015            .newest::<Point>(&snapshot.display_snapshot)
21016            .head();
21017
21018        self.go_to_hunk_before_or_after_position(
21019            &snapshot,
21020            position,
21021            Direction::Next,
21022            wrap_around,
21023            window,
21024            cx,
21025        );
21026    }
21027
21028    pub(crate) fn do_stage_or_unstage(
21029        &self,
21030        stage: bool,
21031        buffer_id: BufferId,
21032        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
21033        cx: &mut App,
21034    ) -> Option<()> {
21035        let project = self.project()?;
21036        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
21037        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
21038        let buffer_snapshot = buffer.read(cx).snapshot();
21039        let file_exists = buffer_snapshot
21040            .file()
21041            .is_some_and(|file| file.disk_state().exists());
21042        diff.update(cx, |diff, cx| {
21043            diff.stage_or_unstage_hunks(
21044                stage,
21045                &hunks
21046                    .map(|hunk| buffer_diff::DiffHunk {
21047                        buffer_range: hunk.buffer_range,
21048                        // We don't need to pass in word diffs here because they're only used for rendering and
21049                        // this function changes internal state
21050                        base_word_diffs: Vec::default(),
21051                        buffer_word_diffs: Vec::default(),
21052                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
21053                            ..hunk.diff_base_byte_range.end.0,
21054                        secondary_status: hunk.status.secondary,
21055                        range: Point::zero()..Point::zero(), // unused
21056                    })
21057                    .collect::<Vec<_>>(),
21058                &buffer_snapshot,
21059                file_exists,
21060                cx,
21061            )
21062        });
21063        None
21064    }
21065
21066    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
21067        let ranges: Vec<_> = self
21068            .selections
21069            .disjoint_anchors()
21070            .iter()
21071            .map(|s| s.range())
21072            .collect();
21073        self.buffer
21074            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
21075    }
21076
21077    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
21078        self.buffer.update(cx, |buffer, cx| {
21079            let ranges = vec![Anchor::Min..Anchor::Max];
21080            if !buffer.all_diff_hunks_expanded()
21081                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
21082            {
21083                buffer.collapse_diff_hunks(ranges, cx);
21084                true
21085            } else {
21086                false
21087            }
21088        })
21089    }
21090
21091    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21092        if self.buffer.read(cx).all_diff_hunks_expanded() {
21093            return true;
21094        }
21095        let ranges = vec![Anchor::Min..Anchor::Max];
21096        self.buffer
21097            .read(cx)
21098            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21099    }
21100
21101    fn toggle_diff_hunks_in_ranges(
21102        &mut self,
21103        ranges: Vec<Range<Anchor>>,
21104        cx: &mut Context<Editor>,
21105    ) {
21106        self.buffer.update(cx, |buffer, cx| {
21107            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21108            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21109        })
21110    }
21111
21112    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21113        self.buffer.update(cx, |buffer, cx| {
21114            buffer.toggle_single_diff_hunk(range, cx);
21115        })
21116    }
21117
21118    pub(crate) fn apply_all_diff_hunks(
21119        &mut self,
21120        _: &ApplyAllDiffHunks,
21121        window: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21125
21126        let buffers = self.buffer.read(cx).all_buffers();
21127        for branch_buffer in buffers {
21128            branch_buffer.update(cx, |branch_buffer, cx| {
21129                branch_buffer.merge_into_base(Vec::new(), cx);
21130            });
21131        }
21132
21133        if let Some(project) = self.project.clone() {
21134            self.save(
21135                SaveOptions {
21136                    format: true,
21137                    autosave: false,
21138                },
21139                project,
21140                window,
21141                cx,
21142            )
21143            .detach_and_log_err(cx);
21144        }
21145    }
21146
21147    pub(crate) fn apply_selected_diff_hunks(
21148        &mut self,
21149        _: &ApplyDiffHunk,
21150        window: &mut Window,
21151        cx: &mut Context<Self>,
21152    ) {
21153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21154        let snapshot = self.snapshot(window, cx);
21155        let hunks = snapshot.hunks_for_ranges(
21156            self.selections
21157                .all(&snapshot.display_snapshot)
21158                .into_iter()
21159                .map(|selection| selection.range()),
21160        );
21161        let mut ranges_by_buffer = HashMap::default();
21162        self.transact(window, cx, |editor, _window, cx| {
21163            for hunk in hunks {
21164                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21165                    ranges_by_buffer
21166                        .entry(buffer.clone())
21167                        .or_insert_with(Vec::new)
21168                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21169                }
21170            }
21171
21172            for (buffer, ranges) in ranges_by_buffer {
21173                buffer.update(cx, |buffer, cx| {
21174                    buffer.merge_into_base(ranges, cx);
21175                });
21176            }
21177        });
21178
21179        if let Some(project) = self.project.clone() {
21180            self.save(
21181                SaveOptions {
21182                    format: true,
21183                    autosave: false,
21184                },
21185                project,
21186                window,
21187                cx,
21188            )
21189            .detach_and_log_err(cx);
21190        }
21191    }
21192
21193    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21194        if hovered != self.gutter_hovered {
21195            self.gutter_hovered = hovered;
21196            cx.notify();
21197        }
21198    }
21199
21200    pub fn insert_blocks(
21201        &mut self,
21202        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21203        autoscroll: Option<Autoscroll>,
21204        cx: &mut Context<Self>,
21205    ) -> Vec<CustomBlockId> {
21206        let blocks = self
21207            .display_map
21208            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21209        if let Some(autoscroll) = autoscroll {
21210            self.request_autoscroll(autoscroll, cx);
21211        }
21212        cx.notify();
21213        blocks
21214    }
21215
21216    pub fn resize_blocks(
21217        &mut self,
21218        heights: HashMap<CustomBlockId, u32>,
21219        autoscroll: Option<Autoscroll>,
21220        cx: &mut Context<Self>,
21221    ) {
21222        self.display_map
21223            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21224        if let Some(autoscroll) = autoscroll {
21225            self.request_autoscroll(autoscroll, cx);
21226        }
21227        cx.notify();
21228    }
21229
21230    pub fn replace_blocks(
21231        &mut self,
21232        renderers: HashMap<CustomBlockId, RenderBlock>,
21233        autoscroll: Option<Autoscroll>,
21234        cx: &mut Context<Self>,
21235    ) {
21236        self.display_map
21237            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21238        if let Some(autoscroll) = autoscroll {
21239            self.request_autoscroll(autoscroll, cx);
21240        }
21241        cx.notify();
21242    }
21243
21244    pub fn remove_blocks(
21245        &mut self,
21246        block_ids: HashSet<CustomBlockId>,
21247        autoscroll: Option<Autoscroll>,
21248        cx: &mut Context<Self>,
21249    ) {
21250        self.display_map.update(cx, |display_map, cx| {
21251            display_map.remove_blocks(block_ids, cx)
21252        });
21253        if let Some(autoscroll) = autoscroll {
21254            self.request_autoscroll(autoscroll, cx);
21255        }
21256        cx.notify();
21257    }
21258
21259    pub fn row_for_block(
21260        &self,
21261        block_id: CustomBlockId,
21262        cx: &mut Context<Self>,
21263    ) -> Option<DisplayRow> {
21264        self.display_map
21265            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21266    }
21267
21268    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21269        self.focused_block = Some(focused_block);
21270    }
21271
21272    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21273        self.focused_block.take()
21274    }
21275
21276    pub fn insert_creases(
21277        &mut self,
21278        creases: impl IntoIterator<Item = Crease<Anchor>>,
21279        cx: &mut Context<Self>,
21280    ) -> Vec<CreaseId> {
21281        self.display_map
21282            .update(cx, |map, cx| map.insert_creases(creases, cx))
21283    }
21284
21285    pub fn remove_creases(
21286        &mut self,
21287        ids: impl IntoIterator<Item = CreaseId>,
21288        cx: &mut Context<Self>,
21289    ) -> Vec<(CreaseId, Range<Anchor>)> {
21290        self.display_map
21291            .update(cx, |map, cx| map.remove_creases(ids, cx))
21292    }
21293
21294    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21295        self.display_map
21296            .update(cx, |map, cx| map.snapshot(cx))
21297            .longest_row()
21298    }
21299
21300    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21301        self.display_map
21302            .update(cx, |map, cx| map.snapshot(cx))
21303            .max_point()
21304    }
21305
21306    pub fn text(&self, cx: &App) -> String {
21307        self.buffer.read(cx).read(cx).text()
21308    }
21309
21310    pub fn is_empty(&self, cx: &App) -> bool {
21311        self.buffer.read(cx).read(cx).is_empty()
21312    }
21313
21314    pub fn text_option(&self, cx: &App) -> Option<String> {
21315        let text = self.text(cx);
21316        let text = text.trim();
21317
21318        if text.is_empty() {
21319            return None;
21320        }
21321
21322        Some(text.to_string())
21323    }
21324
21325    pub fn set_text(
21326        &mut self,
21327        text: impl Into<Arc<str>>,
21328        window: &mut Window,
21329        cx: &mut Context<Self>,
21330    ) {
21331        self.transact(window, cx, |this, _, cx| {
21332            this.buffer
21333                .read(cx)
21334                .as_singleton()
21335                .expect("you can only call set_text on editors for singleton buffers")
21336                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21337        });
21338    }
21339
21340    pub fn display_text(&self, cx: &mut App) -> String {
21341        self.display_map
21342            .update(cx, |map, cx| map.snapshot(cx))
21343            .text()
21344    }
21345
21346    fn create_minimap(
21347        &self,
21348        minimap_settings: MinimapSettings,
21349        window: &mut Window,
21350        cx: &mut Context<Self>,
21351    ) -> Option<Entity<Self>> {
21352        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21353            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21354    }
21355
21356    fn initialize_new_minimap(
21357        &self,
21358        minimap_settings: MinimapSettings,
21359        window: &mut Window,
21360        cx: &mut Context<Self>,
21361    ) -> Entity<Self> {
21362        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21363        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21364
21365        let mut minimap = Editor::new_internal(
21366            EditorMode::Minimap {
21367                parent: cx.weak_entity(),
21368            },
21369            self.buffer.clone(),
21370            None,
21371            Some(self.display_map.clone()),
21372            window,
21373            cx,
21374        );
21375        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21376        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21377        minimap.scroll_manager.clone_state(
21378            &self.scroll_manager,
21379            &my_snapshot,
21380            &minimap_snapshot,
21381            cx,
21382        );
21383        minimap.set_text_style_refinement(TextStyleRefinement {
21384            font_size: Some(MINIMAP_FONT_SIZE),
21385            font_weight: Some(MINIMAP_FONT_WEIGHT),
21386            font_family: Some(MINIMAP_FONT_FAMILY),
21387            ..Default::default()
21388        });
21389        minimap.update_minimap_configuration(minimap_settings, cx);
21390        cx.new(|_| minimap)
21391    }
21392
21393    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21394        let current_line_highlight = minimap_settings
21395            .current_line_highlight
21396            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21397        self.set_current_line_highlight(Some(current_line_highlight));
21398    }
21399
21400    pub fn minimap(&self) -> Option<&Entity<Self>> {
21401        self.minimap
21402            .as_ref()
21403            .filter(|_| self.minimap_visibility.visible())
21404    }
21405
21406    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21407        let mut wrap_guides = smallvec![];
21408
21409        if self.show_wrap_guides == Some(false) {
21410            return wrap_guides;
21411        }
21412
21413        let settings = self.buffer.read(cx).language_settings(cx);
21414        if settings.show_wrap_guides {
21415            match self.soft_wrap_mode(cx) {
21416                SoftWrap::Column(soft_wrap) => {
21417                    wrap_guides.push((soft_wrap as usize, true));
21418                }
21419                SoftWrap::Bounded(soft_wrap) => {
21420                    wrap_guides.push((soft_wrap as usize, true));
21421                }
21422                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21423            }
21424            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21425        }
21426
21427        wrap_guides
21428    }
21429
21430    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21431        let settings = self.buffer.read(cx).language_settings(cx);
21432        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21433        match mode {
21434            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21435                SoftWrap::None
21436            }
21437            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21438            language_settings::SoftWrap::PreferredLineLength => {
21439                SoftWrap::Column(settings.preferred_line_length)
21440            }
21441            language_settings::SoftWrap::Bounded => {
21442                SoftWrap::Bounded(settings.preferred_line_length)
21443            }
21444        }
21445    }
21446
21447    pub fn set_soft_wrap_mode(
21448        &mut self,
21449        mode: language_settings::SoftWrap,
21450        cx: &mut Context<Self>,
21451    ) {
21452        self.soft_wrap_mode_override = Some(mode);
21453        cx.notify();
21454    }
21455
21456    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21457        self.hard_wrap = hard_wrap;
21458        cx.notify();
21459    }
21460
21461    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21462        self.text_style_refinement = Some(style);
21463    }
21464
21465    /// called by the Element so we know what style we were most recently rendered with.
21466    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21467        // We intentionally do not inform the display map about the minimap style
21468        // so that wrapping is not recalculated and stays consistent for the editor
21469        // and its linked minimap.
21470        if !self.mode.is_minimap() {
21471            let font = style.text.font();
21472            let font_size = style.text.font_size.to_pixels(window.rem_size());
21473            let display_map = self
21474                .placeholder_display_map
21475                .as_ref()
21476                .filter(|_| self.is_empty(cx))
21477                .unwrap_or(&self.display_map);
21478
21479            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21480        }
21481        self.style = Some(style);
21482    }
21483
21484    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21485        if self.style.is_none() {
21486            self.style = Some(self.create_style(cx));
21487        }
21488        self.style.as_ref().unwrap()
21489    }
21490
21491    // Called by the element. This method is not designed to be called outside of the editor
21492    // element's layout code because it does not notify when rewrapping is computed synchronously.
21493    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21494        if self.is_empty(cx) {
21495            self.placeholder_display_map
21496                .as_ref()
21497                .map_or(false, |display_map| {
21498                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21499                })
21500        } else {
21501            self.display_map
21502                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21503        }
21504    }
21505
21506    pub fn set_soft_wrap(&mut self) {
21507        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21508    }
21509
21510    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21511        if self.soft_wrap_mode_override.is_some() {
21512            self.soft_wrap_mode_override.take();
21513        } else {
21514            let soft_wrap = match self.soft_wrap_mode(cx) {
21515                SoftWrap::GitDiff => return,
21516                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21517                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21518                    language_settings::SoftWrap::None
21519                }
21520            };
21521            self.soft_wrap_mode_override = Some(soft_wrap);
21522        }
21523        cx.notify();
21524    }
21525
21526    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21527        let Some(workspace) = self.workspace() else {
21528            return;
21529        };
21530        let fs = workspace.read(cx).app_state().fs.clone();
21531        let current_show = TabBarSettings::get_global(cx).show;
21532        update_settings_file(fs, cx, move |setting, _| {
21533            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21534        });
21535    }
21536
21537    pub fn toggle_indent_guides(
21538        &mut self,
21539        _: &ToggleIndentGuides,
21540        _: &mut Window,
21541        cx: &mut Context<Self>,
21542    ) {
21543        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21544            self.buffer
21545                .read(cx)
21546                .language_settings(cx)
21547                .indent_guides
21548                .enabled
21549        });
21550        self.show_indent_guides = Some(!currently_enabled);
21551        cx.notify();
21552    }
21553
21554    fn should_show_indent_guides(&self) -> Option<bool> {
21555        self.show_indent_guides
21556    }
21557
21558    pub fn disable_indent_guides_for_buffer(
21559        &mut self,
21560        buffer_id: BufferId,
21561        cx: &mut Context<Self>,
21562    ) {
21563        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21564        cx.notify();
21565    }
21566
21567    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21568        self.buffers_with_disabled_indent_guides
21569            .contains(&buffer_id)
21570    }
21571
21572    pub fn toggle_line_numbers(
21573        &mut self,
21574        _: &ToggleLineNumbers,
21575        _: &mut Window,
21576        cx: &mut Context<Self>,
21577    ) {
21578        let mut editor_settings = EditorSettings::get_global(cx).clone();
21579        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21580        EditorSettings::override_global(editor_settings, cx);
21581    }
21582
21583    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21584        if let Some(show_line_numbers) = self.show_line_numbers {
21585            return show_line_numbers;
21586        }
21587        EditorSettings::get_global(cx).gutter.line_numbers
21588    }
21589
21590    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21591        match (
21592            self.use_relative_line_numbers,
21593            EditorSettings::get_global(cx).relative_line_numbers,
21594        ) {
21595            (None, setting) => setting,
21596            (Some(false), _) => RelativeLineNumbers::Disabled,
21597            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21598            (Some(true), _) => RelativeLineNumbers::Enabled,
21599        }
21600    }
21601
21602    pub fn toggle_relative_line_numbers(
21603        &mut self,
21604        _: &ToggleRelativeLineNumbers,
21605        _: &mut Window,
21606        cx: &mut Context<Self>,
21607    ) {
21608        let is_relative = self.relative_line_numbers(cx);
21609        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21610    }
21611
21612    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21613        self.use_relative_line_numbers = is_relative;
21614        cx.notify();
21615    }
21616
21617    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21618        self.show_gutter = show_gutter;
21619        cx.notify();
21620    }
21621
21622    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21623        self.show_scrollbars = ScrollbarAxes {
21624            horizontal: show,
21625            vertical: show,
21626        };
21627        cx.notify();
21628    }
21629
21630    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21631        self.show_scrollbars.vertical = show;
21632        cx.notify();
21633    }
21634
21635    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21636        self.show_scrollbars.horizontal = show;
21637        cx.notify();
21638    }
21639
21640    pub fn set_minimap_visibility(
21641        &mut self,
21642        minimap_visibility: MinimapVisibility,
21643        window: &mut Window,
21644        cx: &mut Context<Self>,
21645    ) {
21646        if self.minimap_visibility != minimap_visibility {
21647            if minimap_visibility.visible() && self.minimap.is_none() {
21648                let minimap_settings = EditorSettings::get_global(cx).minimap;
21649                self.minimap =
21650                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21651            }
21652            self.minimap_visibility = minimap_visibility;
21653            cx.notify();
21654        }
21655    }
21656
21657    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21658        self.set_show_scrollbars(false, cx);
21659        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21660    }
21661
21662    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21663        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21664    }
21665
21666    /// Normally the text in full mode and auto height editors is padded on the
21667    /// left side by roughly half a character width for improved hit testing.
21668    ///
21669    /// Use this method to disable this for cases where this is not wanted (e.g.
21670    /// if you want to align the editor text with some other text above or below)
21671    /// or if you want to add this padding to single-line editors.
21672    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21673        self.offset_content = offset_content;
21674        cx.notify();
21675    }
21676
21677    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21678        self.show_line_numbers = Some(show_line_numbers);
21679        cx.notify();
21680    }
21681
21682    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21683        self.disable_expand_excerpt_buttons = true;
21684        cx.notify();
21685    }
21686
21687    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21688        self.number_deleted_lines = number;
21689        cx.notify();
21690    }
21691
21692    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21693        self.delegate_expand_excerpts = delegate;
21694    }
21695
21696    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21697        self.delegate_stage_and_restore = delegate;
21698    }
21699
21700    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21701        self.delegate_open_excerpts = delegate;
21702    }
21703
21704    pub fn set_on_local_selections_changed(
21705        &mut self,
21706        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21707    ) {
21708        self.on_local_selections_changed = callback;
21709    }
21710
21711    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21712        self.suppress_selection_callback = suppress;
21713    }
21714
21715    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21716        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21717        cx.notify();
21718    }
21719
21720    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21721        self.show_code_actions = Some(show_code_actions);
21722        cx.notify();
21723    }
21724
21725    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21726        self.show_runnables = Some(show_runnables);
21727        cx.notify();
21728    }
21729
21730    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21731        self.show_breakpoints = Some(show_breakpoints);
21732        cx.notify();
21733    }
21734
21735    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21736        self.show_diff_review_button = show;
21737        cx.notify();
21738    }
21739
21740    pub fn show_diff_review_button(&self) -> bool {
21741        self.show_diff_review_button
21742    }
21743
21744    pub fn render_diff_review_button(
21745        &self,
21746        display_row: DisplayRow,
21747        width: Pixels,
21748        cx: &mut Context<Self>,
21749    ) -> impl IntoElement {
21750        let text_color = cx.theme().colors().text;
21751        let icon_color = cx.theme().colors().icon_accent;
21752
21753        h_flex()
21754            .id("diff_review_button")
21755            .cursor_pointer()
21756            .w(width - px(1.))
21757            .h(relative(0.9))
21758            .justify_center()
21759            .rounded_sm()
21760            .border_1()
21761            .border_color(text_color.opacity(0.1))
21762            .bg(text_color.opacity(0.15))
21763            .hover(|s| {
21764                s.bg(icon_color.opacity(0.4))
21765                    .border_color(icon_color.opacity(0.5))
21766            })
21767            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21768            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21769            .on_mouse_down(
21770                gpui::MouseButton::Left,
21771                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21772                    editor.start_diff_review_drag(display_row, window, cx);
21773                }),
21774            )
21775    }
21776
21777    pub fn start_diff_review_drag(
21778        &mut self,
21779        display_row: DisplayRow,
21780        window: &mut Window,
21781        cx: &mut Context<Self>,
21782    ) {
21783        let snapshot = self.snapshot(window, cx);
21784        let point = snapshot
21785            .display_snapshot
21786            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21787        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21788        self.diff_review_drag_state = Some(DiffReviewDragState {
21789            start_anchor: anchor,
21790            current_anchor: anchor,
21791        });
21792        cx.notify();
21793    }
21794
21795    pub fn update_diff_review_drag(
21796        &mut self,
21797        display_row: DisplayRow,
21798        window: &mut Window,
21799        cx: &mut Context<Self>,
21800    ) {
21801        if self.diff_review_drag_state.is_none() {
21802            return;
21803        }
21804        let snapshot = self.snapshot(window, cx);
21805        let point = snapshot
21806            .display_snapshot
21807            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21808        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21809        if let Some(drag_state) = &mut self.diff_review_drag_state {
21810            drag_state.current_anchor = anchor;
21811            cx.notify();
21812        }
21813    }
21814
21815    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21816        if let Some(drag_state) = self.diff_review_drag_state.take() {
21817            let snapshot = self.snapshot(window, cx);
21818            let range = drag_state.row_range(&snapshot.display_snapshot);
21819            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21820        }
21821        cx.notify();
21822    }
21823
21824    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21825        self.diff_review_drag_state = None;
21826        cx.notify();
21827    }
21828
21829    /// Calculates the appropriate block height for the diff review overlay.
21830    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21831    /// and 2 lines per comment when expanded.
21832    fn calculate_overlay_height(
21833        &self,
21834        hunk_key: &DiffHunkKey,
21835        comments_expanded: bool,
21836        snapshot: &MultiBufferSnapshot,
21837    ) -> u32 {
21838        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21839        let base_height: u32 = 2; // Input row with avatar and buttons
21840
21841        if comment_count == 0 {
21842            base_height
21843        } else if comments_expanded {
21844            // Header (1 line) + 2 lines per comment
21845            base_height + 1 + (comment_count as u32 * 2)
21846        } else {
21847            // Just header when collapsed
21848            base_height + 1
21849        }
21850    }
21851
21852    pub fn show_diff_review_overlay(
21853        &mut self,
21854        display_range: Range<DisplayRow>,
21855        window: &mut Window,
21856        cx: &mut Context<Self>,
21857    ) {
21858        let Range { start, end } = display_range.sorted();
21859
21860        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21861        let editor_snapshot = self.snapshot(window, cx);
21862
21863        // Convert display rows to multibuffer points
21864        let start_point = editor_snapshot
21865            .display_snapshot
21866            .display_point_to_point(start.as_display_point(), Bias::Left);
21867        let end_point = editor_snapshot
21868            .display_snapshot
21869            .display_point_to_point(end.as_display_point(), Bias::Left);
21870        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21871
21872        // Create anchor range for the selected lines (start of first line to end of last line)
21873        let line_end = Point::new(
21874            end_point.row,
21875            buffer_snapshot.line_len(end_multi_buffer_row),
21876        );
21877        let anchor_range =
21878            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21879
21880        // Compute the hunk key for this display row
21881        let file_path = buffer_snapshot
21882            .file_at(start_point)
21883            .map(|file: &Arc<dyn language::File>| file.path().clone())
21884            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21885        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21886        let new_hunk_key = DiffHunkKey {
21887            file_path,
21888            hunk_start_anchor,
21889        };
21890
21891        // Check if we already have an overlay for this hunk
21892        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21893            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21894        }) {
21895            // Just focus the existing overlay's prompt editor
21896            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21897            window.focus(&focus_handle, cx);
21898            return;
21899        }
21900
21901        // Dismiss overlays that have no comments for their hunks
21902        self.dismiss_overlays_without_comments(cx);
21903
21904        // Get the current user's avatar URI from the project's user_store
21905        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21906            let user_store = project.read(cx).user_store();
21907            user_store
21908                .read(cx)
21909                .current_user()
21910                .map(|user| user.avatar_uri.clone())
21911        });
21912
21913        // Create anchor at the end of the last row so the block appears immediately below it
21914        // Use multibuffer coordinates for anchor creation
21915        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21916        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21917
21918        // Use the hunk key we already computed
21919        let hunk_key = new_hunk_key;
21920
21921        // Create the prompt editor for the review input
21922        let prompt_editor = cx.new(|cx| {
21923            let mut editor = Editor::single_line(window, cx);
21924            editor.set_placeholder_text("Add a review comment...", window, cx);
21925            editor
21926        });
21927
21928        // Register the Newline action on the prompt editor to submit the review
21929        let parent_editor = cx.entity().downgrade();
21930        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21931            prompt_editor.register_action({
21932                let parent_editor = parent_editor.clone();
21933                move |_: &crate::actions::Newline, window, cx| {
21934                    if let Some(editor) = parent_editor.upgrade() {
21935                        editor.update(cx, |editor, cx| {
21936                            editor.submit_diff_review_comment(window, cx);
21937                        });
21938                    }
21939                }
21940            })
21941        });
21942
21943        // Calculate initial height based on existing comments for this hunk
21944        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21945
21946        // Create the overlay block
21947        let prompt_editor_for_render = prompt_editor.clone();
21948        let hunk_key_for_render = hunk_key.clone();
21949        let editor_handle = cx.entity().downgrade();
21950        let block = BlockProperties {
21951            style: BlockStyle::Sticky,
21952            placement: BlockPlacement::Below(anchor),
21953            height: Some(initial_height),
21954            render: Arc::new(move |cx| {
21955                Self::render_diff_review_overlay(
21956                    &prompt_editor_for_render,
21957                    &hunk_key_for_render,
21958                    &editor_handle,
21959                    cx,
21960                )
21961            }),
21962            priority: 0,
21963        };
21964
21965        let block_ids = self.insert_blocks([block], None, cx);
21966        let Some(block_id) = block_ids.into_iter().next() else {
21967            log::error!("Failed to insert diff review overlay block");
21968            return;
21969        };
21970
21971        self.diff_review_overlays.push(DiffReviewOverlay {
21972            anchor_range,
21973            block_id,
21974            prompt_editor: prompt_editor.clone(),
21975            hunk_key,
21976            comments_expanded: true,
21977            inline_edit_editors: HashMap::default(),
21978            inline_edit_subscriptions: HashMap::default(),
21979            user_avatar_uri,
21980            _subscription: subscription,
21981        });
21982
21983        // Focus the prompt editor
21984        let focus_handle = prompt_editor.focus_handle(cx);
21985        window.focus(&focus_handle, cx);
21986
21987        cx.notify();
21988    }
21989
21990    /// Dismisses all diff review overlays.
21991    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21992        if self.diff_review_overlays.is_empty() {
21993            return;
21994        }
21995        let block_ids: HashSet<_> = self
21996            .diff_review_overlays
21997            .drain(..)
21998            .map(|overlay| overlay.block_id)
21999            .collect();
22000        self.remove_blocks(block_ids, None, cx);
22001        cx.notify();
22002    }
22003
22004    /// Dismisses overlays that have no comments stored for their hunks.
22005    /// Keeps overlays that have at least one comment.
22006    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
22007        let snapshot = self.buffer.read(cx).snapshot(cx);
22008
22009        // First, compute which overlays have comments (to avoid borrow issues with retain)
22010        let overlays_with_comments: Vec<bool> = self
22011            .diff_review_overlays
22012            .iter()
22013            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
22014            .collect();
22015
22016        // Now collect block IDs to remove and retain overlays
22017        let mut block_ids_to_remove = HashSet::default();
22018        let mut index = 0;
22019        self.diff_review_overlays.retain(|overlay| {
22020            let has_comments = overlays_with_comments[index];
22021            index += 1;
22022            if !has_comments {
22023                block_ids_to_remove.insert(overlay.block_id);
22024            }
22025            has_comments
22026        });
22027
22028        if !block_ids_to_remove.is_empty() {
22029            self.remove_blocks(block_ids_to_remove, None, cx);
22030            cx.notify();
22031        }
22032    }
22033
22034    /// Refreshes the diff review overlay block to update its height and render function.
22035    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
22036    fn refresh_diff_review_overlay_height(
22037        &mut self,
22038        hunk_key: &DiffHunkKey,
22039        _window: &mut Window,
22040        cx: &mut Context<Self>,
22041    ) {
22042        // Extract all needed data from overlay first to avoid borrow conflicts
22043        let snapshot = self.buffer.read(cx).snapshot(cx);
22044        let (comments_expanded, block_id, prompt_editor) = {
22045            let Some(overlay) = self
22046                .diff_review_overlays
22047                .iter()
22048                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22049            else {
22050                return;
22051            };
22052
22053            (
22054                overlay.comments_expanded,
22055                overlay.block_id,
22056                overlay.prompt_editor.clone(),
22057            )
22058        };
22059
22060        // Calculate new height
22061        let snapshot = self.buffer.read(cx).snapshot(cx);
22062        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
22063
22064        // Update the block height using resize_blocks (avoids flicker)
22065        let mut heights = HashMap::default();
22066        heights.insert(block_id, new_height);
22067        self.resize_blocks(heights, None, cx);
22068
22069        // Update the render function using replace_blocks (avoids flicker)
22070        let hunk_key_for_render = hunk_key.clone();
22071        let editor_handle = cx.entity().downgrade();
22072        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
22073            Arc::new(move |cx| {
22074                Self::render_diff_review_overlay(
22075                    &prompt_editor,
22076                    &hunk_key_for_render,
22077                    &editor_handle,
22078                    cx,
22079                )
22080            });
22081
22082        let mut renderers = HashMap::default();
22083        renderers.insert(block_id, render);
22084        self.replace_blocks(renderers, None, cx);
22085    }
22086
22087    /// Action handler for SubmitDiffReviewComment.
22088    pub fn submit_diff_review_comment_action(
22089        &mut self,
22090        _: &SubmitDiffReviewComment,
22091        window: &mut Window,
22092        cx: &mut Context<Self>,
22093    ) {
22094        self.submit_diff_review_comment(window, cx);
22095    }
22096
22097    /// Stores the diff review comment locally.
22098    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22099    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22100        // Find the overlay that currently has focus
22101        let overlay_index = self
22102            .diff_review_overlays
22103            .iter()
22104            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22105        let Some(overlay_index) = overlay_index else {
22106            return;
22107        };
22108        let overlay = &self.diff_review_overlays[overlay_index];
22109
22110        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22111        if comment_text.is_empty() {
22112            return;
22113        }
22114
22115        let anchor_range = overlay.anchor_range.clone();
22116        let hunk_key = overlay.hunk_key.clone();
22117
22118        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22119
22120        // Clear the prompt editor but keep the overlay open
22121        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22122            overlay.prompt_editor.update(cx, |editor, cx| {
22123                editor.clear(window, cx);
22124            });
22125        }
22126
22127        // Refresh the overlay to update the block height for the new comment
22128        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22129
22130        cx.notify();
22131    }
22132
22133    /// Returns the prompt editor for the diff review overlay, if one is active.
22134    /// This is primarily used for testing.
22135    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22136        self.diff_review_overlays
22137            .first()
22138            .map(|overlay| &overlay.prompt_editor)
22139    }
22140
22141    /// Returns the line range for the first diff review overlay, if one is active.
22142    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22143    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22144        let overlay = self.diff_review_overlays.first()?;
22145        let snapshot = self.buffer.read(cx).snapshot(cx);
22146        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22147        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22148        let start_row = snapshot
22149            .point_to_buffer_point(start_point)
22150            .map(|(_, p)| p.row)
22151            .unwrap_or(start_point.row);
22152        let end_row = snapshot
22153            .point_to_buffer_point(end_point)
22154            .map(|(_, p)| p.row)
22155            .unwrap_or(end_point.row);
22156        Some((start_row, end_row))
22157    }
22158
22159    /// Sets whether the comments section is expanded in the diff review overlay.
22160    /// This is primarily used for testing.
22161    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22162        for overlay in &mut self.diff_review_overlays {
22163            overlay.comments_expanded = expanded;
22164        }
22165        cx.notify();
22166    }
22167
22168    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22169    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22170        a.file_path == b.file_path
22171            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22172    }
22173
22174    /// Returns comments for a specific hunk, ordered by creation time.
22175    pub fn comments_for_hunk<'a>(
22176        &'a self,
22177        key: &DiffHunkKey,
22178        snapshot: &MultiBufferSnapshot,
22179    ) -> &'a [StoredReviewComment] {
22180        let key_point = key.hunk_start_anchor.to_point(snapshot);
22181        self.stored_review_comments
22182            .iter()
22183            .find(|(k, _)| {
22184                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22185            })
22186            .map(|(_, comments)| comments.as_slice())
22187            .unwrap_or(&[])
22188    }
22189
22190    /// Returns the total count of stored review comments across all hunks.
22191    pub fn total_review_comment_count(&self) -> usize {
22192        self.stored_review_comments
22193            .iter()
22194            .map(|(_, v)| v.len())
22195            .sum()
22196    }
22197
22198    /// Returns the count of comments for a specific hunk.
22199    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22200        let key_point = key.hunk_start_anchor.to_point(snapshot);
22201        self.stored_review_comments
22202            .iter()
22203            .find(|(k, _)| {
22204                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22205            })
22206            .map(|(_, v)| v.len())
22207            .unwrap_or(0)
22208    }
22209
22210    /// Adds a new review comment to a specific hunk.
22211    pub fn add_review_comment(
22212        &mut self,
22213        hunk_key: DiffHunkKey,
22214        comment: String,
22215        anchor_range: Range<Anchor>,
22216        cx: &mut Context<Self>,
22217    ) -> usize {
22218        let id = self.next_review_comment_id;
22219        self.next_review_comment_id += 1;
22220
22221        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22222
22223        let snapshot = self.buffer.read(cx).snapshot(cx);
22224        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22225
22226        // Find existing entry for this hunk or add a new one
22227        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22228            k.file_path == hunk_key.file_path
22229                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22230        }) {
22231            comments.push(stored_comment);
22232        } else {
22233            self.stored_review_comments
22234                .push((hunk_key, vec![stored_comment]));
22235        }
22236
22237        cx.emit(EditorEvent::ReviewCommentsChanged {
22238            total_count: self.total_review_comment_count(),
22239        });
22240        cx.notify();
22241        id
22242    }
22243
22244    /// Removes a review comment by ID from any hunk.
22245    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22246        for (_, comments) in self.stored_review_comments.iter_mut() {
22247            if let Some(index) = comments.iter().position(|c| c.id == id) {
22248                comments.remove(index);
22249                cx.emit(EditorEvent::ReviewCommentsChanged {
22250                    total_count: self.total_review_comment_count(),
22251                });
22252                cx.notify();
22253                return true;
22254            }
22255        }
22256        false
22257    }
22258
22259    /// Updates a review comment's text by ID.
22260    pub fn update_review_comment(
22261        &mut self,
22262        id: usize,
22263        new_comment: String,
22264        cx: &mut Context<Self>,
22265    ) -> bool {
22266        for (_, comments) in self.stored_review_comments.iter_mut() {
22267            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22268                comment.comment = new_comment;
22269                comment.is_editing = false;
22270                cx.emit(EditorEvent::ReviewCommentsChanged {
22271                    total_count: self.total_review_comment_count(),
22272                });
22273                cx.notify();
22274                return true;
22275            }
22276        }
22277        false
22278    }
22279
22280    /// Sets a comment's editing state.
22281    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22282        for (_, comments) in self.stored_review_comments.iter_mut() {
22283            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22284                comment.is_editing = is_editing;
22285                cx.notify();
22286                return;
22287            }
22288        }
22289    }
22290
22291    /// Takes all stored comments from all hunks, clearing the storage.
22292    /// Returns a Vec of (hunk_key, comments) pairs.
22293    pub fn take_all_review_comments(
22294        &mut self,
22295        cx: &mut Context<Self>,
22296    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22297        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22298        self.dismiss_all_diff_review_overlays(cx);
22299        let comments = std::mem::take(&mut self.stored_review_comments);
22300        // Reset the ID counter since all comments have been taken
22301        self.next_review_comment_id = 0;
22302        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22303        cx.notify();
22304        comments
22305    }
22306
22307    /// Removes review comments whose anchors are no longer valid or whose
22308    /// associated diff hunks no longer exist.
22309    ///
22310    /// This should be called when the buffer changes to prevent orphaned comments
22311    /// from accumulating.
22312    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22313        let snapshot = self.buffer.read(cx).snapshot(cx);
22314        let original_count = self.total_review_comment_count();
22315
22316        // Remove comments with invalid hunk anchors
22317        self.stored_review_comments
22318            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22319
22320        // Also clean up individual comments with invalid anchor ranges
22321        for (_, comments) in &mut self.stored_review_comments {
22322            comments.retain(|comment| {
22323                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22324            });
22325        }
22326
22327        // Remove empty hunk entries
22328        self.stored_review_comments
22329            .retain(|(_, comments)| !comments.is_empty());
22330
22331        let new_count = self.total_review_comment_count();
22332        if new_count != original_count {
22333            cx.emit(EditorEvent::ReviewCommentsChanged {
22334                total_count: new_count,
22335            });
22336            cx.notify();
22337        }
22338    }
22339
22340    /// Toggles the expanded state of the comments section in the overlay.
22341    pub fn toggle_review_comments_expanded(
22342        &mut self,
22343        _: &ToggleReviewCommentsExpanded,
22344        window: &mut Window,
22345        cx: &mut Context<Self>,
22346    ) {
22347        // Find the overlay that currently has focus, or use the first one
22348        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22349            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22350                overlay.comments_expanded = !overlay.comments_expanded;
22351                Some(overlay.hunk_key.clone())
22352            } else {
22353                None
22354            }
22355        });
22356
22357        // If no focused overlay found, toggle the first one
22358        let hunk_key = overlay_info.or_else(|| {
22359            self.diff_review_overlays.first_mut().map(|overlay| {
22360                overlay.comments_expanded = !overlay.comments_expanded;
22361                overlay.hunk_key.clone()
22362            })
22363        });
22364
22365        if let Some(hunk_key) = hunk_key {
22366            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22367            cx.notify();
22368        }
22369    }
22370
22371    /// Handles the EditReviewComment action - sets a comment into editing mode.
22372    pub fn edit_review_comment(
22373        &mut self,
22374        action: &EditReviewComment,
22375        window: &mut Window,
22376        cx: &mut Context<Self>,
22377    ) {
22378        let comment_id = action.id;
22379
22380        // Set the comment to editing mode
22381        self.set_comment_editing(comment_id, true, cx);
22382
22383        // Find the overlay that contains this comment and create an inline editor if needed
22384        // First, find which hunk this comment belongs to
22385        let hunk_key = self
22386            .stored_review_comments
22387            .iter()
22388            .find_map(|(key, comments)| {
22389                if comments.iter().any(|c| c.id == comment_id) {
22390                    Some(key.clone())
22391                } else {
22392                    None
22393                }
22394            });
22395
22396        let snapshot = self.buffer.read(cx).snapshot(cx);
22397        if let Some(hunk_key) = hunk_key {
22398            if let Some(overlay) = self
22399                .diff_review_overlays
22400                .iter_mut()
22401                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22402            {
22403                if let std::collections::hash_map::Entry::Vacant(entry) =
22404                    overlay.inline_edit_editors.entry(comment_id)
22405                {
22406                    // Find the comment text
22407                    let comment_text = self
22408                        .stored_review_comments
22409                        .iter()
22410                        .flat_map(|(_, comments)| comments)
22411                        .find(|c| c.id == comment_id)
22412                        .map(|c| c.comment.clone())
22413                        .unwrap_or_default();
22414
22415                    // Create inline editor
22416                    let parent_editor = cx.entity().downgrade();
22417                    let inline_editor = cx.new(|cx| {
22418                        let mut editor = Editor::single_line(window, cx);
22419                        editor.set_text(&*comment_text, window, cx);
22420                        // Select all text for easy replacement
22421                        editor.select_all(&crate::actions::SelectAll, window, cx);
22422                        editor
22423                    });
22424
22425                    // Register the Newline action to confirm the edit
22426                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22427                        inline_editor.register_action({
22428                            let parent_editor = parent_editor.clone();
22429                            move |_: &crate::actions::Newline, window, cx| {
22430                                if let Some(editor) = parent_editor.upgrade() {
22431                                    editor.update(cx, |editor, cx| {
22432                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22433                                    });
22434                                }
22435                            }
22436                        })
22437                    });
22438
22439                    // Store the subscription to keep the action handler alive
22440                    overlay
22441                        .inline_edit_subscriptions
22442                        .insert(comment_id, subscription);
22443
22444                    // Focus the inline editor
22445                    let focus_handle = inline_editor.focus_handle(cx);
22446                    window.focus(&focus_handle, cx);
22447
22448                    entry.insert(inline_editor);
22449                }
22450            }
22451        }
22452
22453        cx.notify();
22454    }
22455
22456    /// Confirms an inline edit of a review comment.
22457    pub fn confirm_edit_review_comment(
22458        &mut self,
22459        comment_id: usize,
22460        _window: &mut Window,
22461        cx: &mut Context<Self>,
22462    ) {
22463        // Get the new text from the inline editor
22464        // Find the overlay containing this comment's inline editor
22465        let snapshot = self.buffer.read(cx).snapshot(cx);
22466        let hunk_key = self
22467            .stored_review_comments
22468            .iter()
22469            .find_map(|(key, comments)| {
22470                if comments.iter().any(|c| c.id == comment_id) {
22471                    Some(key.clone())
22472                } else {
22473                    None
22474                }
22475            });
22476
22477        let new_text = hunk_key
22478            .as_ref()
22479            .and_then(|hunk_key| {
22480                self.diff_review_overlays
22481                    .iter()
22482                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22483            })
22484            .as_ref()
22485            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22486            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22487
22488        if let Some(new_text) = new_text {
22489            if !new_text.is_empty() {
22490                self.update_review_comment(comment_id, new_text, cx);
22491            }
22492        }
22493
22494        // Remove the inline editor and its subscription
22495        if let Some(hunk_key) = hunk_key {
22496            if let Some(overlay) = self
22497                .diff_review_overlays
22498                .iter_mut()
22499                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22500            {
22501                overlay.inline_edit_editors.remove(&comment_id);
22502                overlay.inline_edit_subscriptions.remove(&comment_id);
22503            }
22504        }
22505
22506        // Clear editing state
22507        self.set_comment_editing(comment_id, false, cx);
22508    }
22509
22510    /// Cancels an inline edit of a review comment.
22511    pub fn cancel_edit_review_comment(
22512        &mut self,
22513        comment_id: usize,
22514        _window: &mut Window,
22515        cx: &mut Context<Self>,
22516    ) {
22517        // Find which hunk this comment belongs to
22518        let hunk_key = self
22519            .stored_review_comments
22520            .iter()
22521            .find_map(|(key, comments)| {
22522                if comments.iter().any(|c| c.id == comment_id) {
22523                    Some(key.clone())
22524                } else {
22525                    None
22526                }
22527            });
22528
22529        // Remove the inline editor and its subscription
22530        if let Some(hunk_key) = hunk_key {
22531            let snapshot = self.buffer.read(cx).snapshot(cx);
22532            if let Some(overlay) = self
22533                .diff_review_overlays
22534                .iter_mut()
22535                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22536            {
22537                overlay.inline_edit_editors.remove(&comment_id);
22538                overlay.inline_edit_subscriptions.remove(&comment_id);
22539            }
22540        }
22541
22542        // Clear editing state
22543        self.set_comment_editing(comment_id, false, cx);
22544    }
22545
22546    /// Action handler for ConfirmEditReviewComment.
22547    pub fn confirm_edit_review_comment_action(
22548        &mut self,
22549        action: &ConfirmEditReviewComment,
22550        window: &mut Window,
22551        cx: &mut Context<Self>,
22552    ) {
22553        self.confirm_edit_review_comment(action.id, window, cx);
22554    }
22555
22556    /// Action handler for CancelEditReviewComment.
22557    pub fn cancel_edit_review_comment_action(
22558        &mut self,
22559        action: &CancelEditReviewComment,
22560        window: &mut Window,
22561        cx: &mut Context<Self>,
22562    ) {
22563        self.cancel_edit_review_comment(action.id, window, cx);
22564    }
22565
22566    /// Handles the DeleteReviewComment action - removes a comment.
22567    pub fn delete_review_comment(
22568        &mut self,
22569        action: &DeleteReviewComment,
22570        window: &mut Window,
22571        cx: &mut Context<Self>,
22572    ) {
22573        // Get the hunk key before removing the comment
22574        // Find the hunk key from the comment itself
22575        let comment_id = action.id;
22576        let hunk_key = self
22577            .stored_review_comments
22578            .iter()
22579            .find_map(|(key, comments)| {
22580                if comments.iter().any(|c| c.id == comment_id) {
22581                    Some(key.clone())
22582                } else {
22583                    None
22584                }
22585            });
22586
22587        // Also get it from the overlay for refresh purposes
22588        let overlay_hunk_key = self
22589            .diff_review_overlays
22590            .first()
22591            .map(|o| o.hunk_key.clone());
22592
22593        self.remove_review_comment(action.id, cx);
22594
22595        // Refresh the overlay height after removing a comment
22596        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22597            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22598        }
22599    }
22600
22601    fn render_diff_review_overlay(
22602        prompt_editor: &Entity<Editor>,
22603        hunk_key: &DiffHunkKey,
22604        editor_handle: &WeakEntity<Editor>,
22605        cx: &mut BlockContext,
22606    ) -> AnyElement {
22607        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22608            if ranges.is_empty() {
22609                return None;
22610            }
22611            let formatted: Vec<String> = ranges
22612                .iter()
22613                .map(|(start, end)| {
22614                    let start_line = start + 1;
22615                    let end_line = end + 1;
22616                    if start_line == end_line {
22617                        format!("Line {start_line}")
22618                    } else {
22619                        format!("Lines {start_line}-{end_line}")
22620                    }
22621                })
22622                .collect();
22623            // Don't show label for single line in single excerpt
22624            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22625                return None;
22626            }
22627            Some(formatted.join(""))
22628        }
22629
22630        let theme = cx.theme();
22631        let colors = theme.colors();
22632
22633        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22634            editor_handle
22635                .upgrade()
22636                .map(|editor| {
22637                    let editor = editor.read(cx);
22638                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22639                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22640                    let (expanded, editors, avatar_uri, line_ranges) = editor
22641                        .diff_review_overlays
22642                        .iter()
22643                        .find(|overlay| {
22644                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22645                        })
22646                        .map(|o| {
22647                            let start_point = o.anchor_range.start.to_point(&snapshot);
22648                            let end_point = o.anchor_range.end.to_point(&snapshot);
22649                            // Get line ranges per excerpt to detect discontinuities
22650                            let buffer_ranges =
22651                                snapshot.range_to_buffer_ranges(start_point..end_point);
22652                            let ranges: Vec<(u32, u32)> = buffer_ranges
22653                                .iter()
22654                                .map(|(buffer_snapshot, range, _)| {
22655                                    let start = buffer_snapshot.offset_to_point(range.start.0).row;
22656                                    let end = buffer_snapshot.offset_to_point(range.end.0).row;
22657                                    (start, end)
22658                                })
22659                                .collect();
22660                            (
22661                                o.comments_expanded,
22662                                o.inline_edit_editors.clone(),
22663                                o.user_avatar_uri.clone(),
22664                                if ranges.is_empty() {
22665                                    None
22666                                } else {
22667                                    Some(ranges)
22668                                },
22669                            )
22670                        })
22671                        .unwrap_or((true, HashMap::default(), None, None));
22672                    (comments, expanded, editors, avatar_uri, line_ranges)
22673                })
22674                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22675
22676        let comment_count = comments.len();
22677        let avatar_size = px(20.);
22678        let action_icon_size = IconSize::XSmall;
22679
22680        v_flex()
22681            .w_full()
22682            .bg(colors.editor_background)
22683            .border_b_1()
22684            .border_color(colors.border)
22685            .px_2()
22686            .pb_2()
22687            .gap_2()
22688            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22689            .when_some(line_ranges, |el, ranges| {
22690                let label = format_line_ranges(&ranges);
22691                if let Some(label) = label {
22692                    el.child(
22693                        h_flex()
22694                            .w_full()
22695                            .px_2()
22696                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22697                    )
22698                } else {
22699                    el
22700                }
22701            })
22702            // Top row: editable input with user's avatar
22703            .child(
22704                h_flex()
22705                    .w_full()
22706                    .items_center()
22707                    .gap_2()
22708                    .px_2()
22709                    .py_1p5()
22710                    .rounded_md()
22711                    .bg(colors.surface_background)
22712                    .child(
22713                        div()
22714                            .size(avatar_size)
22715                            .flex_shrink_0()
22716                            .rounded_full()
22717                            .overflow_hidden()
22718                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22719                                Avatar::new(avatar_uri.clone())
22720                                    .size(avatar_size)
22721                                    .into_any_element()
22722                            } else {
22723                                Icon::new(IconName::Person)
22724                                    .size(IconSize::Small)
22725                                    .color(ui::Color::Muted)
22726                                    .into_any_element()
22727                            }),
22728                    )
22729                    .child(
22730                        div()
22731                            .flex_1()
22732                            .border_1()
22733                            .border_color(colors.border)
22734                            .rounded_md()
22735                            .bg(colors.editor_background)
22736                            .px_2()
22737                            .py_1()
22738                            .child(prompt_editor.clone()),
22739                    )
22740                    .child(
22741                        h_flex()
22742                            .flex_shrink_0()
22743                            .gap_1()
22744                            .child(
22745                                IconButton::new("diff-review-close", IconName::Close)
22746                                    .icon_color(ui::Color::Muted)
22747                                    .icon_size(action_icon_size)
22748                                    .tooltip(Tooltip::text("Close"))
22749                                    .on_click(|_, window, cx| {
22750                                        window
22751                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22752                                    }),
22753                            )
22754                            .child(
22755                                IconButton::new("diff-review-add", IconName::Return)
22756                                    .icon_color(ui::Color::Muted)
22757                                    .icon_size(action_icon_size)
22758                                    .tooltip(Tooltip::text("Add comment"))
22759                                    .on_click(|_, window, cx| {
22760                                        window.dispatch_action(
22761                                            Box::new(crate::actions::SubmitDiffReviewComment),
22762                                            cx,
22763                                        );
22764                                    }),
22765                            ),
22766                    ),
22767            )
22768            // Expandable comments section (only shown when there are comments)
22769            .when(comment_count > 0, |el| {
22770                el.child(Self::render_comments_section(
22771                    comments,
22772                    comments_expanded,
22773                    inline_editors,
22774                    user_avatar_uri,
22775                    avatar_size,
22776                    action_icon_size,
22777                    colors,
22778                ))
22779            })
22780            .into_any_element()
22781    }
22782
22783    fn render_comments_section(
22784        comments: Vec<StoredReviewComment>,
22785        expanded: bool,
22786        inline_editors: HashMap<usize, Entity<Editor>>,
22787        user_avatar_uri: Option<SharedUri>,
22788        avatar_size: Pixels,
22789        action_icon_size: IconSize,
22790        colors: &theme::ThemeColors,
22791    ) -> impl IntoElement {
22792        let comment_count = comments.len();
22793
22794        v_flex()
22795            .w_full()
22796            .gap_1()
22797            // Header with expand/collapse toggle
22798            .child(
22799                h_flex()
22800                    .id("review-comments-header")
22801                    .w_full()
22802                    .items_center()
22803                    .gap_1()
22804                    .px_2()
22805                    .py_1()
22806                    .cursor_pointer()
22807                    .rounded_md()
22808                    .hover(|style| style.bg(colors.ghost_element_hover))
22809                    .on_click(|_, window: &mut Window, cx| {
22810                        window.dispatch_action(
22811                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22812                            cx,
22813                        );
22814                    })
22815                    .child(
22816                        Icon::new(if expanded {
22817                            IconName::ChevronDown
22818                        } else {
22819                            IconName::ChevronRight
22820                        })
22821                        .size(IconSize::Small)
22822                        .color(ui::Color::Muted),
22823                    )
22824                    .child(
22825                        Label::new(format!(
22826                            "{} Comment{}",
22827                            comment_count,
22828                            if comment_count == 1 { "" } else { "s" }
22829                        ))
22830                        .size(LabelSize::Small)
22831                        .color(Color::Muted),
22832                    ),
22833            )
22834            // Comments list (when expanded)
22835            .when(expanded, |el| {
22836                el.children(comments.into_iter().map(|comment| {
22837                    let inline_editor = inline_editors.get(&comment.id).cloned();
22838                    Self::render_comment_row(
22839                        comment,
22840                        inline_editor,
22841                        user_avatar_uri.clone(),
22842                        avatar_size,
22843                        action_icon_size,
22844                        colors,
22845                    )
22846                }))
22847            })
22848    }
22849
22850    fn render_comment_row(
22851        comment: StoredReviewComment,
22852        inline_editor: Option<Entity<Editor>>,
22853        user_avatar_uri: Option<SharedUri>,
22854        avatar_size: Pixels,
22855        action_icon_size: IconSize,
22856        colors: &theme::ThemeColors,
22857    ) -> impl IntoElement {
22858        let comment_id = comment.id;
22859        let is_editing = inline_editor.is_some();
22860
22861        h_flex()
22862            .w_full()
22863            .items_center()
22864            .gap_2()
22865            .px_2()
22866            .py_1p5()
22867            .rounded_md()
22868            .bg(colors.surface_background)
22869            .child(
22870                div()
22871                    .size(avatar_size)
22872                    .flex_shrink_0()
22873                    .rounded_full()
22874                    .overflow_hidden()
22875                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22876                        Avatar::new(avatar_uri.clone())
22877                            .size(avatar_size)
22878                            .into_any_element()
22879                    } else {
22880                        Icon::new(IconName::Person)
22881                            .size(IconSize::Small)
22882                            .color(ui::Color::Muted)
22883                            .into_any_element()
22884                    }),
22885            )
22886            .child(if let Some(editor) = inline_editor {
22887                // Inline edit mode: show an editable text field
22888                div()
22889                    .flex_1()
22890                    .border_1()
22891                    .border_color(colors.border)
22892                    .rounded_md()
22893                    .bg(colors.editor_background)
22894                    .px_2()
22895                    .py_1()
22896                    .child(editor)
22897                    .into_any_element()
22898            } else {
22899                // Display mode: show the comment text
22900                div()
22901                    .flex_1()
22902                    .text_sm()
22903                    .text_color(colors.text)
22904                    .child(comment.comment)
22905                    .into_any_element()
22906            })
22907            .child(if is_editing {
22908                // Editing mode: show close and confirm buttons
22909                h_flex()
22910                    .gap_1()
22911                    .child(
22912                        IconButton::new(
22913                            format!("diff-review-cancel-edit-{comment_id}"),
22914                            IconName::Close,
22915                        )
22916                        .icon_color(ui::Color::Muted)
22917                        .icon_size(action_icon_size)
22918                        .tooltip(Tooltip::text("Cancel"))
22919                        .on_click(move |_, window, cx| {
22920                            window.dispatch_action(
22921                                Box::new(crate::actions::CancelEditReviewComment {
22922                                    id: comment_id,
22923                                }),
22924                                cx,
22925                            );
22926                        }),
22927                    )
22928                    .child(
22929                        IconButton::new(
22930                            format!("diff-review-confirm-edit-{comment_id}"),
22931                            IconName::Return,
22932                        )
22933                        .icon_color(ui::Color::Muted)
22934                        .icon_size(action_icon_size)
22935                        .tooltip(Tooltip::text("Confirm"))
22936                        .on_click(move |_, window, cx| {
22937                            window.dispatch_action(
22938                                Box::new(crate::actions::ConfirmEditReviewComment {
22939                                    id: comment_id,
22940                                }),
22941                                cx,
22942                            );
22943                        }),
22944                    )
22945                    .into_any_element()
22946            } else {
22947                // Display mode: no action buttons for now (edit/delete not yet implemented)
22948                gpui::Empty.into_any_element()
22949            })
22950    }
22951
22952    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22953        if self.display_map.read(cx).masked != masked {
22954            self.display_map.update(cx, |map, _| map.masked = masked);
22955        }
22956        cx.notify()
22957    }
22958
22959    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22960        self.show_wrap_guides = Some(show_wrap_guides);
22961        cx.notify();
22962    }
22963
22964    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22965        self.show_indent_guides = Some(show_indent_guides);
22966        cx.notify();
22967    }
22968
22969    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22970        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22971            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22972                && let Some(dir) = file.abs_path(cx).parent()
22973            {
22974                return Some(dir.to_owned());
22975            }
22976        }
22977
22978        None
22979    }
22980
22981    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22982        self.active_buffer(cx)?
22983            .read(cx)
22984            .file()
22985            .and_then(|f| f.as_local())
22986    }
22987
22988    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22989        self.active_buffer(cx).and_then(|buffer| {
22990            let buffer = buffer.read(cx);
22991            if let Some(project_path) = buffer.project_path(cx) {
22992                let project = self.project()?.read(cx);
22993                project.absolute_path(&project_path, cx)
22994            } else {
22995                buffer
22996                    .file()
22997                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22998            }
22999        })
23000    }
23001
23002    pub fn reveal_in_finder(
23003        &mut self,
23004        _: &RevealInFileManager,
23005        _window: &mut Window,
23006        cx: &mut Context<Self>,
23007    ) {
23008        if let Some(path) = self.target_file_abs_path(cx) {
23009            if let Some(project) = self.project() {
23010                project.update(cx, |project, cx| project.reveal_path(&path, cx));
23011            } else {
23012                cx.reveal_path(&path);
23013            }
23014        }
23015    }
23016
23017    pub fn copy_path(
23018        &mut self,
23019        _: &zed_actions::workspace::CopyPath,
23020        _window: &mut Window,
23021        cx: &mut Context<Self>,
23022    ) {
23023        if let Some(path) = self.target_file_abs_path(cx)
23024            && let Some(path) = path.to_str()
23025        {
23026            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23027        } else {
23028            cx.propagate();
23029        }
23030    }
23031
23032    pub fn copy_relative_path(
23033        &mut self,
23034        _: &zed_actions::workspace::CopyRelativePath,
23035        _window: &mut Window,
23036        cx: &mut Context<Self>,
23037    ) {
23038        if let Some(path) = self.active_buffer(cx).and_then(|buffer| {
23039            let project = self.project()?.read(cx);
23040            let path = buffer.read(cx).file()?.path();
23041            let path = path.display(project.path_style(cx));
23042            Some(path)
23043        }) {
23044            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23045        } else {
23046            cx.propagate();
23047        }
23048    }
23049
23050    /// Returns the project path for the editor's buffer, if any buffer is
23051    /// opened in the editor.
23052    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
23053        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
23054            buffer.read(cx).project_path(cx)
23055        } else {
23056            None
23057        }
23058    }
23059
23060    // Returns true if the editor handled a go-to-line request
23061    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
23062        maybe!({
23063            let breakpoint_store = self.breakpoint_store.as_ref()?;
23064
23065            let (active_stack_frame, debug_line_pane_id) = {
23066                let store = breakpoint_store.read(cx);
23067                let active_stack_frame = store.active_position().cloned();
23068                let debug_line_pane_id = store.active_debug_line_pane_id();
23069                (active_stack_frame, debug_line_pane_id)
23070            };
23071
23072            let Some(active_stack_frame) = active_stack_frame else {
23073                self.clear_row_highlights::<ActiveDebugLine>();
23074                return None;
23075            };
23076
23077            if let Some(debug_line_pane_id) = debug_line_pane_id {
23078                if let Some(workspace) = self
23079                    .workspace
23080                    .as_ref()
23081                    .and_then(|(workspace, _)| workspace.upgrade())
23082                {
23083                    let editor_pane_id = workspace
23084                        .read(cx)
23085                        .pane_for_item_id(cx.entity_id())
23086                        .map(|pane| pane.entity_id());
23087
23088                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
23089                        self.clear_row_highlights::<ActiveDebugLine>();
23090                        return None;
23091                    }
23092                }
23093            }
23094
23095            let position = active_stack_frame.position;
23096
23097            let snapshot = self.buffer.read(cx).snapshot(cx);
23098            let multibuffer_anchor = snapshot.anchor_in_excerpt(position)?;
23099
23100            self.clear_row_highlights::<ActiveDebugLine>();
23101
23102            self.go_to_line::<ActiveDebugLine>(
23103                multibuffer_anchor,
23104                Some(cx.theme().colors().editor_debugger_active_line_background),
23105                window,
23106                cx,
23107            );
23108
23109            cx.notify();
23110
23111            Some(())
23112        })
23113        .is_some()
23114    }
23115
23116    pub fn copy_file_name_without_extension(
23117        &mut self,
23118        _: &CopyFileNameWithoutExtension,
23119        _: &mut Window,
23120        cx: &mut Context<Self>,
23121    ) {
23122        if let Some(file_stem) = self.active_buffer(cx).and_then(|buffer| {
23123            let file = buffer.read(cx).file()?;
23124            file.path().file_stem()
23125        }) {
23126            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23127        }
23128    }
23129
23130    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23131        if let Some(file_name) = self.active_buffer(cx).and_then(|buffer| {
23132            let file = buffer.read(cx).file()?;
23133            Some(file.file_name(cx))
23134        }) {
23135            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23136        }
23137    }
23138
23139    pub fn toggle_git_blame(
23140        &mut self,
23141        _: &::git::Blame,
23142        window: &mut Window,
23143        cx: &mut Context<Self>,
23144    ) {
23145        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23146
23147        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23148            self.start_git_blame(true, window, cx);
23149        }
23150
23151        cx.notify();
23152    }
23153
23154    pub fn toggle_git_blame_inline(
23155        &mut self,
23156        _: &ToggleGitBlameInline,
23157        window: &mut Window,
23158        cx: &mut Context<Self>,
23159    ) {
23160        self.toggle_git_blame_inline_internal(true, window, cx);
23161        cx.notify();
23162    }
23163
23164    pub fn open_git_blame_commit(
23165        &mut self,
23166        _: &OpenGitBlameCommit,
23167        window: &mut Window,
23168        cx: &mut Context<Self>,
23169    ) {
23170        self.open_git_blame_commit_internal(window, cx);
23171    }
23172
23173    fn open_git_blame_commit_internal(
23174        &mut self,
23175        window: &mut Window,
23176        cx: &mut Context<Self>,
23177    ) -> Option<()> {
23178        let blame = self.blame.as_ref()?;
23179        let snapshot = self.snapshot(window, cx);
23180        let cursor = self
23181            .selections
23182            .newest::<Point>(&snapshot.display_snapshot)
23183            .head();
23184        let (buffer, point) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23185        let (_, blame_entry) = blame
23186            .update(cx, |blame, cx| {
23187                blame
23188                    .blame_for_rows(
23189                        &[RowInfo {
23190                            buffer_id: Some(buffer.remote_id()),
23191                            buffer_row: Some(point.row),
23192                            ..Default::default()
23193                        }],
23194                        cx,
23195                    )
23196                    .next()
23197            })
23198            .flatten()?;
23199        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23200        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23201        let workspace = self.workspace()?.downgrade();
23202        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23203        None
23204    }
23205
23206    pub fn git_blame_inline_enabled(&self) -> bool {
23207        self.git_blame_inline_enabled
23208    }
23209
23210    pub fn toggle_selection_menu(
23211        &mut self,
23212        _: &ToggleSelectionMenu,
23213        _: &mut Window,
23214        cx: &mut Context<Self>,
23215    ) {
23216        self.show_selection_menu = self
23217            .show_selection_menu
23218            .map(|show_selections_menu| !show_selections_menu)
23219            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23220
23221        cx.notify();
23222    }
23223
23224    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23225        self.show_selection_menu
23226            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23227    }
23228
23229    fn start_git_blame(
23230        &mut self,
23231        user_triggered: bool,
23232        window: &mut Window,
23233        cx: &mut Context<Self>,
23234    ) {
23235        if let Some(project) = self.project() {
23236            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23237                && buffer.read(cx).file().is_none()
23238            {
23239                return;
23240            }
23241
23242            let focused = self.focus_handle(cx).contains_focused(window, cx);
23243
23244            let project = project.clone();
23245            let blame = cx
23246                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23247            self.blame_subscription =
23248                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23249            self.blame = Some(blame);
23250        }
23251    }
23252
23253    fn toggle_git_blame_inline_internal(
23254        &mut self,
23255        user_triggered: bool,
23256        window: &mut Window,
23257        cx: &mut Context<Self>,
23258    ) {
23259        if self.git_blame_inline_enabled {
23260            self.git_blame_inline_enabled = false;
23261            self.show_git_blame_inline = false;
23262            self.show_git_blame_inline_delay_task.take();
23263        } else {
23264            self.git_blame_inline_enabled = true;
23265            self.start_git_blame_inline(user_triggered, window, cx);
23266        }
23267
23268        cx.notify();
23269    }
23270
23271    fn start_git_blame_inline(
23272        &mut self,
23273        user_triggered: bool,
23274        window: &mut Window,
23275        cx: &mut Context<Self>,
23276    ) {
23277        self.start_git_blame(user_triggered, window, cx);
23278
23279        if ProjectSettings::get_global(cx)
23280            .git
23281            .inline_blame_delay()
23282            .is_some()
23283        {
23284            self.start_inline_blame_timer(window, cx);
23285        } else {
23286            self.show_git_blame_inline = true
23287        }
23288    }
23289
23290    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23291        self.blame.as_ref()
23292    }
23293
23294    pub fn show_git_blame_gutter(&self) -> bool {
23295        self.show_git_blame_gutter
23296    }
23297
23298    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23299        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23300    }
23301
23302    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23303        self.show_git_blame_inline
23304            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23305            && !self.newest_selection_head_on_empty_line(cx)
23306            && self.has_blame_entries(cx)
23307    }
23308
23309    fn has_blame_entries(&self, cx: &App) -> bool {
23310        self.blame()
23311            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23312    }
23313
23314    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23315        let cursor_anchor = self.selections.newest_anchor().head();
23316
23317        let snapshot = self.buffer.read(cx).snapshot(cx);
23318        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23319
23320        snapshot.line_len(buffer_row) == 0
23321    }
23322
23323    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23324        let buffer_and_selection = maybe!({
23325            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23326            let selection_range = selection.range();
23327
23328            let multi_buffer = self.buffer().read(cx);
23329            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23330            let buffer_ranges = multi_buffer_snapshot
23331                .range_to_buffer_ranges(selection_range.start..selection_range.end);
23332
23333            let (buffer_snapshot, range, _) = if selection.reversed {
23334                buffer_ranges.first()
23335            } else {
23336                buffer_ranges.last()
23337            }?;
23338
23339            let buffer_range = range.to_point(buffer_snapshot);
23340            let buffer = multi_buffer.buffer(buffer_snapshot.remote_id()).unwrap();
23341
23342            let Some(buffer_diff) = multi_buffer.diff_for(buffer_snapshot.remote_id()) else {
23343                return Some((buffer, buffer_range.start.row..buffer_range.end.row));
23344            };
23345
23346            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23347            let start = buffer_diff_snapshot
23348                .buffer_point_to_base_text_point(buffer_range.start, &buffer_snapshot);
23349            let end = buffer_diff_snapshot
23350                .buffer_point_to_base_text_point(buffer_range.end, &buffer_snapshot);
23351
23352            Some((buffer, start.row..end.row))
23353        });
23354
23355        let Some((buffer, selection)) = buffer_and_selection else {
23356            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23357        };
23358
23359        let Some(project) = self.project() else {
23360            return Task::ready(Err(anyhow!("editor does not have project")));
23361        };
23362
23363        project.update(cx, |project, cx| {
23364            project.get_permalink_to_line(&buffer, selection, cx)
23365        })
23366    }
23367
23368    pub fn copy_permalink_to_line(
23369        &mut self,
23370        _: &CopyPermalinkToLine,
23371        window: &mut Window,
23372        cx: &mut Context<Self>,
23373    ) {
23374        let permalink_task = self.get_permalink_to_line(cx);
23375        let workspace = self.workspace();
23376
23377        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23378            Ok(permalink) => {
23379                cx.update(|_, cx| {
23380                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23381                })
23382                .ok();
23383            }
23384            Err(err) => {
23385                let message = format!("Failed to copy permalink: {err}");
23386
23387                anyhow::Result::<()>::Err(err).log_err();
23388
23389                if let Some(workspace) = workspace {
23390                    workspace
23391                        .update_in(cx, |workspace, _, cx| {
23392                            struct CopyPermalinkToLine;
23393
23394                            workspace.show_toast(
23395                                Toast::new(
23396                                    NotificationId::unique::<CopyPermalinkToLine>(),
23397                                    message,
23398                                ),
23399                                cx,
23400                            )
23401                        })
23402                        .ok();
23403                }
23404            }
23405        })
23406        .detach();
23407    }
23408
23409    pub fn copy_file_location(
23410        &mut self,
23411        _: &CopyFileLocation,
23412        _: &mut Window,
23413        cx: &mut Context<Self>,
23414    ) {
23415        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23416
23417        let start_line = selection.start.row + 1;
23418        let end_line = selection.end.row + 1;
23419
23420        let end_line = if selection.end.column == 0 && end_line > start_line {
23421            end_line - 1
23422        } else {
23423            end_line
23424        };
23425
23426        if let Some(file_location) = self.active_buffer(cx).and_then(|buffer| {
23427            let project = self.project()?.read(cx);
23428            let file = buffer.read(cx).file()?;
23429            let path = file.path().display(project.path_style(cx));
23430
23431            let location = if start_line == end_line {
23432                format!("{path}:{start_line}")
23433            } else {
23434                format!("{path}:{start_line}-{end_line}")
23435            };
23436            Some(location)
23437        }) {
23438            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23439        }
23440    }
23441
23442    pub fn open_permalink_to_line(
23443        &mut self,
23444        _: &OpenPermalinkToLine,
23445        window: &mut Window,
23446        cx: &mut Context<Self>,
23447    ) {
23448        let permalink_task = self.get_permalink_to_line(cx);
23449        let workspace = self.workspace();
23450
23451        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23452            Ok(permalink) => {
23453                cx.update(|_, cx| {
23454                    cx.open_url(permalink.as_ref());
23455                })
23456                .ok();
23457            }
23458            Err(err) => {
23459                let message = format!("Failed to open permalink: {err}");
23460
23461                anyhow::Result::<()>::Err(err).log_err();
23462
23463                if let Some(workspace) = workspace {
23464                    workspace.update(cx, |workspace, cx| {
23465                        struct OpenPermalinkToLine;
23466
23467                        workspace.show_toast(
23468                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23469                            cx,
23470                        )
23471                    });
23472                }
23473            }
23474        })
23475        .detach();
23476    }
23477
23478    pub fn insert_uuid_v4(
23479        &mut self,
23480        _: &InsertUuidV4,
23481        window: &mut Window,
23482        cx: &mut Context<Self>,
23483    ) {
23484        self.insert_uuid(UuidVersion::V4, window, cx);
23485    }
23486
23487    pub fn insert_uuid_v7(
23488        &mut self,
23489        _: &InsertUuidV7,
23490        window: &mut Window,
23491        cx: &mut Context<Self>,
23492    ) {
23493        self.insert_uuid(UuidVersion::V7, window, cx);
23494    }
23495
23496    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23497        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23498        self.transact(window, cx, |this, window, cx| {
23499            let edits = this
23500                .selections
23501                .all::<Point>(&this.display_snapshot(cx))
23502                .into_iter()
23503                .map(|selection| {
23504                    let uuid = match version {
23505                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23506                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23507                    };
23508
23509                    (selection.range(), uuid.to_string())
23510                });
23511            this.edit(edits, cx);
23512            this.refresh_edit_prediction(true, false, window, cx);
23513        });
23514    }
23515
23516    pub fn open_selections_in_multibuffer(
23517        &mut self,
23518        _: &OpenSelectionsInMultibuffer,
23519        window: &mut Window,
23520        cx: &mut Context<Self>,
23521    ) {
23522        let multibuffer = self.buffer.read(cx);
23523
23524        let Some(buffer) = multibuffer.as_singleton() else {
23525            return;
23526        };
23527        let buffer_snapshot = buffer.read(cx).snapshot();
23528
23529        let Some(workspace) = self.workspace() else {
23530            return;
23531        };
23532
23533        let title = multibuffer.title(cx).to_string();
23534
23535        let locations = self
23536            .selections
23537            .all_anchors(&self.display_snapshot(cx))
23538            .iter()
23539            .map(|selection| {
23540                (
23541                    buffer.clone(),
23542                    (selection.start.text_anchor_in(&buffer_snapshot)
23543                        ..selection.end.text_anchor_in(&buffer_snapshot))
23544                        .to_point(buffer.read(cx)),
23545                )
23546            })
23547            .into_group_map();
23548
23549        cx.spawn_in(window, async move |_, cx| {
23550            workspace.update_in(cx, |workspace, window, cx| {
23551                Self::open_locations_in_multibuffer(
23552                    workspace,
23553                    locations,
23554                    format!("Selections for '{title}'"),
23555                    false,
23556                    false,
23557                    MultibufferSelectionMode::All,
23558                    window,
23559                    cx,
23560                );
23561            })
23562        })
23563        .detach();
23564    }
23565
23566    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23567    /// last highlight added will be used.
23568    ///
23569    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23570    pub fn highlight_rows<T: 'static>(
23571        &mut self,
23572        range: Range<Anchor>,
23573        color: Hsla,
23574        options: RowHighlightOptions,
23575        cx: &mut Context<Self>,
23576    ) {
23577        let snapshot = self.buffer().read(cx).snapshot(cx);
23578        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23579        let ix = row_highlights.binary_search_by(|highlight| {
23580            Ordering::Equal
23581                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23582                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23583        });
23584
23585        if let Err(mut ix) = ix {
23586            let index = post_inc(&mut self.highlight_order);
23587
23588            // If this range intersects with the preceding highlight, then merge it with
23589            // the preceding highlight. Otherwise insert a new highlight.
23590            let mut merged = false;
23591            if ix > 0 {
23592                let prev_highlight = &mut row_highlights[ix - 1];
23593                if prev_highlight
23594                    .range
23595                    .end
23596                    .cmp(&range.start, &snapshot)
23597                    .is_ge()
23598                {
23599                    ix -= 1;
23600                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23601                        prev_highlight.range.end = range.end;
23602                    }
23603                    merged = true;
23604                    prev_highlight.index = index;
23605                    prev_highlight.color = color;
23606                    prev_highlight.options = options;
23607                }
23608            }
23609
23610            if !merged {
23611                row_highlights.insert(
23612                    ix,
23613                    RowHighlight {
23614                        range,
23615                        index,
23616                        color,
23617                        options,
23618                        type_id: TypeId::of::<T>(),
23619                    },
23620                );
23621            }
23622
23623            // If any of the following highlights intersect with this one, merge them.
23624            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23625                let highlight = &row_highlights[ix];
23626                if next_highlight
23627                    .range
23628                    .start
23629                    .cmp(&highlight.range.end, &snapshot)
23630                    .is_le()
23631                {
23632                    if next_highlight
23633                        .range
23634                        .end
23635                        .cmp(&highlight.range.end, &snapshot)
23636                        .is_gt()
23637                    {
23638                        row_highlights[ix].range.end = next_highlight.range.end;
23639                    }
23640                    row_highlights.remove(ix + 1);
23641                } else {
23642                    break;
23643                }
23644            }
23645        }
23646    }
23647
23648    /// Remove any highlighted row ranges of the given type that intersect the
23649    /// given ranges.
23650    pub fn remove_highlighted_rows<T: 'static>(
23651        &mut self,
23652        ranges_to_remove: Vec<Range<Anchor>>,
23653        cx: &mut Context<Self>,
23654    ) {
23655        let snapshot = self.buffer().read(cx).snapshot(cx);
23656        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23657        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23658        row_highlights.retain(|highlight| {
23659            while let Some(range_to_remove) = ranges_to_remove.peek() {
23660                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23661                    Ordering::Less | Ordering::Equal => {
23662                        ranges_to_remove.next();
23663                    }
23664                    Ordering::Greater => {
23665                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23666                            Ordering::Less | Ordering::Equal => {
23667                                return false;
23668                            }
23669                            Ordering::Greater => break,
23670                        }
23671                    }
23672                }
23673            }
23674
23675            true
23676        })
23677    }
23678
23679    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23680    pub fn clear_row_highlights<T: 'static>(&mut self) {
23681        self.highlighted_rows.remove(&TypeId::of::<T>());
23682    }
23683
23684    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23685    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23686        self.highlighted_rows
23687            .get(&TypeId::of::<T>())
23688            .map_or(&[] as &[_], |vec| vec.as_slice())
23689            .iter()
23690            .map(|highlight| (highlight.range.clone(), highlight.color))
23691    }
23692
23693    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23694    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23695    /// Allows to ignore certain kinds of highlights.
23696    pub fn highlighted_display_rows(
23697        &self,
23698        window: &mut Window,
23699        cx: &mut App,
23700    ) -> BTreeMap<DisplayRow, LineHighlight> {
23701        let snapshot = self.snapshot(window, cx);
23702        let mut used_highlight_orders = HashMap::default();
23703        self.highlighted_rows
23704            .iter()
23705            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23706            .fold(
23707                BTreeMap::<DisplayRow, LineHighlight>::new(),
23708                |mut unique_rows, highlight| {
23709                    let start = highlight.range.start.to_display_point(&snapshot);
23710                    let end = highlight.range.end.to_display_point(&snapshot);
23711                    let start_row = start.row().0;
23712                    let end_row = if !highlight.range.end.is_max() && end.column() == 0 {
23713                        end.row().0.saturating_sub(1)
23714                    } else {
23715                        end.row().0
23716                    };
23717                    for row in start_row..=end_row {
23718                        let used_index =
23719                            used_highlight_orders.entry(row).or_insert(highlight.index);
23720                        if highlight.index >= *used_index {
23721                            *used_index = highlight.index;
23722                            unique_rows.insert(
23723                                DisplayRow(row),
23724                                LineHighlight {
23725                                    include_gutter: highlight.options.include_gutter,
23726                                    border: None,
23727                                    background: highlight.color.into(),
23728                                    type_id: Some(highlight.type_id),
23729                                },
23730                            );
23731                        }
23732                    }
23733                    unique_rows
23734                },
23735            )
23736    }
23737
23738    pub fn highlighted_display_row_for_autoscroll(
23739        &self,
23740        snapshot: &DisplaySnapshot,
23741    ) -> Option<DisplayRow> {
23742        self.highlighted_rows
23743            .values()
23744            .flat_map(|highlighted_rows| highlighted_rows.iter())
23745            .filter_map(|highlight| {
23746                if highlight.options.autoscroll {
23747                    Some(highlight.range.start.to_display_point(snapshot).row())
23748                } else {
23749                    None
23750                }
23751            })
23752            .min()
23753    }
23754
23755    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23756        self.highlight_background(
23757            HighlightKey::SearchWithinRange,
23758            ranges,
23759            |_, colors| colors.colors().editor_document_highlight_read_background,
23760            cx,
23761        )
23762    }
23763
23764    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23765        self.breadcrumb_header = Some(new_header);
23766    }
23767
23768    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23769        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23770    }
23771
23772    pub fn highlight_background(
23773        &mut self,
23774        key: HighlightKey,
23775        ranges: &[Range<Anchor>],
23776        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23777        cx: &mut Context<Self>,
23778    ) {
23779        self.background_highlights
23780            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23781        self.scrollbar_marker_state.dirty = true;
23782        cx.notify();
23783    }
23784
23785    pub fn clear_background_highlights(
23786        &mut self,
23787        key: HighlightKey,
23788        cx: &mut Context<Self>,
23789    ) -> Option<BackgroundHighlight> {
23790        let text_highlights = self.background_highlights.remove(&key)?;
23791        if !text_highlights.1.is_empty() {
23792            self.scrollbar_marker_state.dirty = true;
23793            cx.notify();
23794        }
23795        Some(text_highlights)
23796    }
23797
23798    pub fn highlight_gutter<T: 'static>(
23799        &mut self,
23800        ranges: impl Into<Vec<Range<Anchor>>>,
23801        color_fetcher: fn(&App) -> Hsla,
23802        cx: &mut Context<Self>,
23803    ) {
23804        self.gutter_highlights
23805            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23806        cx.notify();
23807    }
23808
23809    pub fn clear_gutter_highlights<T: 'static>(
23810        &mut self,
23811        cx: &mut Context<Self>,
23812    ) -> Option<GutterHighlight> {
23813        cx.notify();
23814        self.gutter_highlights.remove(&TypeId::of::<T>())
23815    }
23816
23817    pub fn insert_gutter_highlight<T: 'static>(
23818        &mut self,
23819        range: Range<Anchor>,
23820        color_fetcher: fn(&App) -> Hsla,
23821        cx: &mut Context<Self>,
23822    ) {
23823        let snapshot = self.buffer().read(cx).snapshot(cx);
23824        let mut highlights = self
23825            .gutter_highlights
23826            .remove(&TypeId::of::<T>())
23827            .map(|(_, highlights)| highlights)
23828            .unwrap_or_default();
23829        let ix = highlights.binary_search_by(|highlight| {
23830            Ordering::Equal
23831                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23832                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23833        });
23834        if let Err(ix) = ix {
23835            highlights.insert(ix, range);
23836        }
23837        self.gutter_highlights
23838            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23839    }
23840
23841    pub fn remove_gutter_highlights<T: 'static>(
23842        &mut self,
23843        ranges_to_remove: Vec<Range<Anchor>>,
23844        cx: &mut Context<Self>,
23845    ) {
23846        let snapshot = self.buffer().read(cx).snapshot(cx);
23847        let Some((color_fetcher, mut gutter_highlights)) =
23848            self.gutter_highlights.remove(&TypeId::of::<T>())
23849        else {
23850            return;
23851        };
23852        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23853        gutter_highlights.retain(|highlight| {
23854            while let Some(range_to_remove) = ranges_to_remove.peek() {
23855                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23856                    Ordering::Less | Ordering::Equal => {
23857                        ranges_to_remove.next();
23858                    }
23859                    Ordering::Greater => {
23860                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23861                            Ordering::Less | Ordering::Equal => {
23862                                return false;
23863                            }
23864                            Ordering::Greater => break,
23865                        }
23866                    }
23867                }
23868            }
23869
23870            true
23871        });
23872        self.gutter_highlights
23873            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23874    }
23875
23876    #[cfg(any(test, feature = "test-support"))]
23877    pub fn all_text_highlights(
23878        &self,
23879        window: &mut Window,
23880        cx: &mut Context<Self>,
23881    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23882        let snapshot = self.snapshot(window, cx);
23883        self.display_map.update(cx, |display_map, _| {
23884            display_map
23885                .all_text_highlights()
23886                .map(|(_, highlight)| {
23887                    let (style, ranges) = highlight.as_ref();
23888                    (
23889                        *style,
23890                        ranges
23891                            .iter()
23892                            .map(|range| range.clone().to_display_points(&snapshot))
23893                            .collect(),
23894                    )
23895                })
23896                .collect()
23897        })
23898    }
23899
23900    #[cfg(any(test, feature = "test-support"))]
23901    pub fn all_text_background_highlights(
23902        &self,
23903        window: &mut Window,
23904        cx: &mut Context<Self>,
23905    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23906        let snapshot = self.snapshot(window, cx);
23907        let buffer = &snapshot.buffer_snapshot();
23908        let start = buffer.anchor_before(MultiBufferOffset(0));
23909        let end = buffer.anchor_after(buffer.len());
23910        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23911    }
23912
23913    #[cfg(any(test, feature = "test-support"))]
23914    pub fn sorted_background_highlights_in_range(
23915        &self,
23916        search_range: Range<Anchor>,
23917        display_snapshot: &DisplaySnapshot,
23918        theme: &Theme,
23919    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23920        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23921        res.sort_by(|a, b| {
23922            a.0.start
23923                .cmp(&b.0.start)
23924                .then_with(|| a.0.end.cmp(&b.0.end))
23925                .then_with(|| a.1.cmp(&b.1))
23926        });
23927        res
23928    }
23929
23930    #[cfg(any(test, feature = "test-support"))]
23931    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23932        let snapshot = self.buffer().read(cx).snapshot(cx);
23933
23934        let highlights = self
23935            .background_highlights
23936            .get(&HighlightKey::BufferSearchHighlights);
23937
23938        if let Some((_color, ranges)) = highlights {
23939            ranges
23940                .iter()
23941                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23942                .collect_vec()
23943        } else {
23944            vec![]
23945        }
23946    }
23947
23948    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23949        self.background_highlights
23950            .get(&key)
23951            .is_some_and(|(_, highlights)| !highlights.is_empty())
23952    }
23953
23954    /// Returns all background highlights for a given range.
23955    ///
23956    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23957    pub fn background_highlights_in_range(
23958        &self,
23959        search_range: Range<Anchor>,
23960        display_snapshot: &DisplaySnapshot,
23961        theme: &Theme,
23962    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23963        let mut results = Vec::new();
23964        for (color_fetcher, ranges) in self.background_highlights.values() {
23965            let start_ix = match ranges.binary_search_by(|probe| {
23966                let cmp = probe
23967                    .end
23968                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23969                if cmp.is_gt() {
23970                    Ordering::Greater
23971                } else {
23972                    Ordering::Less
23973                }
23974            }) {
23975                Ok(i) | Err(i) => i,
23976            };
23977            for (index, range) in ranges[start_ix..].iter().enumerate() {
23978                if range
23979                    .start
23980                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23981                    .is_ge()
23982                {
23983                    break;
23984                }
23985
23986                let color = color_fetcher(&(start_ix + index), theme);
23987                let start = range.start.to_display_point(display_snapshot);
23988                let end = range.end.to_display_point(display_snapshot);
23989                results.push((start..end, color))
23990            }
23991        }
23992        results
23993    }
23994
23995    pub fn gutter_highlights_in_range(
23996        &self,
23997        search_range: Range<Anchor>,
23998        display_snapshot: &DisplaySnapshot,
23999        cx: &App,
24000    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24001        let mut results = Vec::new();
24002        for (color_fetcher, ranges) in self.gutter_highlights.values() {
24003            let color = color_fetcher(cx);
24004            let start_ix = match ranges.binary_search_by(|probe| {
24005                let cmp = probe
24006                    .end
24007                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
24008                if cmp.is_gt() {
24009                    Ordering::Greater
24010                } else {
24011                    Ordering::Less
24012                }
24013            }) {
24014                Ok(i) | Err(i) => i,
24015            };
24016            for range in &ranges[start_ix..] {
24017                if range
24018                    .start
24019                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24020                    .is_ge()
24021                {
24022                    break;
24023                }
24024
24025                let start = range.start.to_display_point(display_snapshot);
24026                let end = range.end.to_display_point(display_snapshot);
24027                results.push((start..end, color))
24028            }
24029        }
24030        results
24031    }
24032
24033    /// Get the text ranges corresponding to the redaction query
24034    pub fn redacted_ranges(
24035        &self,
24036        search_range: Range<Anchor>,
24037        display_snapshot: &DisplaySnapshot,
24038        cx: &App,
24039    ) -> Vec<Range<DisplayPoint>> {
24040        display_snapshot
24041            .buffer_snapshot()
24042            .redacted_ranges(search_range, |file| {
24043                if let Some(file) = file {
24044                    file.is_private()
24045                        && EditorSettings::get(
24046                            Some(SettingsLocation {
24047                                worktree_id: file.worktree_id(cx),
24048                                path: file.path().as_ref(),
24049                            }),
24050                            cx,
24051                        )
24052                        .redact_private_values
24053                } else {
24054                    false
24055                }
24056            })
24057            .map(|range| {
24058                range.start.to_display_point(display_snapshot)
24059                    ..range.end.to_display_point(display_snapshot)
24060            })
24061            .collect()
24062    }
24063
24064    pub fn highlight_text_key(
24065        &mut self,
24066        key: HighlightKey,
24067        ranges: Vec<Range<Anchor>>,
24068        style: HighlightStyle,
24069        merge: bool,
24070        cx: &mut Context<Self>,
24071    ) {
24072        self.display_map.update(cx, |map, cx| {
24073            map.highlight_text(key, ranges, style, merge, cx);
24074        });
24075        cx.notify();
24076    }
24077
24078    pub fn highlight_text(
24079        &mut self,
24080        key: HighlightKey,
24081        ranges: Vec<Range<Anchor>>,
24082        style: HighlightStyle,
24083        cx: &mut Context<Self>,
24084    ) {
24085        self.display_map.update(cx, |map, cx| {
24086            map.highlight_text(key, ranges, style, false, cx)
24087        });
24088        cx.notify();
24089    }
24090
24091    pub fn text_highlights<'a>(
24092        &'a self,
24093        key: HighlightKey,
24094        cx: &'a App,
24095    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24096        self.display_map.read(cx).text_highlights(key)
24097    }
24098
24099    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24100        let cleared = self
24101            .display_map
24102            .update(cx, |map, _| map.clear_highlights(key));
24103        if cleared {
24104            cx.notify();
24105        }
24106    }
24107
24108    pub fn clear_highlights_with(
24109        &mut self,
24110        f: &mut dyn FnMut(&HighlightKey) -> bool,
24111        cx: &mut Context<Self>,
24112    ) {
24113        let cleared = self
24114            .display_map
24115            .update(cx, |map, _| map.clear_highlights_with(f));
24116        if cleared {
24117            cx.notify();
24118        }
24119    }
24120
24121    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24122        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24123            && self.focus_handle.is_focused(window)
24124    }
24125
24126    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24127        self.show_cursor_when_unfocused = is_enabled;
24128        cx.notify();
24129    }
24130
24131    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24132        cx.notify();
24133    }
24134
24135    fn on_debug_session_event(
24136        &mut self,
24137        _session: Entity<Session>,
24138        event: &SessionEvent,
24139        cx: &mut Context<Self>,
24140    ) {
24141        if let SessionEvent::InvalidateInlineValue = event {
24142            self.refresh_inline_values(cx);
24143        }
24144    }
24145
24146    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24147        let Some(semantics) = self.semantics_provider.clone() else {
24148            return;
24149        };
24150
24151        if !self.inline_value_cache.enabled {
24152            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24153            self.splice_inlays(&inlays, Vec::new(), cx);
24154            return;
24155        }
24156
24157        let current_execution_position = self
24158            .highlighted_rows
24159            .get(&TypeId::of::<ActiveDebugLine>())
24160            .and_then(|lines| lines.last().map(|line| line.range.end));
24161
24162        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24163            let inline_values = editor
24164                .update(cx, |editor, cx| {
24165                    let Some(current_execution_position) = current_execution_position else {
24166                        return Some(Task::ready(Ok(Vec::new())));
24167                    };
24168
24169                    let (buffer, buffer_anchor) =
24170                        editor.buffer.read_with(cx, |multibuffer, cx| {
24171                            let multibuffer_snapshot = multibuffer.snapshot(cx);
24172                            let (buffer_anchor, _) = multibuffer_snapshot
24173                                .anchor_to_buffer_anchor(current_execution_position)?;
24174                            let buffer = multibuffer.buffer(buffer_anchor.buffer_id)?;
24175                            Some((buffer, buffer_anchor))
24176                        })?;
24177
24178                    let range = buffer.read(cx).anchor_before(0)..buffer_anchor;
24179
24180                    semantics.inline_values(buffer, range, cx)
24181                })
24182                .ok()
24183                .flatten()?
24184                .await
24185                .context("refreshing debugger inlays")
24186                .log_err()?;
24187
24188            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24189
24190            for (buffer_id, inline_value) in inline_values
24191                .into_iter()
24192                .map(|hint| (hint.position.buffer_id, hint))
24193            {
24194                buffer_inline_values
24195                    .entry(buffer_id)
24196                    .or_default()
24197                    .push(inline_value);
24198            }
24199
24200            editor
24201                .update(cx, |editor, cx| {
24202                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24203                    let mut new_inlays = Vec::default();
24204
24205                    for (_buffer_id, inline_values) in buffer_inline_values {
24206                        for hint in inline_values {
24207                            let Some(anchor) = snapshot.anchor_in_excerpt(hint.position) else {
24208                                continue;
24209                            };
24210                            let inlay = Inlay::debugger(
24211                                post_inc(&mut editor.next_inlay_id),
24212                                anchor,
24213                                hint.text(),
24214                            );
24215                            if !inlay.text().chars().contains(&'\n') {
24216                                new_inlays.push(inlay);
24217                            }
24218                        }
24219                    }
24220
24221                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24222                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24223
24224                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24225                })
24226                .ok()?;
24227            Some(())
24228        });
24229    }
24230
24231    fn on_buffer_event(
24232        &mut self,
24233        multibuffer: &Entity<MultiBuffer>,
24234        event: &multi_buffer::Event,
24235        window: &mut Window,
24236        cx: &mut Context<Self>,
24237    ) {
24238        match event {
24239            multi_buffer::Event::Edited {
24240                edited_buffer,
24241                is_local,
24242            } => {
24243                self.scrollbar_marker_state.dirty = true;
24244                self.active_indent_guides_state.dirty = true;
24245                self.refresh_active_diagnostics(cx);
24246                self.refresh_code_actions(window, cx);
24247                self.refresh_single_line_folds(window, cx);
24248                let snapshot = self.snapshot(window, cx);
24249                self.refresh_matching_bracket_highlights(&snapshot, cx);
24250                self.refresh_outline_symbols_at_cursor(cx);
24251                self.refresh_sticky_headers(&snapshot, cx);
24252                if *is_local && self.has_active_edit_prediction() {
24253                    self.update_visible_edit_prediction(window, cx);
24254                }
24255
24256                // Clean up orphaned review comments after edits
24257                self.cleanup_orphaned_review_comments(cx);
24258
24259                if let Some(buffer) = edited_buffer {
24260                    if buffer.read(cx).file().is_none() {
24261                        cx.emit(EditorEvent::TitleChanged);
24262                    }
24263
24264                    if self.project.is_some() {
24265                        let buffer_id = buffer.read(cx).remote_id();
24266                        self.register_buffer(buffer_id, cx);
24267                        self.update_lsp_data(Some(buffer_id), window, cx);
24268                        self.refresh_inlay_hints(
24269                            InlayHintRefreshReason::BufferEdited(buffer_id),
24270                            cx,
24271                        );
24272                    }
24273                }
24274
24275                cx.emit(EditorEvent::BufferEdited);
24276                cx.emit(SearchEvent::MatchesInvalidated);
24277
24278                let Some(project) = &self.project else { return };
24279                let (telemetry, is_via_ssh) = {
24280                    let project = project.read(cx);
24281                    let telemetry = project.client().telemetry().clone();
24282                    let is_via_ssh = project.is_via_remote_server();
24283                    (telemetry, is_via_ssh)
24284                };
24285                telemetry.log_edit_event("editor", is_via_ssh);
24286            }
24287            multi_buffer::Event::BufferRangesUpdated {
24288                buffer,
24289                ranges,
24290                path_key,
24291            } => {
24292                self.refresh_document_highlights(cx);
24293                let buffer_id = buffer.read(cx).remote_id();
24294                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24295                    && let Some(project) = &self.project
24296                {
24297                    update_uncommitted_diff_for_buffer(
24298                        cx.entity(),
24299                        project,
24300                        [buffer.clone()],
24301                        self.buffer.clone(),
24302                        cx,
24303                    )
24304                    .detach();
24305                }
24306                self.register_visible_buffers(cx);
24307                self.update_lsp_data(Some(buffer_id), window, cx);
24308                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24309                self.refresh_runnables(None, window, cx);
24310                self.bracket_fetched_tree_sitter_chunks
24311                    .retain(|range, _| range.start.buffer_id != buffer_id);
24312                self.colorize_brackets(false, cx);
24313                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24314                self.semantic_token_state.invalidate_buffer(&buffer_id);
24315                cx.emit(EditorEvent::BufferRangesUpdated {
24316                    buffer: buffer.clone(),
24317                    ranges: ranges.clone(),
24318                    path_key: path_key.clone(),
24319                });
24320            }
24321            multi_buffer::Event::BuffersRemoved { removed_buffer_ids } => {
24322                if let Some(inlay_hints) = &mut self.inlay_hints {
24323                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24324                }
24325                self.refresh_inlay_hints(
24326                    InlayHintRefreshReason::BuffersRemoved(removed_buffer_ids.clone()),
24327                    cx,
24328                );
24329                for buffer_id in removed_buffer_ids {
24330                    self.registered_buffers.remove(buffer_id);
24331                    self.clear_runnables(Some(*buffer_id));
24332                    self.semantic_token_state.invalidate_buffer(buffer_id);
24333                    self.display_map.update(cx, |display_map, cx| {
24334                        display_map.invalidate_semantic_highlights(*buffer_id);
24335                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24336                    });
24337                }
24338
24339                self.display_map.update(cx, |display_map, cx| {
24340                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24341                });
24342
24343                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24344                cx.emit(EditorEvent::BuffersRemoved {
24345                    removed_buffer_ids: removed_buffer_ids.clone(),
24346                });
24347            }
24348            multi_buffer::Event::BuffersEdited { buffer_ids } => {
24349                self.display_map.update(cx, |map, cx| {
24350                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24351                });
24352                cx.emit(EditorEvent::BuffersEdited {
24353                    buffer_ids: buffer_ids.clone(),
24354                });
24355            }
24356            multi_buffer::Event::Reparsed(buffer_id) => {
24357                self.refresh_runnables(Some(*buffer_id), window, cx);
24358                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24359                self.colorize_brackets(true, cx);
24360                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24361
24362                cx.emit(EditorEvent::Reparsed(*buffer_id));
24363            }
24364            multi_buffer::Event::DiffHunksToggled => {
24365                self.refresh_runnables(None, window, cx);
24366            }
24367            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24368                if !is_fresh_language {
24369                    self.registered_buffers.remove(&buffer_id);
24370                }
24371                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24372                cx.emit(EditorEvent::Reparsed(*buffer_id));
24373                self.update_edit_prediction_settings(cx);
24374                cx.notify();
24375            }
24376            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24377            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24378            multi_buffer::Event::FileHandleChanged
24379            | multi_buffer::Event::Reloaded
24380            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24381            multi_buffer::Event::DiagnosticsUpdated => {
24382                self.update_diagnostics_state(window, cx);
24383            }
24384            _ => {}
24385        };
24386    }
24387
24388    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24389        if !self.diagnostics_enabled() {
24390            return;
24391        }
24392        self.refresh_active_diagnostics(cx);
24393        self.refresh_inline_diagnostics(true, window, cx);
24394        self.scrollbar_marker_state.dirty = true;
24395        cx.notify();
24396    }
24397
24398    pub fn start_temporary_diff_override(&mut self) {
24399        self.load_diff_task.take();
24400        self.temporary_diff_override = true;
24401    }
24402
24403    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24404        self.temporary_diff_override = false;
24405        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24406        self.buffer.update(cx, |buffer, cx| {
24407            buffer.set_all_diff_hunks_collapsed(cx);
24408        });
24409
24410        if let Some(project) = self.project.clone() {
24411            self.load_diff_task = Some(
24412                update_uncommitted_diff_for_buffer(
24413                    cx.entity(),
24414                    &project,
24415                    self.buffer.read(cx).all_buffers(),
24416                    self.buffer.clone(),
24417                    cx,
24418                )
24419                .shared(),
24420            );
24421        }
24422    }
24423
24424    fn on_display_map_changed(
24425        &mut self,
24426        _: Entity<DisplayMap>,
24427        _: &mut Window,
24428        cx: &mut Context<Self>,
24429    ) {
24430        cx.notify();
24431    }
24432
24433    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24434        if !self.mode.is_full() {
24435            return None;
24436        }
24437
24438        let theme_settings = theme_settings::ThemeSettings::get_global(cx);
24439        let theme = cx.theme();
24440        let accent_colors = theme.accents().clone();
24441
24442        let accent_overrides = theme_settings
24443            .theme_overrides
24444            .get(theme.name.as_ref())
24445            .map(|theme_style| &theme_style.accents)
24446            .into_iter()
24447            .flatten()
24448            .chain(
24449                theme_settings
24450                    .experimental_theme_overrides
24451                    .as_ref()
24452                    .map(|overrides| &overrides.accents)
24453                    .into_iter()
24454                    .flatten(),
24455            )
24456            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24457            .collect();
24458
24459        Some(AccentData {
24460            colors: accent_colors,
24461            overrides: accent_overrides,
24462        })
24463    }
24464
24465    fn fetch_applicable_language_settings(
24466        &self,
24467        cx: &App,
24468    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24469        if !self.mode.is_full() {
24470            return HashMap::default();
24471        }
24472
24473        self.buffer().read(cx).all_buffers().into_iter().fold(
24474            HashMap::default(),
24475            |mut acc, buffer| {
24476                let buffer = buffer.read(cx);
24477                let language = buffer.language().map(|language| language.name());
24478                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24479                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24480                }
24481                acc
24482            },
24483        )
24484    }
24485
24486    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24487        let new_language_settings = self.fetch_applicable_language_settings(cx);
24488        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24489        self.applicable_language_settings = new_language_settings;
24490
24491        let new_accents = self.fetch_accent_data(cx);
24492        let accents_changed = new_accents != self.accent_data;
24493        self.accent_data = new_accents;
24494
24495        if self.diagnostics_enabled() {
24496            let new_severity = EditorSettings::get_global(cx)
24497                .diagnostics_max_severity
24498                .unwrap_or(DiagnosticSeverity::Hint);
24499            self.set_max_diagnostics_severity(new_severity, cx);
24500        }
24501        self.refresh_runnables(None, window, cx);
24502        self.update_edit_prediction_settings(cx);
24503        self.refresh_edit_prediction(true, false, window, cx);
24504        self.refresh_inline_values(cx);
24505
24506        let old_cursor_shape = self.cursor_shape;
24507        let old_show_breadcrumbs = self.show_breadcrumbs;
24508
24509        {
24510            let editor_settings = EditorSettings::get_global(cx);
24511            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24512            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24513            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24514            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24515        }
24516
24517        if old_cursor_shape != self.cursor_shape {
24518            cx.emit(EditorEvent::CursorShapeChanged);
24519        }
24520
24521        if old_show_breadcrumbs != self.show_breadcrumbs {
24522            cx.emit(EditorEvent::BreadcrumbsChanged);
24523        }
24524
24525        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24526            let project_settings = ProjectSettings::get_global(cx);
24527            (
24528                project_settings.session.restore_unsaved_buffers,
24529                project_settings.diagnostics.inline.enabled,
24530                project_settings.git.inline_blame.enabled,
24531            )
24532        };
24533        self.buffer_serialization = self
24534            .should_serialize_buffer()
24535            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24536
24537        if self.mode.is_full() {
24538            if self.show_inline_diagnostics != show_inline_diagnostics {
24539                self.show_inline_diagnostics = show_inline_diagnostics;
24540                self.refresh_inline_diagnostics(false, window, cx);
24541            }
24542
24543            if self.git_blame_inline_enabled != inline_blame_enabled {
24544                self.toggle_git_blame_inline_internal(false, window, cx);
24545            }
24546
24547            let minimap_settings = EditorSettings::get_global(cx).minimap;
24548            if self.minimap_visibility != MinimapVisibility::Disabled {
24549                if self.minimap_visibility.settings_visibility()
24550                    != minimap_settings.minimap_enabled()
24551                {
24552                    self.set_minimap_visibility(
24553                        MinimapVisibility::for_mode(self.mode(), cx),
24554                        window,
24555                        cx,
24556                    );
24557                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24558                    minimap_entity.update(cx, |minimap_editor, cx| {
24559                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24560                    })
24561                }
24562            }
24563
24564            if language_settings_changed || accents_changed {
24565                self.colorize_brackets(true, cx);
24566            }
24567
24568            if language_settings_changed {
24569                self.clear_disabled_lsp_folding_ranges(window, cx);
24570                self.refresh_document_symbols(None, cx);
24571            }
24572
24573            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24574                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24575            }) {
24576                if !inlay_splice.is_empty() {
24577                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24578                }
24579                self.refresh_document_colors(None, window, cx);
24580            }
24581
24582            self.refresh_inlay_hints(
24583                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24584                    self.selections.newest_anchor().head(),
24585                    &self.buffer.read(cx).snapshot(cx),
24586                    cx,
24587                )),
24588                cx,
24589            );
24590
24591            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24592                .global_lsp_settings
24593                .semantic_token_rules
24594                .clone();
24595            let semantic_token_rules_changed = self
24596                .semantic_token_state
24597                .update_rules(new_semantic_token_rules);
24598            if language_settings_changed || semantic_token_rules_changed {
24599                self.invalidate_semantic_tokens(None);
24600                self.refresh_semantic_tokens(None, None, cx);
24601            }
24602        }
24603
24604        cx.notify();
24605    }
24606
24607    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24608        if !self.mode.is_full() {
24609            return;
24610        }
24611
24612        let new_accents = self.fetch_accent_data(cx);
24613        if new_accents != self.accent_data {
24614            self.accent_data = new_accents;
24615            self.colorize_brackets(true, cx);
24616        }
24617
24618        self.invalidate_semantic_tokens(None);
24619        self.refresh_semantic_tokens(None, None, cx);
24620    }
24621
24622    pub fn set_searchable(&mut self, searchable: bool) {
24623        self.searchable = searchable;
24624    }
24625
24626    pub fn searchable(&self) -> bool {
24627        self.searchable
24628    }
24629
24630    pub fn open_excerpts_in_split(
24631        &mut self,
24632        _: &OpenExcerptsSplit,
24633        window: &mut Window,
24634        cx: &mut Context<Self>,
24635    ) {
24636        self.open_excerpts_common(None, true, window, cx)
24637    }
24638
24639    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24640        self.open_excerpts_common(None, false, window, cx)
24641    }
24642
24643    pub(crate) fn open_excerpts_common(
24644        &mut self,
24645        jump_data: Option<JumpData>,
24646        split: bool,
24647        window: &mut Window,
24648        cx: &mut Context<Self>,
24649    ) {
24650        if self.buffer.read(cx).is_singleton() {
24651            cx.propagate();
24652            return;
24653        }
24654
24655        let mut new_selections_by_buffer = HashMap::default();
24656        match &jump_data {
24657            Some(JumpData::MultiBufferPoint {
24658                anchor,
24659                position,
24660                line_offset_from_top,
24661            }) => {
24662                if let Some(buffer) = self.buffer.read(cx).buffer(anchor.buffer_id) {
24663                    let buffer_snapshot = buffer.read(cx).snapshot();
24664                    let jump_to_point = if buffer_snapshot.can_resolve(&anchor) {
24665                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24666                    } else {
24667                        buffer_snapshot.clip_point(*position, Bias::Left)
24668                    };
24669                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24670                    new_selections_by_buffer.insert(
24671                        buffer,
24672                        (
24673                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24674                            Some(*line_offset_from_top),
24675                        ),
24676                    );
24677                }
24678            }
24679            Some(JumpData::MultiBufferRow {
24680                row,
24681                line_offset_from_top,
24682            }) => {
24683                let point = MultiBufferPoint::new(row.0, 0);
24684                if let Some((buffer, buffer_point)) =
24685                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24686                {
24687                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24688                    new_selections_by_buffer
24689                        .entry(buffer)
24690                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24691                        .0
24692                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24693                }
24694            }
24695            None => {
24696                let selections = self
24697                    .selections
24698                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24699                let multi_buffer = self.buffer.read(cx);
24700                let multi_buffer_snapshot = multi_buffer.snapshot(cx);
24701                for selection in selections {
24702                    for (snapshot, range, anchor) in multi_buffer_snapshot
24703                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24704                    {
24705                        if let Some((text_anchor, _)) = anchor.and_then(|anchor| {
24706                            multi_buffer_snapshot.anchor_to_buffer_anchor(anchor)
24707                        }) {
24708                            let Some(buffer_handle) = multi_buffer.buffer(text_anchor.buffer_id)
24709                            else {
24710                                continue;
24711                            };
24712                            let offset = text::ToOffset::to_offset(
24713                                &text_anchor,
24714                                &buffer_handle.read(cx).snapshot(),
24715                            );
24716                            let range = BufferOffset(offset)..BufferOffset(offset);
24717                            new_selections_by_buffer
24718                                .entry(buffer_handle)
24719                                .or_insert((Vec::new(), None))
24720                                .0
24721                                .push(range)
24722                        } else {
24723                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24724                            else {
24725                                continue;
24726                            };
24727                            new_selections_by_buffer
24728                                .entry(buffer_handle)
24729                                .or_insert((Vec::new(), None))
24730                                .0
24731                                .push(range)
24732                        }
24733                    }
24734                }
24735            }
24736        }
24737
24738        if self.delegate_open_excerpts {
24739            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24740                .into_iter()
24741                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24742                .collect();
24743            if !selections_by_buffer.is_empty() {
24744                cx.emit(EditorEvent::OpenExcerptsRequested {
24745                    selections_by_buffer,
24746                    split,
24747                });
24748            }
24749            return;
24750        }
24751
24752        let Some(workspace) = self.workspace() else {
24753            cx.propagate();
24754            return;
24755        };
24756
24757        new_selections_by_buffer
24758            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24759
24760        if new_selections_by_buffer.is_empty() {
24761            return;
24762        }
24763
24764        Self::open_buffers_in_workspace(
24765            workspace.downgrade(),
24766            new_selections_by_buffer,
24767            split,
24768            window,
24769            cx,
24770        );
24771    }
24772
24773    pub(crate) fn open_buffers_in_workspace(
24774        workspace: WeakEntity<Workspace>,
24775        new_selections_by_buffer: HashMap<
24776            Entity<language::Buffer>,
24777            (Vec<Range<BufferOffset>>, Option<u32>),
24778        >,
24779        split: bool,
24780        window: &mut Window,
24781        cx: &mut App,
24782    ) {
24783        // We defer the pane interaction because we ourselves are a workspace item
24784        // and activating a new item causes the pane to call a method on us reentrantly,
24785        // which panics if we're on the stack.
24786        window.defer(cx, move |window, cx| {
24787            workspace
24788                .update(cx, |workspace, cx| {
24789                    let pane = if split {
24790                        workspace.adjacent_pane(window, cx)
24791                    } else {
24792                        workspace.active_pane().clone()
24793                    };
24794
24795                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24796                        let buffer_read = buffer.read(cx);
24797                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24798                            (true, project::File::from_dyn(Some(file)).is_some())
24799                        } else {
24800                            (false, false)
24801                        };
24802
24803                        // If project file is none workspace.open_project_item will fail to open the excerpt
24804                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24805                        // so we check if there's a tab match in that case first
24806                        let editor = (!has_file || !is_project_file)
24807                            .then(|| {
24808                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24809                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24810                                // Instead, we try to activate the existing editor in the pane first.
24811                                let (editor, pane_item_index, pane_item_id) =
24812                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24813                                        let editor = item.downcast::<Editor>()?;
24814                                        let singleton_buffer =
24815                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24816                                        if singleton_buffer == buffer {
24817                                            Some((editor, i, item.item_id()))
24818                                        } else {
24819                                            None
24820                                        }
24821                                    })?;
24822                                pane.update(cx, |pane, cx| {
24823                                    pane.activate_item(pane_item_index, true, true, window, cx);
24824                                    if !PreviewTabsSettings::get_global(cx)
24825                                        .enable_preview_from_multibuffer
24826                                    {
24827                                        pane.unpreview_item_if_preview(pane_item_id);
24828                                    }
24829                                });
24830                                Some(editor)
24831                            })
24832                            .flatten()
24833                            .unwrap_or_else(|| {
24834                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24835                                    .enable_keep_preview_on_code_navigation;
24836                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24837                                    .enable_preview_from_multibuffer;
24838                                workspace.open_project_item::<Self>(
24839                                    pane.clone(),
24840                                    buffer,
24841                                    true,
24842                                    true,
24843                                    keep_old_preview,
24844                                    allow_new_preview,
24845                                    window,
24846                                    cx,
24847                                )
24848                            });
24849
24850                        editor.update(cx, |editor, cx| {
24851                            if has_file && !is_project_file {
24852                                editor.set_read_only(true);
24853                            }
24854                            let autoscroll = match scroll_offset {
24855                                Some(scroll_offset) => {
24856                                    Autoscroll::top_relative(scroll_offset as usize)
24857                                }
24858                                None => Autoscroll::newest(),
24859                            };
24860                            let nav_history = editor.nav_history.take();
24861                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24862                            let Some(buffer_snapshot) = multibuffer_snapshot.as_singleton() else {
24863                                return;
24864                            };
24865                            editor.change_selections(
24866                                SelectionEffects::scroll(autoscroll),
24867                                window,
24868                                cx,
24869                                |s| {
24870                                    s.select_ranges(ranges.into_iter().map(|range| {
24871                                        let range = buffer_snapshot.anchor_before(range.start)
24872                                            ..buffer_snapshot.anchor_after(range.end);
24873                                        multibuffer_snapshot
24874                                            .buffer_anchor_range_to_anchor_range(range)
24875                                            .unwrap()
24876                                    }));
24877                                },
24878                            );
24879                            editor.nav_history = nav_history;
24880                        });
24881                    }
24882                })
24883                .ok();
24884        });
24885    }
24886
24887    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24888        let snapshot = self.buffer.read(cx).read(cx);
24889        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24890        Some(
24891            ranges
24892                .iter()
24893                .map(move |range| {
24894                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24895                })
24896                .collect(),
24897        )
24898    }
24899
24900    fn selection_replacement_ranges(
24901        &self,
24902        range: Range<MultiBufferOffsetUtf16>,
24903        cx: &mut App,
24904    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24905        let selections = self
24906            .selections
24907            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24908        let newest_selection = selections
24909            .iter()
24910            .max_by_key(|selection| selection.id)
24911            .unwrap();
24912        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24913        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24914        let snapshot = self.buffer.read(cx).read(cx);
24915        selections
24916            .into_iter()
24917            .map(|mut selection| {
24918                selection.start.0.0 =
24919                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24920                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24921                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24922                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24923            })
24924            .collect()
24925    }
24926
24927    fn report_editor_event(
24928        &self,
24929        reported_event: ReportEditorEvent,
24930        file_extension: Option<String>,
24931        cx: &App,
24932    ) {
24933        if cfg!(any(test, feature = "test-support")) {
24934            return;
24935        }
24936
24937        let Some(project) = &self.project else { return };
24938
24939        // If None, we are in a file without an extension
24940        let file = self
24941            .buffer
24942            .read(cx)
24943            .as_singleton()
24944            .and_then(|b| b.read(cx).file());
24945        let file_extension = file_extension.or(file
24946            .as_ref()
24947            .and_then(|file| Path::new(file.file_name(cx)).extension())
24948            .and_then(|e| e.to_str())
24949            .map(|a| a.to_string()));
24950
24951        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24952            .map(|vim_mode| vim_mode.0)
24953            .unwrap_or(false);
24954
24955        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24956        let copilot_enabled = edit_predictions_provider
24957            == language::language_settings::EditPredictionProvider::Copilot;
24958        let copilot_enabled_for_language = self
24959            .buffer
24960            .read(cx)
24961            .language_settings(cx)
24962            .show_edit_predictions;
24963
24964        let project = project.read(cx);
24965        let event_type = reported_event.event_type();
24966
24967        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24968            telemetry::event!(
24969                event_type,
24970                type = if auto_saved {"autosave"} else {"manual"},
24971                file_extension,
24972                vim_mode,
24973                copilot_enabled,
24974                copilot_enabled_for_language,
24975                edit_predictions_provider,
24976                is_via_ssh = project.is_via_remote_server(),
24977            );
24978        } else {
24979            telemetry::event!(
24980                event_type,
24981                file_extension,
24982                vim_mode,
24983                copilot_enabled,
24984                copilot_enabled_for_language,
24985                edit_predictions_provider,
24986                is_via_ssh = project.is_via_remote_server(),
24987            );
24988        };
24989    }
24990
24991    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24992    /// with each line being an array of {text, highlight} objects.
24993    fn copy_highlight_json(
24994        &mut self,
24995        _: &CopyHighlightJson,
24996        _: &mut Window,
24997        cx: &mut Context<Self>,
24998    ) {
24999        #[derive(Serialize)]
25000        struct Chunk<'a> {
25001            text: String,
25002            highlight: Option<&'a str>,
25003        }
25004
25005        let snapshot = self.buffer.read(cx).snapshot(cx);
25006        let mut selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
25007        let max_point = snapshot.max_point();
25008
25009        let range = if self.selections.line_mode() {
25010            selection.start = Point::new(selection.start.row, 0);
25011            selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
25012            selection.goal = SelectionGoal::None;
25013            selection.range()
25014        } else if selection.is_empty() {
25015            Point::new(0, 0)..max_point
25016        } else {
25017            selection.range()
25018        };
25019
25020        let chunks = snapshot.chunks(
25021            range,
25022            LanguageAwareStyling {
25023                tree_sitter: true,
25024                diagnostics: true,
25025            },
25026        );
25027        let mut lines = Vec::new();
25028        let mut line: VecDeque<Chunk> = VecDeque::new();
25029
25030        let Some(style) = self.style.as_ref() else {
25031            return;
25032        };
25033
25034        for chunk in chunks {
25035            let highlight = chunk
25036                .syntax_highlight_id
25037                .and_then(|id| style.syntax.get_capture_name(id));
25038
25039            let mut chunk_lines = chunk.text.split('\n').peekable();
25040            while let Some(text) = chunk_lines.next() {
25041                let mut merged_with_last_token = false;
25042                if let Some(last_token) = line.back_mut()
25043                    && last_token.highlight == highlight
25044                {
25045                    last_token.text.push_str(text);
25046                    merged_with_last_token = true;
25047                }
25048
25049                if !merged_with_last_token {
25050                    line.push_back(Chunk {
25051                        text: text.into(),
25052                        highlight,
25053                    });
25054                }
25055
25056                if chunk_lines.peek().is_some() {
25057                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25058                        line.pop_front();
25059                    }
25060                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25061                        line.pop_back();
25062                    }
25063
25064                    lines.push(mem::take(&mut line));
25065                }
25066            }
25067        }
25068
25069        if line.iter().any(|chunk| !chunk.text.is_empty()) {
25070            lines.push(line);
25071        }
25072
25073        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25074            return;
25075        };
25076        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25077    }
25078
25079    pub fn open_context_menu(
25080        &mut self,
25081        _: &OpenContextMenu,
25082        window: &mut Window,
25083        cx: &mut Context<Self>,
25084    ) {
25085        self.request_autoscroll(Autoscroll::newest(), cx);
25086        let position = self
25087            .selections
25088            .newest_display(&self.display_snapshot(cx))
25089            .start;
25090        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25091    }
25092
25093    pub fn replay_insert_event(
25094        &mut self,
25095        text: &str,
25096        relative_utf16_range: Option<Range<isize>>,
25097        window: &mut Window,
25098        cx: &mut Context<Self>,
25099    ) {
25100        if !self.input_enabled {
25101            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25102            return;
25103        }
25104        if let Some(relative_utf16_range) = relative_utf16_range {
25105            let selections = self
25106                .selections
25107                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25108            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25109                let new_ranges = selections.into_iter().map(|range| {
25110                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25111                        range
25112                            .head()
25113                            .0
25114                            .0
25115                            .saturating_add_signed(relative_utf16_range.start),
25116                    ));
25117                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25118                        range
25119                            .head()
25120                            .0
25121                            .0
25122                            .saturating_add_signed(relative_utf16_range.end),
25123                    ));
25124                    start..end
25125                });
25126                s.select_ranges(new_ranges);
25127            });
25128        }
25129
25130        self.handle_input(text, window, cx);
25131    }
25132
25133    pub fn is_focused(&self, window: &Window) -> bool {
25134        self.focus_handle.is_focused(window)
25135    }
25136
25137    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25138        cx.emit(EditorEvent::Focused);
25139
25140        if let Some(descendant) = self
25141            .last_focused_descendant
25142            .take()
25143            .and_then(|descendant| descendant.upgrade())
25144        {
25145            window.focus(&descendant, cx);
25146        } else {
25147            if let Some(blame) = self.blame.as_ref() {
25148                blame.update(cx, GitBlame::focus)
25149            }
25150
25151            self.blink_manager.update(cx, BlinkManager::enable);
25152            self.show_cursor_names(window, cx);
25153            self.buffer.update(cx, |buffer, cx| {
25154                buffer.finalize_last_transaction(cx);
25155                if self.leader_id.is_none() {
25156                    buffer.set_active_selections(
25157                        &self.selections.disjoint_anchors_arc(),
25158                        self.selections.line_mode(),
25159                        self.cursor_shape,
25160                        cx,
25161                    );
25162                }
25163            });
25164
25165            if let Some(position_map) = self.last_position_map.clone()
25166                && !self.mouse_cursor_hidden
25167            {
25168                EditorElement::mouse_moved(
25169                    self,
25170                    &MouseMoveEvent {
25171                        position: window.mouse_position(),
25172                        pressed_button: None,
25173                        modifiers: window.modifiers(),
25174                    },
25175                    &position_map,
25176                    None,
25177                    window,
25178                    cx,
25179                );
25180            }
25181        }
25182    }
25183
25184    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25185        cx.emit(EditorEvent::FocusedIn)
25186    }
25187
25188    fn handle_focus_out(
25189        &mut self,
25190        event: FocusOutEvent,
25191        _window: &mut Window,
25192        cx: &mut Context<Self>,
25193    ) {
25194        if event.blurred != self.focus_handle {
25195            self.last_focused_descendant = Some(event.blurred);
25196        }
25197        self.selection_drag_state = SelectionDragState::None;
25198        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25199    }
25200
25201    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25202        self.blink_manager.update(cx, BlinkManager::disable);
25203        self.buffer
25204            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25205
25206        if let Some(blame) = self.blame.as_ref() {
25207            blame.update(cx, GitBlame::blur)
25208        }
25209        if !self.hover_state.focused(window, cx) {
25210            hide_hover(self, cx);
25211        }
25212        if !self
25213            .context_menu
25214            .borrow()
25215            .as_ref()
25216            .is_some_and(|context_menu| context_menu.focused(window, cx))
25217        {
25218            self.hide_context_menu(window, cx);
25219        }
25220        self.take_active_edit_prediction(true, cx);
25221        cx.emit(EditorEvent::Blurred);
25222        cx.notify();
25223    }
25224
25225    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25226        let mut pending: String = window
25227            .pending_input_keystrokes()
25228            .into_iter()
25229            .flatten()
25230            .filter_map(|keystroke| keystroke.key_char.clone())
25231            .collect();
25232
25233        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25234            pending = "".to_string();
25235        }
25236
25237        let existing_pending = self
25238            .text_highlights(HighlightKey::PendingInput, cx)
25239            .map(|(_, ranges)| ranges.to_vec());
25240        if existing_pending.is_none() && pending.is_empty() {
25241            return;
25242        }
25243        let transaction =
25244            self.transact(window, cx, |this, window, cx| {
25245                let selections = this
25246                    .selections
25247                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25248                let edits = selections
25249                    .iter()
25250                    .map(|selection| (selection.end..selection.end, pending.clone()));
25251                this.edit(edits, cx);
25252                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25253                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25254                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25255                    }));
25256                });
25257                if let Some(existing_ranges) = existing_pending {
25258                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25259                    this.edit(edits, cx);
25260                }
25261            });
25262
25263        let snapshot = self.snapshot(window, cx);
25264        let ranges = self
25265            .selections
25266            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25267            .into_iter()
25268            .map(|selection| {
25269                snapshot.buffer_snapshot().anchor_after(selection.end)
25270                    ..snapshot
25271                        .buffer_snapshot()
25272                        .anchor_before(selection.end + pending.len())
25273            })
25274            .collect();
25275
25276        if pending.is_empty() {
25277            self.clear_highlights(HighlightKey::PendingInput, cx);
25278        } else {
25279            self.highlight_text(
25280                HighlightKey::PendingInput,
25281                ranges,
25282                HighlightStyle {
25283                    underline: Some(UnderlineStyle {
25284                        thickness: px(1.),
25285                        color: None,
25286                        wavy: false,
25287                    }),
25288                    ..Default::default()
25289                },
25290                cx,
25291            );
25292        }
25293
25294        self.ime_transaction = self.ime_transaction.or(transaction);
25295        if let Some(transaction) = self.ime_transaction {
25296            self.buffer.update(cx, |buffer, cx| {
25297                buffer.group_until_transaction(transaction, cx);
25298            });
25299        }
25300
25301        if self
25302            .text_highlights(HighlightKey::PendingInput, cx)
25303            .is_none()
25304        {
25305            self.ime_transaction.take();
25306        }
25307    }
25308
25309    pub fn register_action_renderer(
25310        &mut self,
25311        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25312    ) -> Subscription {
25313        let id = self.next_editor_action_id.post_inc();
25314        self.editor_actions
25315            .borrow_mut()
25316            .insert(id, Box::new(listener));
25317
25318        let editor_actions = self.editor_actions.clone();
25319        Subscription::new(move || {
25320            editor_actions.borrow_mut().remove(&id);
25321        })
25322    }
25323
25324    pub fn register_action<A: Action>(
25325        &mut self,
25326        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25327    ) -> Subscription {
25328        let id = self.next_editor_action_id.post_inc();
25329        let listener = Arc::new(listener);
25330        self.editor_actions.borrow_mut().insert(
25331            id,
25332            Box::new(move |_, window, _| {
25333                let listener = listener.clone();
25334                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25335                    let action = action.downcast_ref().unwrap();
25336                    if phase == DispatchPhase::Bubble {
25337                        listener(action, window, cx)
25338                    }
25339                })
25340            }),
25341        );
25342
25343        let editor_actions = self.editor_actions.clone();
25344        Subscription::new(move || {
25345            editor_actions.borrow_mut().remove(&id);
25346        })
25347    }
25348
25349    pub fn file_header_size(&self) -> u32 {
25350        FILE_HEADER_HEIGHT
25351    }
25352
25353    pub fn restore(
25354        &mut self,
25355        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25356        window: &mut Window,
25357        cx: &mut Context<Self>,
25358    ) {
25359        self.buffer().update(cx, |multi_buffer, cx| {
25360            for (buffer_id, changes) in revert_changes {
25361                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25362                    buffer.update(cx, |buffer, cx| {
25363                        buffer.edit(
25364                            changes
25365                                .into_iter()
25366                                .map(|(range, text)| (range, text.to_string())),
25367                            None,
25368                            cx,
25369                        );
25370                    });
25371                }
25372            }
25373        });
25374        let selections = self
25375            .selections
25376            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
25377        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25378            s.select(selections);
25379        });
25380    }
25381
25382    pub fn to_pixel_point(
25383        &mut self,
25384        source: Anchor,
25385        editor_snapshot: &EditorSnapshot,
25386        window: &mut Window,
25387        cx: &mut App,
25388    ) -> Option<gpui::Point<Pixels>> {
25389        let source_point = source.to_display_point(editor_snapshot);
25390        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25391    }
25392
25393    pub fn display_to_pixel_point(
25394        &mut self,
25395        source: DisplayPoint,
25396        editor_snapshot: &EditorSnapshot,
25397        window: &mut Window,
25398        cx: &mut App,
25399    ) -> Option<gpui::Point<Pixels>> {
25400        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25401        let text_layout_details = self.text_layout_details(window, cx);
25402        let scroll_top = text_layout_details
25403            .scroll_anchor
25404            .scroll_position(editor_snapshot)
25405            .y;
25406
25407        if source.row().as_f64() < scroll_top.floor() {
25408            return None;
25409        }
25410        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25411        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25412        Some(gpui::Point::new(source_x, source_y))
25413    }
25414
25415    pub fn has_visible_completions_menu(&self) -> bool {
25416        !self.edit_prediction_preview_is_active()
25417            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25418                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25419            })
25420    }
25421
25422    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25423        if self.mode.is_minimap() {
25424            return;
25425        }
25426        self.addons
25427            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25428    }
25429
25430    pub fn unregister_addon<T: Addon>(&mut self) {
25431        self.addons.remove(&std::any::TypeId::of::<T>());
25432    }
25433
25434    pub fn addon<T: Addon>(&self) -> Option<&T> {
25435        let type_id = std::any::TypeId::of::<T>();
25436        self.addons
25437            .get(&type_id)
25438            .and_then(|item| item.to_any().downcast_ref::<T>())
25439    }
25440
25441    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25442        let type_id = std::any::TypeId::of::<T>();
25443        self.addons
25444            .get_mut(&type_id)
25445            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25446    }
25447
25448    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25449        let text_layout_details = self.text_layout_details(window, cx);
25450        let style = &text_layout_details.editor_style;
25451        let font_id = window.text_system().resolve_font(&style.text.font());
25452        let font_size = style.text.font_size.to_pixels(window.rem_size());
25453        let line_height = style.text.line_height_in_pixels(window.rem_size());
25454        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25455        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25456
25457        CharacterDimensions {
25458            em_width,
25459            em_advance,
25460            line_height,
25461        }
25462    }
25463
25464    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25465        self.load_diff_task.clone()
25466    }
25467
25468    fn read_metadata_from_db(
25469        &mut self,
25470        item_id: u64,
25471        workspace_id: WorkspaceId,
25472        window: &mut Window,
25473        cx: &mut Context<Editor>,
25474    ) {
25475        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25476            && !self.mode.is_minimap()
25477            && WorkspaceSettings::get(None, cx).restore_on_startup
25478                != RestoreOnStartupBehavior::EmptyTab
25479        {
25480            let buffer_snapshot = OnceCell::new();
25481
25482            // Get file path for path-based fold lookup
25483            let file_path: Option<Arc<Path>> =
25484                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25485                    project::File::from_dyn(buffer.read(cx).file())
25486                        .map(|file| Arc::from(file.abs_path(cx)))
25487                });
25488
25489            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25490            let db = EditorDb::global(cx);
25491            let (folds, needs_migration) = if let Some(ref path) = file_path {
25492                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25493                    && !folds.is_empty()
25494                {
25495                    (Some(folds), false)
25496                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25497                    && !folds.is_empty()
25498                {
25499                    // Found old editor_folds data, will migrate to file_folds
25500                    (Some(folds), true)
25501                } else {
25502                    (None, false)
25503                }
25504            } else {
25505                // No file path, try editor_folds as fallback
25506                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25507                (folds.filter(|f| !f.is_empty()), false)
25508            };
25509
25510            if let Some(folds) = folds {
25511                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25512                let snapshot_len = snapshot.len().0;
25513
25514                // Helper: search for fingerprint in buffer, return offset if found
25515                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25516                    // Ensure we start at a character boundary (defensive)
25517                    let search_start = snapshot
25518                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25519                        .0;
25520                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25521
25522                    let mut byte_offset = search_start;
25523                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25524                        if byte_offset > search_end {
25525                            break;
25526                        }
25527                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25528                            return Some(byte_offset);
25529                        }
25530                        byte_offset += ch.len_utf8();
25531                    }
25532                    None
25533                };
25534
25535                // Track search position to handle duplicate fingerprints correctly.
25536                // Folds are stored in document order, so we advance after each match.
25537                let mut search_start = 0usize;
25538
25539                // Collect db_folds for migration (only folds with valid fingerprints)
25540                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25541
25542                let valid_folds: Vec<_> = folds
25543                    .into_iter()
25544                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25545                        // Skip folds without fingerprints (old data before migration)
25546                        let sfp = start_fp?;
25547                        let efp = end_fp?;
25548                        let efp_len = efp.len();
25549
25550                        // Fast path: check if fingerprints match at stored offsets
25551                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25552                        let start_matches = stored_start < snapshot_len
25553                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25554                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25555                        let end_matches = efp_check_pos >= stored_start
25556                            && stored_end <= snapshot_len
25557                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25558
25559                        let (new_start, new_end) = if start_matches && end_matches {
25560                            // Offsets unchanged, use stored values
25561                            (stored_start, stored_end)
25562                        } else if sfp == efp {
25563                            // Short fold: identical fingerprints can only match once per search
25564                            // Use stored fold length to compute new_end
25565                            let new_start = find_fingerprint(&sfp, search_start)?;
25566                            let fold_len = stored_end - stored_start;
25567                            let new_end = new_start + fold_len;
25568                            (new_start, new_end)
25569                        } else {
25570                            // Slow path: search for fingerprints in buffer
25571                            let new_start = find_fingerprint(&sfp, search_start)?;
25572                            // Search for end_fp after start, then add efp_len to get actual fold end
25573                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25574                            let new_end = efp_pos + efp_len;
25575                            (new_start, new_end)
25576                        };
25577
25578                        // Advance search position for next fold
25579                        search_start = new_end;
25580
25581                        // Validate fold makes sense (end must be after start)
25582                        if new_end <= new_start {
25583                            return None;
25584                        }
25585
25586                        // Collect for migration if needed
25587                        if needs_migration {
25588                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25589                        }
25590
25591                        Some(
25592                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25593                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25594                        )
25595                    })
25596                    .collect();
25597
25598                if !valid_folds.is_empty() {
25599                    self.fold_ranges(valid_folds, false, window, cx);
25600
25601                    // Migrate from editor_folds to file_folds if we loaded from old table
25602                    if needs_migration {
25603                        if let Some(ref path) = file_path {
25604                            let path = path.clone();
25605                            let db = EditorDb::global(cx);
25606                            cx.spawn(async move |_, _| {
25607                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25608                                    .await
25609                                    .log_err();
25610                            })
25611                            .detach();
25612                        }
25613                    }
25614                }
25615            }
25616
25617            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25618                && !selections.is_empty()
25619            {
25620                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25621                // skip adding the initial selection to selection history
25622                self.selection_history.mode = SelectionHistoryMode::Skipping;
25623                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25624                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25625                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25626                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25627                    }));
25628                });
25629                self.selection_history.mode = SelectionHistoryMode::Normal;
25630            };
25631        }
25632
25633        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25634    }
25635
25636    /// Load folds from the file_folds database table by file path.
25637    /// Used when manually opening a file that was previously closed.
25638    fn load_folds_from_db(
25639        &mut self,
25640        workspace_id: WorkspaceId,
25641        file_path: PathBuf,
25642        window: &mut Window,
25643        cx: &mut Context<Editor>,
25644    ) {
25645        if self.mode.is_minimap()
25646            || WorkspaceSettings::get(None, cx).restore_on_startup
25647                == RestoreOnStartupBehavior::EmptyTab
25648        {
25649            return;
25650        }
25651
25652        let Some(folds) = EditorDb::global(cx)
25653            .get_file_folds(workspace_id, &file_path)
25654            .log_err()
25655        else {
25656            return;
25657        };
25658        if folds.is_empty() {
25659            return;
25660        }
25661
25662        let snapshot = self.buffer.read(cx).snapshot(cx);
25663        let snapshot_len = snapshot.len().0;
25664
25665        // Helper: search for fingerprint in buffer, return offset if found
25666        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25667            let search_start = snapshot
25668                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25669                .0;
25670            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25671
25672            let mut byte_offset = search_start;
25673            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25674                if byte_offset > search_end {
25675                    break;
25676                }
25677                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25678                    return Some(byte_offset);
25679                }
25680                byte_offset += ch.len_utf8();
25681            }
25682            None
25683        };
25684
25685        let mut search_start = 0usize;
25686
25687        let valid_folds: Vec<_> = folds
25688            .into_iter()
25689            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25690                let sfp = start_fp?;
25691                let efp = end_fp?;
25692                let efp_len = efp.len();
25693
25694                let start_matches = stored_start < snapshot_len
25695                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25696                let efp_check_pos = stored_end.saturating_sub(efp_len);
25697                let end_matches = efp_check_pos >= stored_start
25698                    && stored_end <= snapshot_len
25699                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25700
25701                let (new_start, new_end) = if start_matches && end_matches {
25702                    (stored_start, stored_end)
25703                } else if sfp == efp {
25704                    let new_start = find_fingerprint(&sfp, search_start)?;
25705                    let fold_len = stored_end - stored_start;
25706                    let new_end = new_start + fold_len;
25707                    (new_start, new_end)
25708                } else {
25709                    let new_start = find_fingerprint(&sfp, search_start)?;
25710                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25711                    let new_end = efp_pos + efp_len;
25712                    (new_start, new_end)
25713                };
25714
25715                search_start = new_end;
25716
25717                if new_end <= new_start {
25718                    return None;
25719                }
25720
25721                Some(
25722                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25723                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25724                )
25725            })
25726            .collect();
25727
25728        if !valid_folds.is_empty() {
25729            self.fold_ranges(valid_folds, false, window, cx);
25730        }
25731    }
25732
25733    fn lsp_data_enabled(&self) -> bool {
25734        self.enable_lsp_data && self.mode().is_full()
25735    }
25736
25737    fn update_lsp_data(
25738        &mut self,
25739        for_buffer: Option<BufferId>,
25740        window: &mut Window,
25741        cx: &mut Context<'_, Self>,
25742    ) {
25743        if !self.lsp_data_enabled() {
25744            return;
25745        }
25746
25747        if let Some(buffer_id) = for_buffer {
25748            self.pull_diagnostics(buffer_id, window, cx);
25749        }
25750        self.refresh_semantic_tokens(for_buffer, None, cx);
25751        self.refresh_document_colors(for_buffer, window, cx);
25752        self.refresh_folding_ranges(for_buffer, window, cx);
25753        self.refresh_document_symbols(for_buffer, cx);
25754    }
25755
25756    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25757        if !self.lsp_data_enabled() {
25758            return;
25759        }
25760        let visible_buffers: Vec<_> = self
25761            .visible_buffers(cx)
25762            .into_iter()
25763            .filter(|buffer| self.is_lsp_relevant(buffer.read(cx).file(), cx))
25764            .collect();
25765        for visible_buffer in visible_buffers {
25766            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25767        }
25768    }
25769
25770    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25771        if !self.lsp_data_enabled() {
25772            return;
25773        }
25774
25775        if !self.registered_buffers.contains_key(&buffer_id)
25776            && let Some(project) = self.project.as_ref()
25777        {
25778            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25779                project.update(cx, |project, cx| {
25780                    self.registered_buffers.insert(
25781                        buffer_id,
25782                        project.register_buffer_with_language_servers(&buffer, cx),
25783                    );
25784                });
25785            } else {
25786                self.registered_buffers.remove(&buffer_id);
25787            }
25788        }
25789    }
25790
25791    fn create_style(&self, cx: &App) -> EditorStyle {
25792        let settings = ThemeSettings::get_global(cx);
25793
25794        let mut text_style = match self.mode {
25795            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25796                color: cx.theme().colors().editor_foreground,
25797                font_family: settings.ui_font.family.clone(),
25798                font_features: settings.ui_font.features.clone(),
25799                font_fallbacks: settings.ui_font.fallbacks.clone(),
25800                font_size: rems(0.875).into(),
25801                font_weight: settings.ui_font.weight,
25802                line_height: relative(settings.buffer_line_height.value()),
25803                ..Default::default()
25804            },
25805            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25806                color: cx.theme().colors().editor_foreground,
25807                font_family: settings.buffer_font.family.clone(),
25808                font_features: settings.buffer_font.features.clone(),
25809                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25810                font_size: settings.buffer_font_size(cx).into(),
25811                font_weight: settings.buffer_font.weight,
25812                line_height: relative(settings.buffer_line_height.value()),
25813                ..Default::default()
25814            },
25815        };
25816        if let Some(text_style_refinement) = &self.text_style_refinement {
25817            text_style.refine(text_style_refinement)
25818        }
25819
25820        let background = match self.mode {
25821            EditorMode::SingleLine => cx.theme().system().transparent,
25822            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25823            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25824            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25825        };
25826
25827        EditorStyle {
25828            background,
25829            border: cx.theme().colors().border,
25830            local_player: cx.theme().players().local(),
25831            text: text_style,
25832            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25833            syntax: cx.theme().syntax().clone(),
25834            status: cx.theme().status().clone(),
25835            inlay_hints_style: make_inlay_hints_style(cx),
25836            edit_prediction_styles: make_suggestion_styles(cx),
25837            unnecessary_code_fade: settings.unnecessary_code_fade,
25838            show_underlines: self.diagnostics_enabled(),
25839        }
25840    }
25841
25842    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25843        let multibuffer = self.buffer().read(cx);
25844        let is_singleton = multibuffer.is_singleton();
25845        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25846        let buffer = multibuffer.buffer(*buffer_id)?;
25847
25848        let buffer = buffer.read(cx);
25849        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25850        let mut breadcrumbs = if is_singleton {
25851            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25852                buffer
25853                    .snapshot()
25854                    .resolve_file_path(
25855                        self.project
25856                            .as_ref()
25857                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25858                            .unwrap_or_default(),
25859                        cx,
25860                    )
25861                    .unwrap_or_else(|| {
25862                        if multibuffer.is_singleton() {
25863                            multibuffer.title(cx).to_string()
25864                        } else {
25865                            "untitled".to_string()
25866                        }
25867                    })
25868            });
25869            vec![HighlightedText {
25870                text: text.into(),
25871                highlights: vec![],
25872            }]
25873        } else {
25874            vec![]
25875        };
25876
25877        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25878            text: symbol.text.clone().into(),
25879            highlights: symbol.highlight_ranges.clone(),
25880        }));
25881        Some(breadcrumbs)
25882    }
25883
25884    fn disable_lsp_data(&mut self) {
25885        self.enable_lsp_data = false;
25886    }
25887
25888    fn disable_runnables(&mut self) {
25889        self.enable_runnables = false;
25890    }
25891
25892    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25893        self.register_visible_buffers(cx);
25894        self.colorize_brackets(false, cx);
25895        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25896        if !self.buffer().read(cx).is_singleton() {
25897            self.update_lsp_data(None, window, cx);
25898            self.refresh_runnables(None, window, cx);
25899        }
25900    }
25901}
25902
25903fn edit_for_markdown_paste<'a>(
25904    buffer: &MultiBufferSnapshot,
25905    range: Range<MultiBufferOffset>,
25906    to_insert: &'a str,
25907    url: Option<url::Url>,
25908) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25909    if url.is_none() {
25910        return (range, Cow::Borrowed(to_insert));
25911    };
25912
25913    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25914
25915    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25916        Cow::Borrowed(to_insert)
25917    } else {
25918        Cow::Owned(format!("[{old_text}]({to_insert})"))
25919    };
25920    (range, new_text)
25921}
25922
25923fn process_completion_for_edit(
25924    completion: &Completion,
25925    intent: CompletionIntent,
25926    buffer: &Entity<Buffer>,
25927    cursor_position: &text::Anchor,
25928    cx: &mut Context<Editor>,
25929) -> CompletionEdit {
25930    let buffer = buffer.read(cx);
25931    let buffer_snapshot = buffer.snapshot();
25932    let (snippet, new_text) = if completion.is_snippet() {
25933        let mut snippet_source = completion.new_text.clone();
25934        // Workaround for typescript language server issues so that methods don't expand within
25935        // strings and functions with type expressions. The previous point is used because the query
25936        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25937        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25938        let previous_point = if previous_point.column > 0 {
25939            cursor_position.to_previous_offset(&buffer_snapshot)
25940        } else {
25941            cursor_position.to_offset(&buffer_snapshot)
25942        };
25943        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25944            && scope.prefers_label_for_snippet_in_completion()
25945            && let Some(label) = completion.label()
25946            && matches!(
25947                completion.kind(),
25948                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25949            )
25950        {
25951            snippet_source = label;
25952        }
25953        match Snippet::parse(&snippet_source).log_err() {
25954            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25955            None => (None, completion.new_text.clone()),
25956        }
25957    } else {
25958        (None, completion.new_text.clone())
25959    };
25960
25961    let mut range_to_replace = {
25962        let replace_range = &completion.replace_range;
25963        if let CompletionSource::Lsp {
25964            insert_range: Some(insert_range),
25965            ..
25966        } = &completion.source
25967        {
25968            debug_assert_eq!(
25969                insert_range.start, replace_range.start,
25970                "insert_range and replace_range should start at the same position"
25971            );
25972            debug_assert!(
25973                insert_range
25974                    .start
25975                    .cmp(cursor_position, &buffer_snapshot)
25976                    .is_le(),
25977                "insert_range should start before or at cursor position"
25978            );
25979            debug_assert!(
25980                replace_range
25981                    .start
25982                    .cmp(cursor_position, &buffer_snapshot)
25983                    .is_le(),
25984                "replace_range should start before or at cursor position"
25985            );
25986
25987            let should_replace = match intent {
25988                CompletionIntent::CompleteWithInsert => false,
25989                CompletionIntent::CompleteWithReplace => true,
25990                CompletionIntent::Complete | CompletionIntent::Compose => {
25991                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
25992                        .completions
25993                        .lsp_insert_mode;
25994                    match insert_mode {
25995                        LspInsertMode::Insert => false,
25996                        LspInsertMode::Replace => true,
25997                        LspInsertMode::ReplaceSubsequence => {
25998                            let mut text_to_replace = buffer.chars_for_range(
25999                                buffer.anchor_before(replace_range.start)
26000                                    ..buffer.anchor_after(replace_range.end),
26001                            );
26002                            let mut current_needle = text_to_replace.next();
26003                            for haystack_ch in completion.label.text.chars() {
26004                                if let Some(needle_ch) = current_needle
26005                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
26006                                {
26007                                    current_needle = text_to_replace.next();
26008                                }
26009                            }
26010                            current_needle.is_none()
26011                        }
26012                        LspInsertMode::ReplaceSuffix => {
26013                            if replace_range
26014                                .end
26015                                .cmp(cursor_position, &buffer_snapshot)
26016                                .is_gt()
26017                            {
26018                                let range_after_cursor = *cursor_position..replace_range.end;
26019                                let text_after_cursor = buffer
26020                                    .text_for_range(
26021                                        buffer.anchor_before(range_after_cursor.start)
26022                                            ..buffer.anchor_after(range_after_cursor.end),
26023                                    )
26024                                    .collect::<String>()
26025                                    .to_ascii_lowercase();
26026                                completion
26027                                    .label
26028                                    .text
26029                                    .to_ascii_lowercase()
26030                                    .ends_with(&text_after_cursor)
26031                            } else {
26032                                true
26033                            }
26034                        }
26035                    }
26036                }
26037            };
26038
26039            if should_replace {
26040                replace_range.clone()
26041            } else {
26042                insert_range.clone()
26043            }
26044        } else {
26045            replace_range.clone()
26046        }
26047    };
26048
26049    if range_to_replace
26050        .end
26051        .cmp(cursor_position, &buffer_snapshot)
26052        .is_lt()
26053    {
26054        range_to_replace.end = *cursor_position;
26055    }
26056
26057    CompletionEdit {
26058        new_text,
26059        replace_range: range_to_replace,
26060        snippet,
26061    }
26062}
26063
26064struct CompletionEdit {
26065    new_text: String,
26066    replace_range: Range<text::Anchor>,
26067    snippet: Option<Snippet>,
26068}
26069
26070fn comment_delimiter_for_newline(
26071    start_point: &Point,
26072    buffer: &MultiBufferSnapshot,
26073    language: &LanguageScope,
26074) -> Option<Arc<str>> {
26075    let delimiters = language.line_comment_prefixes();
26076    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26077    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26078
26079    let num_of_whitespaces = snapshot
26080        .chars_for_range(range.clone())
26081        .take_while(|c| c.is_whitespace())
26082        .count();
26083    let comment_candidate = snapshot
26084        .chars_for_range(range.clone())
26085        .skip(num_of_whitespaces)
26086        .take(max_len_of_delimiter + 2)
26087        .collect::<String>();
26088    let (delimiter, trimmed_len, is_repl) = delimiters
26089        .iter()
26090        .filter_map(|delimiter| {
26091            let prefix = delimiter.trim_end();
26092            if comment_candidate.starts_with(prefix) {
26093                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26094                {
26095                    stripped_comment.starts_with(" %%")
26096                } else {
26097                    false
26098                };
26099                Some((delimiter, prefix.len(), is_repl))
26100            } else {
26101                None
26102            }
26103        })
26104        .max_by_key(|(_, len, _)| *len)?;
26105
26106    if let Some(BlockCommentConfig {
26107        start: block_start, ..
26108    }) = language.block_comment()
26109    {
26110        let block_start_trimmed = block_start.trim_end();
26111        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26112            let line_content = snapshot
26113                .chars_for_range(range.clone())
26114                .skip(num_of_whitespaces)
26115                .take(block_start_trimmed.len())
26116                .collect::<String>();
26117
26118            if line_content.starts_with(block_start_trimmed) {
26119                return None;
26120            }
26121        }
26122    }
26123
26124    let cursor_is_placed_after_comment_marker =
26125        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26126    if cursor_is_placed_after_comment_marker {
26127        if !is_repl {
26128            return Some(delimiter.clone());
26129        }
26130
26131        let line_content_after_cursor: String = snapshot
26132            .chars_for_range(range)
26133            .skip(start_point.column as usize)
26134            .collect();
26135
26136        if line_content_after_cursor.trim().is_empty() {
26137            return None;
26138        } else {
26139            return Some(delimiter.clone());
26140        }
26141    } else {
26142        None
26143    }
26144}
26145
26146fn documentation_delimiter_for_newline(
26147    start_point: &Point,
26148    buffer: &MultiBufferSnapshot,
26149    language: &LanguageScope,
26150    newline_config: &mut NewlineConfig,
26151) -> Option<Arc<str>> {
26152    let BlockCommentConfig {
26153        start: start_tag,
26154        end: end_tag,
26155        prefix: delimiter,
26156        tab_size: len,
26157    } = language.documentation_comment()?;
26158    let is_within_block_comment = buffer
26159        .language_scope_at(*start_point)
26160        .is_some_and(|scope| scope.override_name() == Some("comment"));
26161    if !is_within_block_comment {
26162        return None;
26163    }
26164
26165    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26166
26167    let num_of_whitespaces = snapshot
26168        .chars_for_range(range.clone())
26169        .take_while(|c| c.is_whitespace())
26170        .count();
26171
26172    // 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.
26173    let column = start_point.column;
26174    let cursor_is_after_start_tag = {
26175        let start_tag_len = start_tag.len();
26176        let start_tag_line = snapshot
26177            .chars_for_range(range.clone())
26178            .skip(num_of_whitespaces)
26179            .take(start_tag_len)
26180            .collect::<String>();
26181        if start_tag_line.starts_with(start_tag.as_ref()) {
26182            num_of_whitespaces + start_tag_len <= column as usize
26183        } else {
26184            false
26185        }
26186    };
26187
26188    let cursor_is_after_delimiter = {
26189        let delimiter_trim = delimiter.trim_end();
26190        let delimiter_line = snapshot
26191            .chars_for_range(range.clone())
26192            .skip(num_of_whitespaces)
26193            .take(delimiter_trim.len())
26194            .collect::<String>();
26195        if delimiter_line.starts_with(delimiter_trim) {
26196            num_of_whitespaces + delimiter_trim.len() <= column as usize
26197        } else {
26198            false
26199        }
26200    };
26201
26202    let mut needs_extra_line = false;
26203    let mut extra_line_additional_indent = IndentSize::spaces(0);
26204
26205    let cursor_is_before_end_tag_if_exists = {
26206        let mut char_position = 0u32;
26207        let mut end_tag_offset = None;
26208
26209        'outer: for chunk in snapshot.text_for_range(range) {
26210            if let Some(byte_pos) = chunk.find(&**end_tag) {
26211                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26212                end_tag_offset = Some(char_position + chars_before_match);
26213                break 'outer;
26214            }
26215            char_position += chunk.chars().count() as u32;
26216        }
26217
26218        if let Some(end_tag_offset) = end_tag_offset {
26219            let cursor_is_before_end_tag = column <= end_tag_offset;
26220            if cursor_is_after_start_tag {
26221                if cursor_is_before_end_tag {
26222                    needs_extra_line = true;
26223                }
26224                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26225                if cursor_is_at_start_of_end_tag {
26226                    extra_line_additional_indent.len = *len;
26227                }
26228            }
26229            cursor_is_before_end_tag
26230        } else {
26231            true
26232        }
26233    };
26234
26235    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26236        && cursor_is_before_end_tag_if_exists
26237    {
26238        let additional_indent = if cursor_is_after_start_tag {
26239            IndentSize::spaces(*len)
26240        } else {
26241            IndentSize::spaces(0)
26242        };
26243
26244        *newline_config = NewlineConfig::Newline {
26245            additional_indent,
26246            extra_line_additional_indent: if needs_extra_line {
26247                Some(extra_line_additional_indent)
26248            } else {
26249                None
26250            },
26251            prevent_auto_indent: true,
26252        };
26253        Some(delimiter.clone())
26254    } else {
26255        None
26256    }
26257}
26258
26259const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26260
26261fn list_delimiter_for_newline(
26262    start_point: &Point,
26263    buffer: &MultiBufferSnapshot,
26264    language: &LanguageScope,
26265    newline_config: &mut NewlineConfig,
26266) -> Option<Arc<str>> {
26267    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26268
26269    let num_of_whitespaces = snapshot
26270        .chars_for_range(range.clone())
26271        .take_while(|c| c.is_whitespace())
26272        .count();
26273
26274    let task_list_entries: Vec<_> = language
26275        .task_list()
26276        .into_iter()
26277        .flat_map(|config| {
26278            config
26279                .prefixes
26280                .iter()
26281                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26282        })
26283        .collect();
26284    let unordered_list_entries: Vec<_> = language
26285        .unordered_list()
26286        .iter()
26287        .map(|marker| (marker.as_ref(), marker.as_ref()))
26288        .collect();
26289
26290    let all_entries: Vec<_> = task_list_entries
26291        .into_iter()
26292        .chain(unordered_list_entries)
26293        .collect();
26294
26295    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26296        let candidate: String = snapshot
26297            .chars_for_range(range.clone())
26298            .skip(num_of_whitespaces)
26299            .take(max_prefix_len)
26300            .collect();
26301
26302        if let Some((prefix, continuation)) = all_entries
26303            .iter()
26304            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26305            .max_by_key(|(prefix, _)| prefix.len())
26306        {
26307            let end_of_prefix = num_of_whitespaces + prefix.len();
26308            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26309            let has_content_after_marker = snapshot
26310                .chars_for_range(range)
26311                .skip(end_of_prefix)
26312                .any(|c| !c.is_whitespace());
26313
26314            if has_content_after_marker && cursor_is_after_prefix {
26315                return Some((*continuation).into());
26316            }
26317
26318            if start_point.column as usize == end_of_prefix {
26319                if num_of_whitespaces == 0 {
26320                    *newline_config = NewlineConfig::ClearCurrentLine;
26321                } else {
26322                    *newline_config = NewlineConfig::UnindentCurrentLine {
26323                        continuation: (*continuation).into(),
26324                    };
26325                }
26326            }
26327
26328            return None;
26329        }
26330    }
26331
26332    let candidate: String = snapshot
26333        .chars_for_range(range.clone())
26334        .skip(num_of_whitespaces)
26335        .take(ORDERED_LIST_MAX_MARKER_LEN)
26336        .collect();
26337
26338    for ordered_config in language.ordered_list() {
26339        let regex = match Regex::new(&ordered_config.pattern) {
26340            Ok(r) => r,
26341            Err(_) => continue,
26342        };
26343
26344        if let Some(captures) = regex.captures(&candidate) {
26345            let full_match = captures.get(0)?;
26346            let marker_len = full_match.len();
26347            let end_of_prefix = num_of_whitespaces + marker_len;
26348            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26349
26350            let has_content_after_marker = snapshot
26351                .chars_for_range(range)
26352                .skip(end_of_prefix)
26353                .any(|c| !c.is_whitespace());
26354
26355            if has_content_after_marker && cursor_is_after_prefix {
26356                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26357                let continuation = ordered_config
26358                    .format
26359                    .replace("{1}", &(number + 1).to_string());
26360                return Some(continuation.into());
26361            }
26362
26363            if start_point.column as usize == end_of_prefix {
26364                let continuation = ordered_config.format.replace("{1}", "1");
26365                if num_of_whitespaces == 0 {
26366                    *newline_config = NewlineConfig::ClearCurrentLine;
26367                } else {
26368                    *newline_config = NewlineConfig::UnindentCurrentLine {
26369                        continuation: continuation.into(),
26370                    };
26371                }
26372            }
26373
26374            return None;
26375        }
26376    }
26377
26378    None
26379}
26380
26381fn is_list_prefix_row(
26382    row: MultiBufferRow,
26383    buffer: &MultiBufferSnapshot,
26384    language: &LanguageScope,
26385) -> bool {
26386    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26387        return false;
26388    };
26389
26390    let num_of_whitespaces = snapshot
26391        .chars_for_range(range.clone())
26392        .take_while(|c| c.is_whitespace())
26393        .count();
26394
26395    let task_list_prefixes: Vec<_> = language
26396        .task_list()
26397        .into_iter()
26398        .flat_map(|config| {
26399            config
26400                .prefixes
26401                .iter()
26402                .map(|p| p.as_ref())
26403                .collect::<Vec<_>>()
26404        })
26405        .collect();
26406    let unordered_list_markers: Vec<_> = language
26407        .unordered_list()
26408        .iter()
26409        .map(|marker| marker.as_ref())
26410        .collect();
26411    let all_prefixes: Vec<_> = task_list_prefixes
26412        .into_iter()
26413        .chain(unordered_list_markers)
26414        .collect();
26415    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26416        let candidate: String = snapshot
26417            .chars_for_range(range.clone())
26418            .skip(num_of_whitespaces)
26419            .take(max_prefix_len)
26420            .collect();
26421        if all_prefixes
26422            .iter()
26423            .any(|prefix| candidate.starts_with(*prefix))
26424        {
26425            return true;
26426        }
26427    }
26428
26429    let ordered_list_candidate: String = snapshot
26430        .chars_for_range(range)
26431        .skip(num_of_whitespaces)
26432        .take(ORDERED_LIST_MAX_MARKER_LEN)
26433        .collect();
26434    for ordered_config in language.ordered_list() {
26435        let regex = match Regex::new(&ordered_config.pattern) {
26436            Ok(r) => r,
26437            Err(_) => continue,
26438        };
26439        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26440            return captures.get(0).is_some();
26441        }
26442    }
26443
26444    false
26445}
26446
26447#[derive(Debug)]
26448enum NewlineConfig {
26449    /// Insert newline with optional additional indent and optional extra blank line
26450    Newline {
26451        additional_indent: IndentSize,
26452        extra_line_additional_indent: Option<IndentSize>,
26453        prevent_auto_indent: bool,
26454    },
26455    /// Clear the current line
26456    ClearCurrentLine,
26457    /// Unindent the current line and add continuation
26458    UnindentCurrentLine { continuation: Arc<str> },
26459}
26460
26461impl NewlineConfig {
26462    fn has_extra_line(&self) -> bool {
26463        matches!(
26464            self,
26465            Self::Newline {
26466                extra_line_additional_indent: Some(_),
26467                ..
26468            }
26469        )
26470    }
26471
26472    fn insert_extra_newline_brackets(
26473        buffer: &MultiBufferSnapshot,
26474        range: Range<MultiBufferOffset>,
26475        language: &language::LanguageScope,
26476    ) -> bool {
26477        let leading_whitespace_len = buffer
26478            .reversed_chars_at(range.start)
26479            .take_while(|c| c.is_whitespace() && *c != '\n')
26480            .map(|c| c.len_utf8())
26481            .sum::<usize>();
26482        let trailing_whitespace_len = buffer
26483            .chars_at(range.end)
26484            .take_while(|c| c.is_whitespace() && *c != '\n')
26485            .map(|c| c.len_utf8())
26486            .sum::<usize>();
26487        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26488
26489        language.brackets().any(|(pair, enabled)| {
26490            let pair_start = pair.start.trim_end();
26491            let pair_end = pair.end.trim_start();
26492
26493            enabled
26494                && pair.newline
26495                && buffer.contains_str_at(range.end, pair_end)
26496                && buffer.contains_str_at(
26497                    range.start.saturating_sub_usize(pair_start.len()),
26498                    pair_start,
26499                )
26500        })
26501    }
26502
26503    fn insert_extra_newline_tree_sitter(
26504        buffer: &MultiBufferSnapshot,
26505        range: Range<MultiBufferOffset>,
26506    ) -> bool {
26507        let (buffer, range) = match buffer
26508            .range_to_buffer_ranges(range.start..range.end)
26509            .as_slice()
26510        {
26511            [(buffer_snapshot, range, _)] => (buffer_snapshot.clone(), range.clone()),
26512            _ => return false,
26513        };
26514        let pair = {
26515            let mut result: Option<BracketMatch<usize>> = None;
26516
26517            for pair in buffer
26518                .all_bracket_ranges(range.start.0..range.end.0)
26519                .filter(move |pair| {
26520                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26521                })
26522            {
26523                let len = pair.close_range.end - pair.open_range.start;
26524
26525                if let Some(existing) = &result {
26526                    let existing_len = existing.close_range.end - existing.open_range.start;
26527                    if len > existing_len {
26528                        continue;
26529                    }
26530                }
26531
26532                result = Some(pair);
26533            }
26534
26535            result
26536        };
26537        let Some(pair) = pair else {
26538            return false;
26539        };
26540        pair.newline_only
26541            && buffer
26542                .chars_for_range(pair.open_range.end..range.start.0)
26543                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26544                .all(|c| c.is_whitespace() && c != '\n')
26545    }
26546}
26547
26548fn update_uncommitted_diff_for_buffer(
26549    editor: Entity<Editor>,
26550    project: &Entity<Project>,
26551    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26552    buffer: Entity<MultiBuffer>,
26553    cx: &mut App,
26554) -> Task<()> {
26555    let mut tasks = Vec::new();
26556    project.update(cx, |project, cx| {
26557        for buffer in buffers {
26558            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26559                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26560            }
26561        }
26562    });
26563    cx.spawn(async move |cx| {
26564        let diffs = future::join_all(tasks).await;
26565        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26566            return;
26567        }
26568
26569        buffer.update(cx, |buffer, cx| {
26570            for diff in diffs.into_iter().flatten() {
26571                buffer.add_diff(diff, cx);
26572            }
26573        });
26574    })
26575}
26576
26577fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26578    let tab_size = tab_size.get() as usize;
26579    let mut width = offset;
26580
26581    for ch in text.chars() {
26582        width += if ch == '\t' {
26583            tab_size - (width % tab_size)
26584        } else {
26585            1
26586        };
26587    }
26588
26589    width - offset
26590}
26591
26592#[cfg(test)]
26593mod tests {
26594    use super::*;
26595
26596    #[test]
26597    fn test_string_size_with_expanded_tabs() {
26598        let nz = |val| NonZeroU32::new(val).unwrap();
26599        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26600        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26601        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26602        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26603        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26604        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26605        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26606        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26607    }
26608}
26609
26610/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26611struct WordBreakingTokenizer<'a> {
26612    input: &'a str,
26613}
26614
26615impl<'a> WordBreakingTokenizer<'a> {
26616    fn new(input: &'a str) -> Self {
26617        Self { input }
26618    }
26619}
26620
26621fn is_char_ideographic(ch: char) -> bool {
26622    use unicode_script::Script::*;
26623    use unicode_script::UnicodeScript;
26624    matches!(ch.script(), Han | Tangut | Yi)
26625}
26626
26627fn is_grapheme_ideographic(text: &str) -> bool {
26628    text.chars().any(is_char_ideographic)
26629}
26630
26631fn is_grapheme_whitespace(text: &str) -> bool {
26632    text.chars().any(|x| x.is_whitespace())
26633}
26634
26635fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26636    text.chars()
26637        .next()
26638        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26639}
26640
26641#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26642enum WordBreakToken<'a> {
26643    Word { token: &'a str, grapheme_len: usize },
26644    InlineWhitespace { token: &'a str, grapheme_len: usize },
26645    Newline,
26646}
26647
26648impl<'a> Iterator for WordBreakingTokenizer<'a> {
26649    /// Yields a span, the count of graphemes in the token, and whether it was
26650    /// whitespace. Note that it also breaks at word boundaries.
26651    type Item = WordBreakToken<'a>;
26652
26653    fn next(&mut self) -> Option<Self::Item> {
26654        use unicode_segmentation::UnicodeSegmentation;
26655        if self.input.is_empty() {
26656            return None;
26657        }
26658
26659        let mut iter = self.input.graphemes(true).peekable();
26660        let mut offset = 0;
26661        let mut grapheme_len = 0;
26662        if let Some(first_grapheme) = iter.next() {
26663            let is_newline = first_grapheme == "\n";
26664            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26665            offset += first_grapheme.len();
26666            grapheme_len += 1;
26667            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26668                if let Some(grapheme) = iter.peek().copied()
26669                    && should_stay_with_preceding_ideograph(grapheme)
26670                {
26671                    offset += grapheme.len();
26672                    grapheme_len += 1;
26673                }
26674            } else {
26675                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26676                let mut next_word_bound = words.peek().copied();
26677                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26678                    next_word_bound = words.next();
26679                }
26680                while let Some(grapheme) = iter.peek().copied() {
26681                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26682                        break;
26683                    };
26684                    if is_grapheme_whitespace(grapheme) != is_whitespace
26685                        || (grapheme == "\n") != is_newline
26686                    {
26687                        break;
26688                    };
26689                    offset += grapheme.len();
26690                    grapheme_len += 1;
26691                    iter.next();
26692                }
26693            }
26694            let token = &self.input[..offset];
26695            self.input = &self.input[offset..];
26696            if token == "\n" {
26697                Some(WordBreakToken::Newline)
26698            } else if is_whitespace {
26699                Some(WordBreakToken::InlineWhitespace {
26700                    token,
26701                    grapheme_len,
26702                })
26703            } else {
26704                Some(WordBreakToken::Word {
26705                    token,
26706                    grapheme_len,
26707                })
26708            }
26709        } else {
26710            None
26711        }
26712    }
26713}
26714
26715#[test]
26716fn test_word_breaking_tokenizer() {
26717    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26718        ("", &[]),
26719        ("  ", &[whitespace("  ", 2)]),
26720        ("Ʒ", &[word("Ʒ", 1)]),
26721        ("Ǽ", &[word("Ǽ", 1)]),
26722        ("", &[word("", 1)]),
26723        ("⋑⋑", &[word("⋑⋑", 2)]),
26724        (
26725            "原理,进而",
26726            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26727        ),
26728        (
26729            "hello world",
26730            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26731        ),
26732        (
26733            "hello, world",
26734            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26735        ),
26736        (
26737            "  hello world",
26738            &[
26739                whitespace("  ", 2),
26740                word("hello", 5),
26741                whitespace(" ", 1),
26742                word("world", 5),
26743            ],
26744        ),
26745        (
26746            "这是什么 \n 钢笔",
26747            &[
26748                word("", 1),
26749                word("", 1),
26750                word("", 1),
26751                word("", 1),
26752                whitespace(" ", 1),
26753                newline(),
26754                whitespace(" ", 1),
26755                word("", 1),
26756                word("", 1),
26757            ],
26758        ),
26759        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26760    ];
26761
26762    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26763        WordBreakToken::Word {
26764            token,
26765            grapheme_len,
26766        }
26767    }
26768
26769    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26770        WordBreakToken::InlineWhitespace {
26771            token,
26772            grapheme_len,
26773        }
26774    }
26775
26776    fn newline() -> WordBreakToken<'static> {
26777        WordBreakToken::Newline
26778    }
26779
26780    for (input, result) in tests {
26781        assert_eq!(
26782            WordBreakingTokenizer::new(input)
26783                .collect::<Vec<_>>()
26784                .as_slice(),
26785            *result,
26786        );
26787    }
26788}
26789
26790fn wrap_with_prefix(
26791    first_line_prefix: String,
26792    subsequent_lines_prefix: String,
26793    unwrapped_text: String,
26794    wrap_column: usize,
26795    tab_size: NonZeroU32,
26796    preserve_existing_whitespace: bool,
26797) -> String {
26798    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26799    let subsequent_lines_prefix_len =
26800        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26801    let mut wrapped_text = String::new();
26802    let mut current_line = first_line_prefix;
26803    let mut is_first_line = true;
26804
26805    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26806    let mut current_line_len = first_line_prefix_len;
26807    let mut in_whitespace = false;
26808    for token in tokenizer {
26809        let have_preceding_whitespace = in_whitespace;
26810        match token {
26811            WordBreakToken::Word {
26812                token,
26813                grapheme_len,
26814            } => {
26815                in_whitespace = false;
26816                let current_prefix_len = if is_first_line {
26817                    first_line_prefix_len
26818                } else {
26819                    subsequent_lines_prefix_len
26820                };
26821                if current_line_len + grapheme_len > wrap_column
26822                    && current_line_len != current_prefix_len
26823                {
26824                    wrapped_text.push_str(current_line.trim_end());
26825                    wrapped_text.push('\n');
26826                    is_first_line = false;
26827                    current_line = subsequent_lines_prefix.clone();
26828                    current_line_len = subsequent_lines_prefix_len;
26829                }
26830                current_line.push_str(token);
26831                current_line_len += grapheme_len;
26832            }
26833            WordBreakToken::InlineWhitespace {
26834                mut token,
26835                mut grapheme_len,
26836            } => {
26837                in_whitespace = true;
26838                if have_preceding_whitespace && !preserve_existing_whitespace {
26839                    continue;
26840                }
26841                if !preserve_existing_whitespace {
26842                    // Keep a single whitespace grapheme as-is
26843                    if let Some(first) =
26844                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26845                    {
26846                        token = first;
26847                    } else {
26848                        token = " ";
26849                    }
26850                    grapheme_len = 1;
26851                }
26852                let current_prefix_len = if is_first_line {
26853                    first_line_prefix_len
26854                } else {
26855                    subsequent_lines_prefix_len
26856                };
26857                if current_line_len + grapheme_len > wrap_column {
26858                    wrapped_text.push_str(current_line.trim_end());
26859                    wrapped_text.push('\n');
26860                    is_first_line = false;
26861                    current_line = subsequent_lines_prefix.clone();
26862                    current_line_len = subsequent_lines_prefix_len;
26863                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26864                    current_line.push_str(token);
26865                    current_line_len += grapheme_len;
26866                }
26867            }
26868            WordBreakToken::Newline => {
26869                in_whitespace = true;
26870                let current_prefix_len = if is_first_line {
26871                    first_line_prefix_len
26872                } else {
26873                    subsequent_lines_prefix_len
26874                };
26875                if preserve_existing_whitespace {
26876                    wrapped_text.push_str(current_line.trim_end());
26877                    wrapped_text.push('\n');
26878                    is_first_line = false;
26879                    current_line = subsequent_lines_prefix.clone();
26880                    current_line_len = subsequent_lines_prefix_len;
26881                } else if have_preceding_whitespace {
26882                    continue;
26883                } else if current_line_len + 1 > wrap_column
26884                    && current_line_len != current_prefix_len
26885                {
26886                    wrapped_text.push_str(current_line.trim_end());
26887                    wrapped_text.push('\n');
26888                    is_first_line = false;
26889                    current_line = subsequent_lines_prefix.clone();
26890                    current_line_len = subsequent_lines_prefix_len;
26891                } else if current_line_len != current_prefix_len {
26892                    current_line.push(' ');
26893                    current_line_len += 1;
26894                }
26895            }
26896        }
26897    }
26898
26899    if !current_line.is_empty() {
26900        wrapped_text.push_str(&current_line);
26901    }
26902    wrapped_text
26903}
26904
26905#[test]
26906fn test_wrap_with_prefix() {
26907    assert_eq!(
26908        wrap_with_prefix(
26909            "# ".to_string(),
26910            "# ".to_string(),
26911            "abcdefg".to_string(),
26912            4,
26913            NonZeroU32::new(4).unwrap(),
26914            false,
26915        ),
26916        "# abcdefg"
26917    );
26918    assert_eq!(
26919        wrap_with_prefix(
26920            "".to_string(),
26921            "".to_string(),
26922            "\thello world".to_string(),
26923            8,
26924            NonZeroU32::new(4).unwrap(),
26925            false,
26926        ),
26927        "hello\nworld"
26928    );
26929    assert_eq!(
26930        wrap_with_prefix(
26931            "// ".to_string(),
26932            "// ".to_string(),
26933            "xx \nyy zz aa bb cc".to_string(),
26934            12,
26935            NonZeroU32::new(4).unwrap(),
26936            false,
26937        ),
26938        "// xx yy zz\n// aa bb cc"
26939    );
26940    assert_eq!(
26941        wrap_with_prefix(
26942            String::new(),
26943            String::new(),
26944            "这是什么 \n 钢笔".to_string(),
26945            3,
26946            NonZeroU32::new(4).unwrap(),
26947            false,
26948        ),
26949        "这是什\n么 钢\n"
26950    );
26951    assert_eq!(
26952        wrap_with_prefix(
26953            String::new(),
26954            String::new(),
26955            format!("foo{}bar", '\u{2009}'), // thin space
26956            80,
26957            NonZeroU32::new(4).unwrap(),
26958            false,
26959        ),
26960        format!("foo{}bar", '\u{2009}')
26961    );
26962}
26963
26964pub trait CollaborationHub {
26965    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26966    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26967    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26968}
26969
26970impl CollaborationHub for Entity<Project> {
26971    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26972        self.read(cx).collaborators()
26973    }
26974
26975    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26976        self.read(cx).user_store().read(cx).participant_indices()
26977    }
26978
26979    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26980        let this = self.read(cx);
26981        let user_ids = this.collaborators().values().map(|c| c.user_id);
26982        this.user_store().read(cx).participant_names(user_ids, cx)
26983    }
26984}
26985
26986pub trait SemanticsProvider {
26987    fn hover(
26988        &self,
26989        buffer: &Entity<Buffer>,
26990        position: text::Anchor,
26991        cx: &mut App,
26992    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26993
26994    fn inline_values(
26995        &self,
26996        buffer_handle: Entity<Buffer>,
26997        range: Range<text::Anchor>,
26998        cx: &mut App,
26999    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
27000
27001    fn applicable_inlay_chunks(
27002        &self,
27003        buffer: &Entity<Buffer>,
27004        ranges: &[Range<text::Anchor>],
27005        cx: &mut App,
27006    ) -> Vec<Range<BufferRow>>;
27007
27008    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
27009
27010    fn inlay_hints(
27011        &self,
27012        invalidate: InvalidationStrategy,
27013        buffer: Entity<Buffer>,
27014        ranges: Vec<Range<text::Anchor>>,
27015        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27016        cx: &mut App,
27017    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27018
27019    fn semantic_tokens(
27020        &self,
27021        buffer: Entity<Buffer>,
27022        refresh: Option<RefreshForServer>,
27023        cx: &mut App,
27024    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27025
27026    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27027
27028    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27029
27030    fn document_highlights(
27031        &self,
27032        buffer: &Entity<Buffer>,
27033        position: text::Anchor,
27034        cx: &mut App,
27035    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27036
27037    fn definitions(
27038        &self,
27039        buffer: &Entity<Buffer>,
27040        position: text::Anchor,
27041        kind: GotoDefinitionKind,
27042        cx: &mut App,
27043    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27044
27045    fn range_for_rename(
27046        &self,
27047        buffer: &Entity<Buffer>,
27048        position: text::Anchor,
27049        cx: &mut App,
27050    ) -> Task<Result<Option<Range<text::Anchor>>>>;
27051
27052    fn perform_rename(
27053        &self,
27054        buffer: &Entity<Buffer>,
27055        position: text::Anchor,
27056        new_name: String,
27057        cx: &mut App,
27058    ) -> Option<Task<Result<ProjectTransaction>>>;
27059}
27060
27061pub trait CompletionProvider {
27062    fn completions(
27063        &self,
27064        buffer: &Entity<Buffer>,
27065        buffer_position: text::Anchor,
27066        trigger: CompletionContext,
27067        window: &mut Window,
27068        cx: &mut Context<Editor>,
27069    ) -> Task<Result<Vec<CompletionResponse>>>;
27070
27071    fn resolve_completions(
27072        &self,
27073        _buffer: Entity<Buffer>,
27074        _completion_indices: Vec<usize>,
27075        _completions: Rc<RefCell<Box<[Completion]>>>,
27076        _cx: &mut Context<Editor>,
27077    ) -> Task<Result<bool>> {
27078        Task::ready(Ok(false))
27079    }
27080
27081    fn apply_additional_edits_for_completion(
27082        &self,
27083        _buffer: Entity<Buffer>,
27084        _completions: Rc<RefCell<Box<[Completion]>>>,
27085        _completion_index: usize,
27086        _push_to_history: bool,
27087        _all_commit_ranges: Vec<Range<language::Anchor>>,
27088        _cx: &mut Context<Editor>,
27089    ) -> Task<Result<Option<language::Transaction>>> {
27090        Task::ready(Ok(None))
27091    }
27092
27093    fn is_completion_trigger(
27094        &self,
27095        buffer: &Entity<Buffer>,
27096        position: language::Anchor,
27097        text: &str,
27098        trigger_in_words: bool,
27099        cx: &mut Context<Editor>,
27100    ) -> bool;
27101
27102    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27103
27104    fn sort_completions(&self) -> bool {
27105        true
27106    }
27107
27108    fn filter_completions(&self) -> bool {
27109        true
27110    }
27111
27112    fn show_snippets(&self) -> bool {
27113        false
27114    }
27115}
27116
27117pub trait CodeActionProvider {
27118    fn id(&self) -> Arc<str>;
27119
27120    fn code_actions(
27121        &self,
27122        buffer: &Entity<Buffer>,
27123        range: Range<text::Anchor>,
27124        window: &mut Window,
27125        cx: &mut App,
27126    ) -> Task<Result<Vec<CodeAction>>>;
27127
27128    fn apply_code_action(
27129        &self,
27130        buffer_handle: Entity<Buffer>,
27131        action: CodeAction,
27132        push_to_history: bool,
27133        window: &mut Window,
27134        cx: &mut App,
27135    ) -> Task<Result<ProjectTransaction>>;
27136}
27137
27138impl CodeActionProvider for Entity<Project> {
27139    fn id(&self) -> Arc<str> {
27140        "project".into()
27141    }
27142
27143    fn code_actions(
27144        &self,
27145        buffer: &Entity<Buffer>,
27146        range: Range<text::Anchor>,
27147        _window: &mut Window,
27148        cx: &mut App,
27149    ) -> Task<Result<Vec<CodeAction>>> {
27150        self.update(cx, |project, cx| {
27151            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27152            let code_actions = project.code_actions(buffer, range, None, cx);
27153            cx.background_spawn(async move {
27154                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27155                Ok(code_lens_actions
27156                    .context("code lens fetch")?
27157                    .into_iter()
27158                    .flatten()
27159                    .chain(
27160                        code_actions
27161                            .context("code action fetch")?
27162                            .into_iter()
27163                            .flatten(),
27164                    )
27165                    .collect())
27166            })
27167        })
27168    }
27169
27170    fn apply_code_action(
27171        &self,
27172        buffer_handle: Entity<Buffer>,
27173        action: CodeAction,
27174        push_to_history: bool,
27175        _window: &mut Window,
27176        cx: &mut App,
27177    ) -> Task<Result<ProjectTransaction>> {
27178        self.update(cx, |project, cx| {
27179            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27180        })
27181    }
27182}
27183
27184fn snippet_completions(
27185    project: &Project,
27186    buffer: &Entity<Buffer>,
27187    buffer_anchor: text::Anchor,
27188    classifier: CharClassifier,
27189    cx: &mut App,
27190) -> Task<Result<CompletionResponse>> {
27191    let languages = buffer.read(cx).languages_at(buffer_anchor);
27192    let snippet_store = project.snippets().read(cx);
27193
27194    let scopes: Vec<_> = languages
27195        .iter()
27196        .filter_map(|language| {
27197            let language_name = language.lsp_id();
27198            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27199
27200            if snippets.is_empty() {
27201                None
27202            } else {
27203                Some((language.default_scope(), snippets))
27204            }
27205        })
27206        .collect();
27207
27208    if scopes.is_empty() {
27209        return Task::ready(Ok(CompletionResponse {
27210            completions: vec![],
27211            display_options: CompletionDisplayOptions::default(),
27212            is_incomplete: false,
27213        }));
27214    }
27215
27216    let snapshot = buffer.read(cx).text_snapshot();
27217    let executor = cx.background_executor().clone();
27218
27219    cx.background_spawn(async move {
27220        let is_word_char = |c| classifier.is_word(c);
27221
27222        let mut is_incomplete = false;
27223        let mut completions: Vec<Completion> = Vec::new();
27224
27225        const MAX_PREFIX_LEN: usize = 128;
27226        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27227        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27228        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27229
27230        let max_buffer_window: String = snapshot
27231            .text_for_range(window_start..buffer_offset)
27232            .collect();
27233
27234        if max_buffer_window.is_empty() {
27235            return Ok(CompletionResponse {
27236                completions: vec![],
27237                display_options: CompletionDisplayOptions::default(),
27238                is_incomplete: true,
27239            });
27240        }
27241
27242        for (_scope, snippets) in scopes.into_iter() {
27243            // Sort snippets by word count to match longer snippet prefixes first.
27244            let mut sorted_snippet_candidates = snippets
27245                .iter()
27246                .enumerate()
27247                .flat_map(|(snippet_ix, snippet)| {
27248                    snippet
27249                        .prefix
27250                        .iter()
27251                        .enumerate()
27252                        .map(move |(prefix_ix, prefix)| {
27253                            let word_count =
27254                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27255                            ((snippet_ix, prefix_ix), prefix, word_count)
27256                        })
27257                })
27258                .collect_vec();
27259            sorted_snippet_candidates
27260                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27261
27262            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27263
27264            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27265                .take(
27266                    sorted_snippet_candidates
27267                        .first()
27268                        .map(|(_, _, word_count)| *word_count)
27269                        .unwrap_or_default(),
27270                )
27271                .collect_vec();
27272
27273            const MAX_RESULTS: usize = 100;
27274            // Each match also remembers how many characters from the buffer it consumed
27275            let mut matches: Vec<(StringMatch, usize)> = vec![];
27276
27277            let mut snippet_list_cutoff_index = 0;
27278            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27279                let word_count = buffer_index + 1;
27280                // Increase `snippet_list_cutoff_index` until we have all of the
27281                // snippets with sufficiently many words.
27282                while sorted_snippet_candidates
27283                    .get(snippet_list_cutoff_index)
27284                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27285                        *snippet_word_count >= word_count
27286                    })
27287                {
27288                    snippet_list_cutoff_index += 1;
27289                }
27290
27291                // Take only the candidates with at least `word_count` many words
27292                let snippet_candidates_at_word_len =
27293                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27294
27295                let candidates = snippet_candidates_at_word_len
27296                    .iter()
27297                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27298                    .enumerate() // index in `sorted_snippet_candidates`
27299                    // First char must match
27300                    .filter(|(_ix, prefix)| {
27301                        itertools::equal(
27302                            prefix
27303                                .chars()
27304                                .next()
27305                                .into_iter()
27306                                .flat_map(|c| c.to_lowercase()),
27307                            buffer_window
27308                                .chars()
27309                                .next()
27310                                .into_iter()
27311                                .flat_map(|c| c.to_lowercase()),
27312                        )
27313                    })
27314                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27315                    .collect::<Vec<StringMatchCandidate>>();
27316
27317                matches.extend(
27318                    fuzzy::match_strings(
27319                        &candidates,
27320                        &buffer_window,
27321                        buffer_window.chars().any(|c| c.is_uppercase()),
27322                        true,
27323                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27324                        &Default::default(),
27325                        executor.clone(),
27326                    )
27327                    .await
27328                    .into_iter()
27329                    .map(|string_match| (string_match, buffer_window.len())),
27330                );
27331
27332                if matches.len() >= MAX_RESULTS {
27333                    break;
27334                }
27335            }
27336
27337            let to_lsp = |point: &text::Anchor| {
27338                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27339                point_to_lsp(end)
27340            };
27341            let lsp_end = to_lsp(&buffer_anchor);
27342
27343            if matches.len() >= MAX_RESULTS {
27344                is_incomplete = true;
27345            }
27346
27347            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27348                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27349                    sorted_snippet_candidates[string_match.candidate_id];
27350                let snippet = &snippets[snippet_index];
27351                let start = buffer_offset - buffer_window_len;
27352                let start = snapshot.anchor_before(start);
27353                let range = start..buffer_anchor;
27354                let lsp_start = to_lsp(&start);
27355                let lsp_range = lsp::Range {
27356                    start: lsp_start,
27357                    end: lsp_end,
27358                };
27359                Completion {
27360                    replace_range: range,
27361                    new_text: snippet.body.clone(),
27362                    source: CompletionSource::Lsp {
27363                        insert_range: None,
27364                        server_id: LanguageServerId(usize::MAX),
27365                        resolved: true,
27366                        lsp_completion: Box::new(lsp::CompletionItem {
27367                            label: snippet.prefix.first().unwrap().clone(),
27368                            kind: Some(CompletionItemKind::SNIPPET),
27369                            label_details: snippet.description.as_ref().map(|description| {
27370                                lsp::CompletionItemLabelDetails {
27371                                    detail: Some(description.clone()),
27372                                    description: None,
27373                                }
27374                            }),
27375                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27376                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27377                                lsp::InsertReplaceEdit {
27378                                    new_text: snippet.body.clone(),
27379                                    insert: lsp_range,
27380                                    replace: lsp_range,
27381                                },
27382                            )),
27383                            filter_text: Some(snippet.body.clone()),
27384                            sort_text: Some(char::MAX.to_string()),
27385                            ..lsp::CompletionItem::default()
27386                        }),
27387                        lsp_defaults: None,
27388                    },
27389                    label: CodeLabel {
27390                        text: matching_prefix.clone(),
27391                        runs: Vec::new(),
27392                        filter_range: 0..matching_prefix.len(),
27393                    },
27394                    icon_path: None,
27395                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27396                        single_line: snippet.name.clone().into(),
27397                        plain_text: snippet
27398                            .description
27399                            .clone()
27400                            .map(|description| description.into()),
27401                    }),
27402                    insert_text_mode: None,
27403                    confirm: None,
27404                    match_start: Some(start),
27405                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27406                }
27407            }));
27408        }
27409
27410        Ok(CompletionResponse {
27411            completions,
27412            display_options: CompletionDisplayOptions::default(),
27413            is_incomplete,
27414        })
27415    })
27416}
27417
27418impl CompletionProvider for Entity<Project> {
27419    fn completions(
27420        &self,
27421        buffer: &Entity<Buffer>,
27422        buffer_position: text::Anchor,
27423        options: CompletionContext,
27424        _window: &mut Window,
27425        cx: &mut Context<Editor>,
27426    ) -> Task<Result<Vec<CompletionResponse>>> {
27427        self.update(cx, |project, cx| {
27428            let task = project.completions(buffer, buffer_position, options, cx);
27429            cx.background_spawn(task)
27430        })
27431    }
27432
27433    fn resolve_completions(
27434        &self,
27435        buffer: Entity<Buffer>,
27436        completion_indices: Vec<usize>,
27437        completions: Rc<RefCell<Box<[Completion]>>>,
27438        cx: &mut Context<Editor>,
27439    ) -> Task<Result<bool>> {
27440        self.update(cx, |project, cx| {
27441            project.lsp_store().update(cx, |lsp_store, cx| {
27442                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27443            })
27444        })
27445    }
27446
27447    fn apply_additional_edits_for_completion(
27448        &self,
27449        buffer: Entity<Buffer>,
27450        completions: Rc<RefCell<Box<[Completion]>>>,
27451        completion_index: usize,
27452        push_to_history: bool,
27453        all_commit_ranges: Vec<Range<language::Anchor>>,
27454        cx: &mut Context<Editor>,
27455    ) -> Task<Result<Option<language::Transaction>>> {
27456        self.update(cx, |project, cx| {
27457            project.lsp_store().update(cx, |lsp_store, cx| {
27458                lsp_store.apply_additional_edits_for_completion(
27459                    buffer,
27460                    completions,
27461                    completion_index,
27462                    push_to_history,
27463                    all_commit_ranges,
27464                    cx,
27465                )
27466            })
27467        })
27468    }
27469
27470    fn is_completion_trigger(
27471        &self,
27472        buffer: &Entity<Buffer>,
27473        position: language::Anchor,
27474        text: &str,
27475        trigger_in_words: bool,
27476        cx: &mut Context<Editor>,
27477    ) -> bool {
27478        let mut chars = text.chars();
27479        let char = if let Some(char) = chars.next() {
27480            char
27481        } else {
27482            return false;
27483        };
27484        if chars.next().is_some() {
27485            return false;
27486        }
27487
27488        let buffer = buffer.read(cx);
27489        let snapshot = buffer.snapshot();
27490        let classifier = snapshot
27491            .char_classifier_at(position)
27492            .scope_context(Some(CharScopeContext::Completion));
27493        if trigger_in_words && classifier.is_word(char) {
27494            return true;
27495        }
27496
27497        buffer.completion_triggers().contains(text)
27498    }
27499
27500    fn show_snippets(&self) -> bool {
27501        true
27502    }
27503}
27504
27505impl SemanticsProvider for WeakEntity<Project> {
27506    fn hover(
27507        &self,
27508        buffer: &Entity<Buffer>,
27509        position: text::Anchor,
27510        cx: &mut App,
27511    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27512        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27513            .ok()
27514    }
27515
27516    fn document_highlights(
27517        &self,
27518        buffer: &Entity<Buffer>,
27519        position: text::Anchor,
27520        cx: &mut App,
27521    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27522        self.update(cx, |project, cx| {
27523            project.document_highlights(buffer, position, cx)
27524        })
27525        .ok()
27526    }
27527
27528    fn definitions(
27529        &self,
27530        buffer: &Entity<Buffer>,
27531        position: text::Anchor,
27532        kind: GotoDefinitionKind,
27533        cx: &mut App,
27534    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27535        self.update(cx, |project, cx| match kind {
27536            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27537            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27538            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27539            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27540        })
27541        .ok()
27542    }
27543
27544    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27545        self.update(cx, |project, cx| {
27546            if project
27547                .active_debug_session(cx)
27548                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27549            {
27550                return true;
27551            }
27552
27553            buffer.update(cx, |buffer, cx| {
27554                project.any_language_server_supports_inlay_hints(buffer, cx)
27555            })
27556        })
27557        .unwrap_or(false)
27558    }
27559
27560    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27561        self.update(cx, |project, cx| {
27562            buffer.update(cx, |buffer, cx| {
27563                project.any_language_server_supports_semantic_tokens(buffer, cx)
27564            })
27565        })
27566        .unwrap_or(false)
27567    }
27568
27569    fn inline_values(
27570        &self,
27571        buffer_handle: Entity<Buffer>,
27572        range: Range<text::Anchor>,
27573        cx: &mut App,
27574    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27575        self.update(cx, |project, cx| {
27576            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27577
27578            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27579        })
27580        .ok()
27581        .flatten()
27582    }
27583
27584    fn applicable_inlay_chunks(
27585        &self,
27586        buffer: &Entity<Buffer>,
27587        ranges: &[Range<text::Anchor>],
27588        cx: &mut App,
27589    ) -> Vec<Range<BufferRow>> {
27590        self.update(cx, |project, cx| {
27591            project.lsp_store().update(cx, |lsp_store, cx| {
27592                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27593            })
27594        })
27595        .unwrap_or_default()
27596    }
27597
27598    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27599        self.update(cx, |project, cx| {
27600            project.lsp_store().update(cx, |lsp_store, _| {
27601                lsp_store.invalidate_inlay_hints(for_buffers)
27602            })
27603        })
27604        .ok();
27605    }
27606
27607    fn inlay_hints(
27608        &self,
27609        invalidate: InvalidationStrategy,
27610        buffer: Entity<Buffer>,
27611        ranges: Vec<Range<text::Anchor>>,
27612        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27613        cx: &mut App,
27614    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27615        self.update(cx, |project, cx| {
27616            project.lsp_store().update(cx, |lsp_store, cx| {
27617                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27618            })
27619        })
27620        .ok()
27621    }
27622
27623    fn semantic_tokens(
27624        &self,
27625        buffer: Entity<Buffer>,
27626        refresh: Option<RefreshForServer>,
27627        cx: &mut App,
27628    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27629        self.update(cx, |this, cx| {
27630            this.lsp_store().update(cx, |lsp_store, cx| {
27631                lsp_store.semantic_tokens(buffer, refresh, cx)
27632            })
27633        })
27634        .ok()
27635    }
27636
27637    fn range_for_rename(
27638        &self,
27639        buffer: &Entity<Buffer>,
27640        position: text::Anchor,
27641        cx: &mut App,
27642    ) -> Task<Result<Option<Range<text::Anchor>>>> {
27643        let Some(this) = self.upgrade() else {
27644            return Task::ready(Ok(None));
27645        };
27646
27647        this.update(cx, |project, cx| {
27648            let buffer = buffer.clone();
27649            let task = project.prepare_rename(buffer.clone(), position, cx);
27650            cx.spawn(async move |_, cx| {
27651                Ok(match task.await? {
27652                    PrepareRenameResponse::Success(range) => Some(range),
27653                    PrepareRenameResponse::InvalidPosition => None,
27654                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27655                        // Fallback on using TreeSitter info to determine identifier range
27656                        buffer.read_with(cx, |buffer, _| {
27657                            let snapshot = buffer.snapshot();
27658                            let (range, kind) = snapshot.surrounding_word(position, None);
27659                            if kind != Some(CharKind::Word) {
27660                                return None;
27661                            }
27662                            Some(
27663                                snapshot.anchor_before(range.start)
27664                                    ..snapshot.anchor_after(range.end),
27665                            )
27666                        })
27667                    }
27668                })
27669            })
27670        })
27671    }
27672
27673    fn perform_rename(
27674        &self,
27675        buffer: &Entity<Buffer>,
27676        position: text::Anchor,
27677        new_name: String,
27678        cx: &mut App,
27679    ) -> Option<Task<Result<ProjectTransaction>>> {
27680        self.update(cx, |project, cx| {
27681            project.perform_rename(buffer.clone(), position, new_name, cx)
27682        })
27683        .ok()
27684    }
27685}
27686
27687fn consume_contiguous_rows(
27688    contiguous_row_selections: &mut Vec<Selection<Point>>,
27689    selection: &Selection<Point>,
27690    display_map: &DisplaySnapshot,
27691    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27692) -> (MultiBufferRow, MultiBufferRow) {
27693    contiguous_row_selections.push(selection.clone());
27694    let start_row = starting_row(selection, display_map);
27695    let mut end_row = ending_row(selection, display_map);
27696
27697    while let Some(next_selection) = selections.peek() {
27698        if next_selection.start.row <= end_row.0 {
27699            end_row = ending_row(next_selection, display_map);
27700            contiguous_row_selections.push(selections.next().unwrap().clone());
27701        } else {
27702            break;
27703        }
27704    }
27705    (start_row, end_row)
27706}
27707
27708fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27709    if selection.start.column > 0 {
27710        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27711    } else {
27712        MultiBufferRow(selection.start.row)
27713    }
27714}
27715
27716fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27717    if next_selection.end.column > 0 || next_selection.is_empty() {
27718        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27719    } else {
27720        MultiBufferRow(next_selection.end.row)
27721    }
27722}
27723
27724impl EditorSnapshot {
27725    pub fn remote_selections_in_range<'a>(
27726        &'a self,
27727        range: &'a Range<Anchor>,
27728        collaboration_hub: &dyn CollaborationHub,
27729        cx: &'a App,
27730    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27731        let participant_names = collaboration_hub.user_names(cx);
27732        let participant_indices = collaboration_hub.user_participant_indices(cx);
27733        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27734        let collaborators_by_replica_id = collaborators_by_peer_id
27735            .values()
27736            .map(|collaborator| (collaborator.replica_id, collaborator))
27737            .collect::<HashMap<_, _>>();
27738        self.buffer_snapshot()
27739            .selections_in_range(range, false)
27740            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27741                if replica_id == ReplicaId::AGENT {
27742                    Some(RemoteSelection {
27743                        replica_id,
27744                        selection,
27745                        cursor_shape,
27746                        line_mode,
27747                        collaborator_id: CollaboratorId::Agent,
27748                        user_name: Some("Agent".into()),
27749                        color: cx.theme().players().agent(),
27750                    })
27751                } else {
27752                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27753                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27754                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27755                    Some(RemoteSelection {
27756                        replica_id,
27757                        selection,
27758                        cursor_shape,
27759                        line_mode,
27760                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27761                        user_name,
27762                        color: if let Some(index) = participant_index {
27763                            cx.theme().players().color_for_participant(index.0)
27764                        } else {
27765                            cx.theme().players().absent()
27766                        },
27767                    })
27768                }
27769            })
27770    }
27771
27772    pub fn hunks_for_ranges(
27773        &self,
27774        ranges: impl IntoIterator<Item = Range<Point>>,
27775    ) -> Vec<MultiBufferDiffHunk> {
27776        let mut hunks = Vec::new();
27777        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27778            HashMap::default();
27779        for query_range in ranges {
27780            let query_rows =
27781                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27782            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27783                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27784            ) {
27785                // Include deleted hunks that are adjacent to the query range, because
27786                // otherwise they would be missed.
27787                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27788                if hunk.status().is_deleted() {
27789                    intersects_range |= hunk.row_range.start == query_rows.end;
27790                    intersects_range |= hunk.row_range.end == query_rows.start;
27791                }
27792                if intersects_range {
27793                    if !processed_buffer_rows
27794                        .entry(hunk.buffer_id)
27795                        .or_default()
27796                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27797                    {
27798                        continue;
27799                    }
27800                    hunks.push(hunk);
27801                }
27802            }
27803        }
27804
27805        hunks
27806    }
27807
27808    fn display_diff_hunks_for_rows<'a>(
27809        &'a self,
27810        display_rows: Range<DisplayRow>,
27811        folded_buffers: &'a HashSet<BufferId>,
27812    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27813        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27814        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27815
27816        self.buffer_snapshot()
27817            .diff_hunks_in_range(buffer_start..buffer_end)
27818            .filter_map(|hunk| {
27819                if folded_buffers.contains(&hunk.buffer_id)
27820                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27821                {
27822                    return None;
27823                }
27824
27825                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27826                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27827                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27828                    let line_len = self.buffer_snapshot().line_len(last_row);
27829                    Point::new(last_row.0, line_len)
27830                } else {
27831                    Point::new(hunk.row_range.end.0, 0)
27832                };
27833
27834                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27835                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27836
27837                let display_hunk = if hunk_display_start.column() != 0 {
27838                    DisplayDiffHunk::Folded {
27839                        display_row: hunk_display_start.row(),
27840                    }
27841                } else {
27842                    let mut end_row = hunk_display_end.row();
27843                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27844                        end_row.0 += 1;
27845                    }
27846                    let is_created_file = hunk.is_created_file();
27847                    let multi_buffer_range = hunk.multi_buffer_range.clone();
27848
27849                    DisplayDiffHunk::Unfolded {
27850                        status: hunk.status(),
27851                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27852                            ..hunk.diff_base_byte_range.end.0,
27853                        word_diffs: hunk.word_diffs,
27854                        display_row_range: hunk_display_start.row()..end_row,
27855                        multi_buffer_range,
27856                        is_created_file,
27857                    }
27858                };
27859
27860                Some(display_hunk)
27861            })
27862    }
27863
27864    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27865        self.display_snapshot
27866            .buffer_snapshot()
27867            .language_at(position)
27868    }
27869
27870    pub fn is_focused(&self) -> bool {
27871        self.is_focused
27872    }
27873
27874    pub fn placeholder_text(&self) -> Option<String> {
27875        self.placeholder_display_snapshot
27876            .as_ref()
27877            .map(|display_map| display_map.text())
27878    }
27879
27880    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27881        self.scroll_anchor.scroll_position(&self.display_snapshot)
27882    }
27883
27884    pub fn gutter_dimensions(
27885        &self,
27886        font_id: FontId,
27887        font_size: Pixels,
27888        style: &EditorStyle,
27889        window: &mut Window,
27890        cx: &App,
27891    ) -> GutterDimensions {
27892        if self.show_gutter
27893            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27894            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27895        {
27896            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27897                matches!(
27898                    ProjectSettings::get_global(cx).git.git_gutter,
27899                    GitGutterSetting::TrackedFiles
27900                )
27901            });
27902            let gutter_settings = EditorSettings::get_global(cx).gutter;
27903            let show_line_numbers = self
27904                .show_line_numbers
27905                .unwrap_or(gutter_settings.line_numbers);
27906            let line_gutter_width = if show_line_numbers {
27907                // Avoid flicker-like gutter resizes when the line number gains another digit by
27908                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27909                let min_width_for_number_on_gutter =
27910                    ch_advance * gutter_settings.min_line_number_digits as f32;
27911                self.max_line_number_width(style, window)
27912                    .max(min_width_for_number_on_gutter)
27913            } else {
27914                0.0.into()
27915            };
27916
27917            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27918            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27919
27920            let git_blame_entries_width =
27921                self.git_blame_gutter_max_author_length
27922                    .map(|max_author_length| {
27923                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27924                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27925
27926                        /// The number of characters to dedicate to gaps and margins.
27927                        const SPACING_WIDTH: usize = 4;
27928
27929                        let max_char_count = max_author_length.min(renderer.max_author_length())
27930                            + ::git::SHORT_SHA_LENGTH
27931                            + MAX_RELATIVE_TIMESTAMP.len()
27932                            + SPACING_WIDTH;
27933
27934                        ch_advance * max_char_count
27935                    });
27936
27937            let is_singleton = self.buffer_snapshot().is_singleton();
27938
27939            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27940            left_padding += if !is_singleton {
27941                ch_width * 4.0
27942            } else if show_runnables || show_breakpoints {
27943                ch_width * 3.0
27944            } else if show_git_gutter && show_line_numbers {
27945                ch_width * 2.0
27946            } else if show_git_gutter || show_line_numbers {
27947                ch_width
27948            } else {
27949                px(0.)
27950            };
27951
27952            let shows_folds = is_singleton && gutter_settings.folds;
27953
27954            let right_padding = if shows_folds && show_line_numbers {
27955                ch_width * 4.0
27956            } else if shows_folds || (!is_singleton && show_line_numbers) {
27957                ch_width * 3.0
27958            } else if show_line_numbers {
27959                ch_width
27960            } else {
27961                px(0.)
27962            };
27963
27964            GutterDimensions {
27965                left_padding,
27966                right_padding,
27967                width: line_gutter_width + left_padding + right_padding,
27968                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27969                git_blame_entries_width,
27970            }
27971        } else if self.offset_content {
27972            GutterDimensions::default_with_margin(font_id, font_size, cx)
27973        } else {
27974            GutterDimensions::default()
27975        }
27976    }
27977
27978    pub fn render_crease_toggle(
27979        &self,
27980        buffer_row: MultiBufferRow,
27981        row_contains_cursor: bool,
27982        editor: Entity<Editor>,
27983        window: &mut Window,
27984        cx: &mut App,
27985    ) -> Option<AnyElement> {
27986        let folded = self.is_line_folded(buffer_row);
27987        let mut is_foldable = false;
27988
27989        if let Some(crease) = self
27990            .crease_snapshot
27991            .query_row(buffer_row, self.buffer_snapshot())
27992        {
27993            is_foldable = true;
27994            match crease {
27995                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27996                    if let Some(render_toggle) = render_toggle {
27997                        let toggle_callback =
27998                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27999                                if folded {
28000                                    editor.update(cx, |editor, cx| {
28001                                        editor.fold_at(buffer_row, window, cx)
28002                                    });
28003                                } else {
28004                                    editor.update(cx, |editor, cx| {
28005                                        editor.unfold_at(buffer_row, window, cx)
28006                                    });
28007                                }
28008                            });
28009                        return Some((render_toggle)(
28010                            buffer_row,
28011                            folded,
28012                            toggle_callback,
28013                            window,
28014                            cx,
28015                        ));
28016                    }
28017                }
28018            }
28019        }
28020
28021        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28022
28023        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28024            Some(
28025                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28026                    .toggle_state(folded)
28027                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28028                        if folded {
28029                            this.unfold_at(buffer_row, window, cx);
28030                        } else {
28031                            this.fold_at(buffer_row, window, cx);
28032                        }
28033                    }))
28034                    .into_any_element(),
28035            )
28036        } else {
28037            None
28038        }
28039    }
28040
28041    pub fn render_crease_trailer(
28042        &self,
28043        buffer_row: MultiBufferRow,
28044        window: &mut Window,
28045        cx: &mut App,
28046    ) -> Option<AnyElement> {
28047        let folded = self.is_line_folded(buffer_row);
28048        if let Crease::Inline { render_trailer, .. } = self
28049            .crease_snapshot
28050            .query_row(buffer_row, self.buffer_snapshot())?
28051        {
28052            let render_trailer = render_trailer.as_ref()?;
28053            Some(render_trailer(buffer_row, folded, window, cx))
28054        } else {
28055            None
28056        }
28057    }
28058
28059    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28060        let digit_count = self.widest_line_number().ilog10() + 1;
28061        column_pixels(style, digit_count as usize, window)
28062    }
28063
28064    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28065    ///
28066    /// This is positive if `base` is before `line`.
28067    fn relative_line_delta(
28068        &self,
28069        current_selection_head: DisplayRow,
28070        first_visible_row: DisplayRow,
28071        consider_wrapped_lines: bool,
28072    ) -> i64 {
28073        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28074        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28075
28076        if consider_wrapped_lines {
28077            let wrap_snapshot = self.wrap_snapshot();
28078            let base_wrap_row = wrap_snapshot
28079                .make_wrap_point(current_selection_head, Bias::Left)
28080                .row();
28081            let wrap_row = wrap_snapshot
28082                .make_wrap_point(first_visible_row, Bias::Left)
28083                .row();
28084
28085            wrap_row.0 as i64 - base_wrap_row.0 as i64
28086        } else {
28087            let fold_snapshot = self.fold_snapshot();
28088            let base_fold_row = fold_snapshot
28089                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28090                .row();
28091            let fold_row = fold_snapshot
28092                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28093                .row();
28094
28095            fold_row as i64 - base_fold_row as i64
28096        }
28097    }
28098
28099    /// Returns the unsigned relative line number to display for each row in `rows`.
28100    ///
28101    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28102    pub fn calculate_relative_line_numbers(
28103        &self,
28104        rows: &Range<DisplayRow>,
28105        current_selection_head: DisplayRow,
28106        count_wrapped_lines: bool,
28107    ) -> HashMap<DisplayRow, u32> {
28108        let initial_offset =
28109            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28110
28111        self.row_infos(rows.start)
28112            .take(rows.len())
28113            .enumerate()
28114            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28115            .filter(|(_row, row_info)| {
28116                row_info.buffer_row.is_some()
28117                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28118            })
28119            .enumerate()
28120            .filter_map(|(i, (row, row_info))| {
28121                // We want to ensure here that the current line has absolute
28122                // numbering, even if we are in a soft-wrapped line. With the
28123                // exception that if we are in a deleted line, we should number this
28124                // relative with 0, as otherwise it would have no line number at all
28125                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28126
28127                (relative_line_number != 0
28128                    || row_info
28129                        .diff_status
28130                        .is_some_and(|status| status.is_deleted()))
28131                .then_some((row, relative_line_number))
28132            })
28133            .collect()
28134    }
28135}
28136
28137pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28138    let font_size = style.text.font_size.to_pixels(window.rem_size());
28139    let layout = window.text_system().shape_line(
28140        SharedString::from(" ".repeat(column)),
28141        font_size,
28142        &[TextRun {
28143            len: column,
28144            font: style.text.font(),
28145            color: Hsla::default(),
28146            ..Default::default()
28147        }],
28148        None,
28149    );
28150
28151    layout.width
28152}
28153
28154impl Deref for EditorSnapshot {
28155    type Target = DisplaySnapshot;
28156
28157    fn deref(&self) -> &Self::Target {
28158        &self.display_snapshot
28159    }
28160}
28161
28162#[derive(Clone, Debug, PartialEq, Eq)]
28163pub enum EditorEvent {
28164    /// Emitted when the stored review comments change (added, removed, or updated).
28165    ReviewCommentsChanged {
28166        /// The new total count of review comments.
28167        total_count: usize,
28168    },
28169    InputIgnored {
28170        text: Arc<str>,
28171    },
28172    InputHandled {
28173        utf16_range_to_replace: Option<Range<isize>>,
28174        text: Arc<str>,
28175    },
28176    BufferRangesUpdated {
28177        buffer: Entity<Buffer>,
28178        path_key: PathKey,
28179        ranges: Vec<ExcerptRange<text::Anchor>>,
28180    },
28181    BuffersRemoved {
28182        removed_buffer_ids: Vec<BufferId>,
28183    },
28184    BuffersEdited {
28185        buffer_ids: Vec<BufferId>,
28186    },
28187    BufferFoldToggled {
28188        ids: Vec<BufferId>,
28189        folded: bool,
28190    },
28191    ExpandExcerptsRequested {
28192        excerpt_anchors: Vec<Anchor>,
28193        lines: u32,
28194        direction: ExpandExcerptDirection,
28195    },
28196    StageOrUnstageRequested {
28197        stage: bool,
28198        hunks: Vec<MultiBufferDiffHunk>,
28199    },
28200    OpenExcerptsRequested {
28201        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28202        split: bool,
28203    },
28204    RestoreRequested {
28205        hunks: Vec<MultiBufferDiffHunk>,
28206    },
28207    BufferEdited,
28208    Edited {
28209        transaction_id: clock::Lamport,
28210    },
28211    Reparsed(BufferId),
28212    Focused,
28213    FocusedIn,
28214    Blurred,
28215    DirtyChanged,
28216    Saved,
28217    TitleChanged,
28218    SelectionsChanged {
28219        local: bool,
28220    },
28221    ScrollPositionChanged {
28222        local: bool,
28223        autoscroll: bool,
28224    },
28225    TransactionUndone {
28226        transaction_id: clock::Lamport,
28227    },
28228    TransactionBegun {
28229        transaction_id: clock::Lamport,
28230    },
28231    CursorShapeChanged,
28232    BreadcrumbsChanged,
28233    OutlineSymbolsChanged,
28234    PushedToNavHistory {
28235        anchor: Anchor,
28236        is_deactivate: bool,
28237    },
28238}
28239
28240impl EventEmitter<EditorEvent> for Editor {}
28241
28242impl Focusable for Editor {
28243    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28244        self.focus_handle.clone()
28245    }
28246}
28247
28248impl Render for Editor {
28249    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28250        EditorElement::new(&cx.entity(), self.create_style(cx))
28251    }
28252}
28253
28254impl EntityInputHandler for Editor {
28255    fn text_for_range(
28256        &mut self,
28257        range_utf16: Range<usize>,
28258        adjusted_range: &mut Option<Range<usize>>,
28259        _: &mut Window,
28260        cx: &mut Context<Self>,
28261    ) -> Option<String> {
28262        let snapshot = self.buffer.read(cx).read(cx);
28263        let start = snapshot.clip_offset_utf16(
28264            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28265            Bias::Left,
28266        );
28267        let end = snapshot.clip_offset_utf16(
28268            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28269            Bias::Right,
28270        );
28271        if (start.0.0..end.0.0) != range_utf16 {
28272            adjusted_range.replace(start.0.0..end.0.0);
28273        }
28274        Some(snapshot.text_for_range(start..end).collect())
28275    }
28276
28277    fn selected_text_range(
28278        &mut self,
28279        ignore_disabled_input: bool,
28280        _: &mut Window,
28281        cx: &mut Context<Self>,
28282    ) -> Option<UTF16Selection> {
28283        // Prevent the IME menu from appearing when holding down an alphabetic key
28284        // while input is disabled.
28285        if !ignore_disabled_input && !self.input_enabled {
28286            return None;
28287        }
28288
28289        let selection = self
28290            .selections
28291            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28292        let range = selection.range();
28293
28294        Some(UTF16Selection {
28295            range: range.start.0.0..range.end.0.0,
28296            reversed: selection.reversed,
28297        })
28298    }
28299
28300    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28301        let snapshot = self.buffer.read(cx).read(cx);
28302        let range = self
28303            .text_highlights(HighlightKey::InputComposition, cx)?
28304            .1
28305            .first()?;
28306        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28307    }
28308
28309    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28310        self.clear_highlights(HighlightKey::InputComposition, cx);
28311        self.ime_transaction.take();
28312    }
28313
28314    fn replace_text_in_range(
28315        &mut self,
28316        range_utf16: Option<Range<usize>>,
28317        text: &str,
28318        window: &mut Window,
28319        cx: &mut Context<Self>,
28320    ) {
28321        if !self.input_enabled {
28322            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28323            return;
28324        }
28325
28326        self.transact(window, cx, |this, window, cx| {
28327            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28328                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28329                    // During IME composition, macOS reports the replacement range
28330                    // relative to the first marked region (the only one visible via
28331                    // marked_text_range). The correct targets for replacement are the
28332                    // marked ranges themselves — one per cursor — so use them directly.
28333                    Some(marked_ranges)
28334                } else if range_utf16.start == range_utf16.end {
28335                    // An empty replacement range means "insert at cursor" with no text
28336                    // to replace. macOS reports the cursor position from its own
28337                    // (single-cursor) view of the buffer, which diverges from our actual
28338                    // cursor positions after multi-cursor edits have shifted offsets.
28339                    // Treating this as range_utf16=None lets each cursor insert in place.
28340                    None
28341                } else {
28342                    // Outside of IME composition (e.g. Accessibility Keyboard word
28343                    // completion), the range is an absolute document offset for the
28344                    // newest cursor. Fan it out to all cursors via
28345                    // selection_replacement_ranges, which applies the delta relative
28346                    // to the newest selection to every cursor.
28347                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28348                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28349                    Some(this.selection_replacement_ranges(range_utf16, cx))
28350                }
28351            } else {
28352                this.marked_text_ranges(cx)
28353            };
28354
28355            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28356                let newest_selection_id = this.selections.newest_anchor().id;
28357                this.selections
28358                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28359                    .iter()
28360                    .zip(ranges_to_replace.iter())
28361                    .find_map(|(selection, range)| {
28362                        if selection.id == newest_selection_id {
28363                            Some(
28364                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28365                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28366                            )
28367                        } else {
28368                            None
28369                        }
28370                    })
28371            });
28372
28373            cx.emit(EditorEvent::InputHandled {
28374                utf16_range_to_replace: range_to_replace,
28375                text: text.into(),
28376            });
28377
28378            if let Some(new_selected_ranges) = new_selected_ranges {
28379                // Only backspace if at least one range covers actual text. When all
28380                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28381                // Keyboard sends replacementRange=cursor..cursor), backspace would
28382                // incorrectly delete the character just before the cursor.
28383                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28384                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28385                    selections.select_ranges(new_selected_ranges)
28386                });
28387                if should_backspace {
28388                    this.backspace(&Default::default(), window, cx);
28389                }
28390            }
28391
28392            this.handle_input(text, window, cx);
28393        });
28394
28395        if let Some(transaction) = self.ime_transaction {
28396            self.buffer.update(cx, |buffer, cx| {
28397                buffer.group_until_transaction(transaction, cx);
28398            });
28399        }
28400
28401        self.unmark_text(window, cx);
28402    }
28403
28404    fn replace_and_mark_text_in_range(
28405        &mut self,
28406        range_utf16: Option<Range<usize>>,
28407        text: &str,
28408        new_selected_range_utf16: Option<Range<usize>>,
28409        window: &mut Window,
28410        cx: &mut Context<Self>,
28411    ) {
28412        if !self.input_enabled {
28413            return;
28414        }
28415
28416        let transaction = self.transact(window, cx, |this, window, cx| {
28417            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28418                let snapshot = this.buffer.read(cx).read(cx);
28419                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28420                    for marked_range in &mut marked_ranges {
28421                        marked_range.end = marked_range.start + relative_range_utf16.end;
28422                        marked_range.start += relative_range_utf16.start;
28423                        marked_range.start =
28424                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28425                        marked_range.end =
28426                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28427                    }
28428                }
28429                Some(marked_ranges)
28430            } else if let Some(range_utf16) = range_utf16 {
28431                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28432                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28433                Some(this.selection_replacement_ranges(range_utf16, cx))
28434            } else {
28435                None
28436            };
28437
28438            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28439                let newest_selection_id = this.selections.newest_anchor().id;
28440                this.selections
28441                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28442                    .iter()
28443                    .zip(ranges_to_replace.iter())
28444                    .find_map(|(selection, range)| {
28445                        if selection.id == newest_selection_id {
28446                            Some(
28447                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28448                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28449                            )
28450                        } else {
28451                            None
28452                        }
28453                    })
28454            });
28455
28456            cx.emit(EditorEvent::InputHandled {
28457                utf16_range_to_replace: range_to_replace,
28458                text: text.into(),
28459            });
28460
28461            if let Some(ranges) = ranges_to_replace {
28462                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28463                    s.select_ranges(ranges)
28464                });
28465            }
28466
28467            let marked_ranges = {
28468                let snapshot = this.buffer.read(cx).read(cx);
28469                this.selections
28470                    .disjoint_anchors_arc()
28471                    .iter()
28472                    .map(|selection| {
28473                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28474                    })
28475                    .collect::<Vec<_>>()
28476            };
28477
28478            if text.is_empty() {
28479                this.unmark_text(window, cx);
28480            } else {
28481                this.highlight_text(
28482                    HighlightKey::InputComposition,
28483                    marked_ranges.clone(),
28484                    HighlightStyle {
28485                        underline: Some(UnderlineStyle {
28486                            thickness: px(1.),
28487                            color: None,
28488                            wavy: false,
28489                        }),
28490                        ..Default::default()
28491                    },
28492                    cx,
28493                );
28494            }
28495
28496            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28497            let use_autoclose = this.use_autoclose;
28498            let use_auto_surround = this.use_auto_surround;
28499            this.set_use_autoclose(false);
28500            this.set_use_auto_surround(false);
28501            this.handle_input(text, window, cx);
28502            this.set_use_autoclose(use_autoclose);
28503            this.set_use_auto_surround(use_auto_surround);
28504
28505            if let Some(new_selected_range) = new_selected_range_utf16 {
28506                let snapshot = this.buffer.read(cx).read(cx);
28507                let new_selected_ranges = marked_ranges
28508                    .into_iter()
28509                    .map(|marked_range| {
28510                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28511                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28512                            insertion_start.0 + new_selected_range.start,
28513                        ));
28514                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28515                            insertion_start.0 + new_selected_range.end,
28516                        ));
28517                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28518                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28519                    })
28520                    .collect::<Vec<_>>();
28521
28522                drop(snapshot);
28523                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28524                    selections.select_ranges(new_selected_ranges)
28525                });
28526            }
28527        });
28528
28529        self.ime_transaction = self.ime_transaction.or(transaction);
28530        if let Some(transaction) = self.ime_transaction {
28531            self.buffer.update(cx, |buffer, cx| {
28532                buffer.group_until_transaction(transaction, cx);
28533            });
28534        }
28535
28536        if self
28537            .text_highlights(HighlightKey::InputComposition, cx)
28538            .is_none()
28539        {
28540            self.ime_transaction.take();
28541        }
28542    }
28543
28544    fn bounds_for_range(
28545        &mut self,
28546        range_utf16: Range<usize>,
28547        element_bounds: gpui::Bounds<Pixels>,
28548        window: &mut Window,
28549        cx: &mut Context<Self>,
28550    ) -> Option<gpui::Bounds<Pixels>> {
28551        let text_layout_details = self.text_layout_details(window, cx);
28552        let CharacterDimensions {
28553            em_width,
28554            em_advance,
28555            line_height,
28556        } = self.character_dimensions(window, cx);
28557
28558        let snapshot = self.snapshot(window, cx);
28559        let scroll_position = snapshot.scroll_position();
28560        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28561
28562        let start =
28563            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28564        let x = Pixels::from(
28565            ScrollOffset::from(
28566                snapshot.x_for_display_point(start, &text_layout_details)
28567                    + self.gutter_dimensions.full_width(),
28568            ) - scroll_left,
28569        );
28570        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28571
28572        Some(Bounds {
28573            origin: element_bounds.origin + point(x, y),
28574            size: size(em_width, line_height),
28575        })
28576    }
28577
28578    fn character_index_for_point(
28579        &mut self,
28580        point: gpui::Point<Pixels>,
28581        _window: &mut Window,
28582        _cx: &mut Context<Self>,
28583    ) -> Option<usize> {
28584        let position_map = self.last_position_map.as_ref()?;
28585        if !position_map.text_hitbox.contains(&point) {
28586            return None;
28587        }
28588        let display_point = position_map.point_for_position(point).previous_valid;
28589        let anchor = position_map
28590            .snapshot
28591            .display_point_to_anchor(display_point, Bias::Left);
28592        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28593        Some(utf16_offset.0.0)
28594    }
28595
28596    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28597        self.expects_character_input
28598    }
28599}
28600
28601trait SelectionExt {
28602    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28603    fn spanned_rows(
28604        &self,
28605        include_end_if_at_line_start: bool,
28606        map: &DisplaySnapshot,
28607    ) -> Range<MultiBufferRow>;
28608}
28609
28610impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28611    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28612        let start = self
28613            .start
28614            .to_point(map.buffer_snapshot())
28615            .to_display_point(map);
28616        let end = self
28617            .end
28618            .to_point(map.buffer_snapshot())
28619            .to_display_point(map);
28620        if self.reversed {
28621            end..start
28622        } else {
28623            start..end
28624        }
28625    }
28626
28627    fn spanned_rows(
28628        &self,
28629        include_end_if_at_line_start: bool,
28630        map: &DisplaySnapshot,
28631    ) -> Range<MultiBufferRow> {
28632        let start = self.start.to_point(map.buffer_snapshot());
28633        let mut end = self.end.to_point(map.buffer_snapshot());
28634        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28635            end.row -= 1;
28636        }
28637
28638        let buffer_start = map.prev_line_boundary(start).0;
28639        let buffer_end = map.next_line_boundary(end).0;
28640        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28641    }
28642}
28643
28644impl<T: InvalidationRegion> InvalidationStack<T> {
28645    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28646    where
28647        S: Clone + ToOffset,
28648    {
28649        while let Some(region) = self.last() {
28650            let all_selections_inside_invalidation_ranges =
28651                if selections.len() == region.ranges().len() {
28652                    selections
28653                        .iter()
28654                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28655                        .all(|(selection, invalidation_range)| {
28656                            let head = selection.head().to_offset(buffer);
28657                            invalidation_range.start <= head && invalidation_range.end >= head
28658                        })
28659                } else {
28660                    false
28661                };
28662
28663            if all_selections_inside_invalidation_ranges {
28664                break;
28665            } else {
28666                self.pop();
28667            }
28668        }
28669    }
28670}
28671
28672#[derive(Clone)]
28673struct ErasedEditorImpl(Entity<Editor>);
28674
28675impl ui_input::ErasedEditor for ErasedEditorImpl {
28676    fn text(&self, cx: &App) -> String {
28677        self.0.read(cx).text(cx)
28678    }
28679
28680    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28681        self.0.update(cx, |this, cx| {
28682            this.set_text(text, window, cx);
28683        })
28684    }
28685
28686    fn clear(&self, window: &mut Window, cx: &mut App) {
28687        self.0.update(cx, |this, cx| this.clear(window, cx));
28688    }
28689
28690    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28691        self.0.update(cx, |this, cx| {
28692            this.set_placeholder_text(text, window, cx);
28693        });
28694    }
28695
28696    fn focus_handle(&self, cx: &App) -> FocusHandle {
28697        self.0.read(cx).focus_handle(cx)
28698    }
28699
28700    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28701        let settings = ThemeSettings::get_global(cx);
28702        let theme_color = cx.theme().colors();
28703
28704        let text_style = TextStyle {
28705            font_family: settings.ui_font.family.clone(),
28706            font_features: settings.ui_font.features.clone(),
28707            font_size: rems(0.875).into(),
28708            font_weight: settings.ui_font.weight,
28709            font_style: FontStyle::Normal,
28710            line_height: relative(1.2),
28711            color: theme_color.text,
28712            ..Default::default()
28713        };
28714        let editor_style = EditorStyle {
28715            background: theme_color.ghost_element_background,
28716            local_player: cx.theme().players().local(),
28717            syntax: cx.theme().syntax().clone(),
28718            text: text_style,
28719            ..Default::default()
28720        };
28721        EditorElement::new(&self.0, editor_style).into_any()
28722    }
28723
28724    fn as_any(&self) -> &dyn Any {
28725        &self.0
28726    }
28727
28728    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28729        self.0.update(cx, |editor, cx| {
28730            let editor_offset = editor.buffer().read(cx).len(cx);
28731            editor.change_selections(
28732                SelectionEffects::scroll(Autoscroll::Next),
28733                window,
28734                cx,
28735                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28736            );
28737        });
28738    }
28739
28740    fn subscribe(
28741        &self,
28742        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28743        window: &mut Window,
28744        cx: &mut App,
28745    ) -> Subscription {
28746        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28747            let event = match event {
28748                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28749                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28750                _ => return,
28751            };
28752            (callback)(event, window, cx);
28753        })
28754    }
28755
28756    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28757        self.0.update(cx, |editor, cx| {
28758            editor.set_masked(masked, cx);
28759        });
28760    }
28761}
28762impl<T> Default for InvalidationStack<T> {
28763    fn default() -> Self {
28764        Self(Default::default())
28765    }
28766}
28767
28768impl<T> Deref for InvalidationStack<T> {
28769    type Target = Vec<T>;
28770
28771    fn deref(&self) -> &Self::Target {
28772        &self.0
28773    }
28774}
28775
28776impl<T> DerefMut for InvalidationStack<T> {
28777    fn deref_mut(&mut self) -> &mut Self::Target {
28778        &mut self.0
28779    }
28780}
28781
28782impl InvalidationRegion for SnippetState {
28783    fn ranges(&self) -> &[Range<Anchor>] {
28784        &self.ranges[self.active_index]
28785    }
28786}
28787
28788fn edit_prediction_edit_text(
28789    current_snapshot: &BufferSnapshot,
28790    edits: &[(Range<Anchor>, impl AsRef<str>)],
28791    edit_preview: &EditPreview,
28792    include_deletions: bool,
28793    multibuffer_snapshot: &MultiBufferSnapshot,
28794    cx: &App,
28795) -> HighlightedText {
28796    let edits = edits
28797        .iter()
28798        .filter_map(|(anchor, text)| {
28799            Some((
28800                multibuffer_snapshot
28801                    .anchor_range_to_buffer_anchor_range(anchor.clone())?
28802                    .1,
28803                text,
28804            ))
28805        })
28806        .collect::<Vec<_>>();
28807
28808    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28809}
28810
28811fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28812    // Fallback for providers that don't provide edit_preview (like Copilot)
28813    // Just show the raw edit text with basic styling
28814    let mut text = String::new();
28815    let mut highlights = Vec::new();
28816
28817    let insertion_highlight_style = HighlightStyle {
28818        color: Some(cx.theme().colors().text),
28819        ..Default::default()
28820    };
28821
28822    for (_, edit_text) in edits {
28823        let start_offset = text.len();
28824        text.push_str(edit_text);
28825        let end_offset = text.len();
28826
28827        if start_offset < end_offset {
28828            highlights.push((start_offset..end_offset, insertion_highlight_style));
28829        }
28830    }
28831
28832    HighlightedText {
28833        text: text.into(),
28834        highlights,
28835    }
28836}
28837
28838pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28839    match severity {
28840        lsp::DiagnosticSeverity::ERROR => colors.error,
28841        lsp::DiagnosticSeverity::WARNING => colors.warning,
28842        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28843        lsp::DiagnosticSeverity::HINT => colors.info,
28844        _ => colors.ignored,
28845    }
28846}
28847
28848pub fn styled_runs_for_code_label<'a>(
28849    label: &'a CodeLabel,
28850    syntax_theme: &'a theme::SyntaxTheme,
28851    local_player: &'a theme::PlayerColor,
28852) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28853    let fade_out = HighlightStyle {
28854        fade_out: Some(0.35),
28855        ..Default::default()
28856    };
28857
28858    if label.runs.is_empty() {
28859        let desc_start = label.filter_range.end;
28860        let fade_run =
28861            (desc_start < label.text.len()).then(|| (desc_start..label.text.len(), fade_out));
28862        return Either::Left(fade_run.into_iter());
28863    }
28864
28865    let mut prev_end = label.filter_range.end;
28866    Either::Right(
28867        label
28868            .runs
28869            .iter()
28870            .enumerate()
28871            .flat_map(move |(ix, (range, highlight_id))| {
28872                let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28873                    HighlightStyle {
28874                        color: Some(local_player.cursor),
28875                        ..Default::default()
28876                    }
28877                } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28878                    HighlightStyle {
28879                        background_color: Some(local_player.selection),
28880                        ..Default::default()
28881                    }
28882                } else if let Some(style) = syntax_theme.get(*highlight_id).cloned() {
28883                    style
28884                } else {
28885                    return Default::default();
28886                };
28887
28888                let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28889                let muted_style = style.highlight(fade_out);
28890                if range.start >= label.filter_range.end {
28891                    if range.start > prev_end {
28892                        runs.push((prev_end..range.start, fade_out));
28893                    }
28894                    runs.push((range.clone(), muted_style));
28895                } else if range.end <= label.filter_range.end {
28896                    runs.push((range.clone(), style));
28897                } else {
28898                    runs.push((range.start..label.filter_range.end, style));
28899                    runs.push((label.filter_range.end..range.end, muted_style));
28900                }
28901                prev_end = cmp::max(prev_end, range.end);
28902
28903                if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28904                    runs.push((prev_end..label.text.len(), fade_out));
28905                }
28906
28907                runs
28908            }),
28909    )
28910}
28911
28912pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28913    let mut prev_index = 0;
28914    let mut prev_codepoint: Option<char> = None;
28915    text.char_indices()
28916        .chain([(text.len(), '\0')])
28917        .filter_map(move |(index, codepoint)| {
28918            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28919            let is_boundary = index == text.len()
28920                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28921                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28922            if is_boundary {
28923                let chunk = &text[prev_index..index];
28924                prev_index = index;
28925                Some(chunk)
28926            } else {
28927                None
28928            }
28929        })
28930}
28931
28932/// Given a string of text immediately before the cursor, iterates over possible
28933/// strings a snippet could match to. More precisely: returns an iterator over
28934/// suffixes of `text` created by splitting at word boundaries (before & after
28935/// every non-word character).
28936///
28937/// Shorter suffixes are returned first.
28938pub(crate) fn snippet_candidate_suffixes<'a>(
28939    text: &'a str,
28940    is_word_char: &'a dyn Fn(char) -> bool,
28941) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28942    let mut prev_index = text.len();
28943    let mut prev_codepoint = None;
28944    text.char_indices()
28945        .rev()
28946        .chain([(0, '\0')])
28947        .filter_map(move |(index, codepoint)| {
28948            let prev_index = std::mem::replace(&mut prev_index, index);
28949            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28950            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28951                None
28952            } else {
28953                let chunk = &text[prev_index..]; // go to end of string
28954                Some(chunk)
28955            }
28956        })
28957}
28958
28959pub trait RangeToAnchorExt: Sized {
28960    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28961
28962    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28963        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28964        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28965    }
28966}
28967
28968impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28969    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28970        let start_offset = self.start.to_offset(snapshot);
28971        let end_offset = self.end.to_offset(snapshot);
28972        if start_offset == end_offset {
28973            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28974        } else {
28975            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28976        }
28977    }
28978}
28979
28980pub trait RowExt {
28981    fn as_f64(&self) -> f64;
28982
28983    fn next_row(&self) -> Self;
28984
28985    fn previous_row(&self) -> Self;
28986
28987    fn minus(&self, other: Self) -> u32;
28988}
28989
28990impl RowExt for DisplayRow {
28991    fn as_f64(&self) -> f64 {
28992        self.0 as _
28993    }
28994
28995    fn next_row(&self) -> Self {
28996        Self(self.0 + 1)
28997    }
28998
28999    fn previous_row(&self) -> Self {
29000        Self(self.0.saturating_sub(1))
29001    }
29002
29003    fn minus(&self, other: Self) -> u32 {
29004        self.0 - other.0
29005    }
29006}
29007
29008impl RowExt for MultiBufferRow {
29009    fn as_f64(&self) -> f64 {
29010        self.0 as _
29011    }
29012
29013    fn next_row(&self) -> Self {
29014        Self(self.0 + 1)
29015    }
29016
29017    fn previous_row(&self) -> Self {
29018        Self(self.0.saturating_sub(1))
29019    }
29020
29021    fn minus(&self, other: Self) -> u32 {
29022        self.0 - other.0
29023    }
29024}
29025
29026trait RowRangeExt {
29027    type Row;
29028
29029    fn len(&self) -> usize;
29030
29031    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29032}
29033
29034impl RowRangeExt for Range<MultiBufferRow> {
29035    type Row = MultiBufferRow;
29036
29037    fn len(&self) -> usize {
29038        (self.end.0 - self.start.0) as usize
29039    }
29040
29041    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29042        (self.start.0..self.end.0).map(MultiBufferRow)
29043    }
29044}
29045
29046impl RowRangeExt for Range<DisplayRow> {
29047    type Row = DisplayRow;
29048
29049    fn len(&self) -> usize {
29050        (self.end.0 - self.start.0) as usize
29051    }
29052
29053    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29054        (self.start.0..self.end.0).map(DisplayRow)
29055    }
29056}
29057
29058/// If select range has more than one line, we
29059/// just point the cursor to range.start.
29060fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29061    if range.start.row == range.end.row {
29062        range
29063    } else {
29064        range.start..range.start
29065    }
29066}
29067pub struct KillRing(ClipboardItem);
29068impl Global for KillRing {}
29069
29070const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29071
29072enum BreakpointPromptEditAction {
29073    Log,
29074    Condition,
29075    HitCondition,
29076}
29077
29078struct BreakpointPromptEditor {
29079    pub(crate) prompt: Entity<Editor>,
29080    editor: WeakEntity<Editor>,
29081    breakpoint_anchor: Anchor,
29082    breakpoint: Breakpoint,
29083    edit_action: BreakpointPromptEditAction,
29084    block_ids: HashSet<CustomBlockId>,
29085    editor_margins: Arc<Mutex<EditorMargins>>,
29086    _subscriptions: Vec<Subscription>,
29087}
29088
29089impl BreakpointPromptEditor {
29090    const MAX_LINES: u8 = 4;
29091
29092    fn new(
29093        editor: WeakEntity<Editor>,
29094        breakpoint_anchor: Anchor,
29095        breakpoint: Breakpoint,
29096        edit_action: BreakpointPromptEditAction,
29097        window: &mut Window,
29098        cx: &mut Context<Self>,
29099    ) -> Self {
29100        let base_text = match edit_action {
29101            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29102            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29103            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29104        }
29105        .map(|msg| msg.to_string())
29106        .unwrap_or_default();
29107
29108        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29109        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29110
29111        let prompt = cx.new(|cx| {
29112            let mut prompt = Editor::new(
29113                EditorMode::AutoHeight {
29114                    min_lines: 1,
29115                    max_lines: Some(Self::MAX_LINES as usize),
29116                },
29117                buffer,
29118                None,
29119                window,
29120                cx,
29121            );
29122            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29123            prompt.set_show_cursor_when_unfocused(false, cx);
29124            prompt.set_placeholder_text(
29125                match edit_action {
29126                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29127                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29128                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29129                },
29130                window,
29131                cx,
29132            );
29133
29134            prompt
29135        });
29136
29137        Self {
29138            prompt,
29139            editor,
29140            breakpoint_anchor,
29141            breakpoint,
29142            edit_action,
29143            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29144            block_ids: Default::default(),
29145            _subscriptions: vec![],
29146        }
29147    }
29148
29149    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29150        self.block_ids.extend(block_ids)
29151    }
29152
29153    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29154        if let Some(editor) = self.editor.upgrade() {
29155            let message = self
29156                .prompt
29157                .read(cx)
29158                .buffer
29159                .read(cx)
29160                .as_singleton()
29161                .expect("A multi buffer in breakpoint prompt isn't possible")
29162                .read(cx)
29163                .as_rope()
29164                .to_string();
29165
29166            editor.update(cx, |editor, cx| {
29167                editor.edit_breakpoint_at_anchor(
29168                    self.breakpoint_anchor,
29169                    self.breakpoint.clone(),
29170                    match self.edit_action {
29171                        BreakpointPromptEditAction::Log => {
29172                            BreakpointEditAction::EditLogMessage(message.into())
29173                        }
29174                        BreakpointPromptEditAction::Condition => {
29175                            BreakpointEditAction::EditCondition(message.into())
29176                        }
29177                        BreakpointPromptEditAction::HitCondition => {
29178                            BreakpointEditAction::EditHitCondition(message.into())
29179                        }
29180                    },
29181                    cx,
29182                );
29183
29184                editor.remove_blocks(self.block_ids.clone(), None, cx);
29185                cx.focus_self(window);
29186            });
29187        }
29188    }
29189
29190    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29191        self.editor
29192            .update(cx, |editor, cx| {
29193                editor.remove_blocks(self.block_ids.clone(), None, cx);
29194                window.focus(&editor.focus_handle, cx);
29195            })
29196            .log_err();
29197    }
29198
29199    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29200        let settings = ThemeSettings::get_global(cx);
29201        let text_style = TextStyle {
29202            color: if self.prompt.read(cx).read_only(cx) {
29203                cx.theme().colors().text_disabled
29204            } else {
29205                cx.theme().colors().text
29206            },
29207            font_family: settings.buffer_font.family.clone(),
29208            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29209            font_size: settings.buffer_font_size(cx).into(),
29210            font_weight: settings.buffer_font.weight,
29211            line_height: relative(settings.buffer_line_height.value()),
29212            ..Default::default()
29213        };
29214        EditorElement::new(
29215            &self.prompt,
29216            EditorStyle {
29217                background: cx.theme().colors().editor_background,
29218                local_player: cx.theme().players().local(),
29219                text: text_style,
29220                ..Default::default()
29221            },
29222        )
29223    }
29224
29225    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29226        let focus_handle = self.prompt.focus_handle(cx);
29227        IconButton::new("cancel", IconName::Close)
29228            .icon_color(Color::Muted)
29229            .shape(IconButtonShape::Square)
29230            .tooltip(move |_window, cx| {
29231                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29232            })
29233            .on_click(cx.listener(|this, _, window, cx| {
29234                this.cancel(&menu::Cancel, window, cx);
29235            }))
29236    }
29237
29238    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29239        let focus_handle = self.prompt.focus_handle(cx);
29240        IconButton::new("confirm", IconName::Return)
29241            .icon_color(Color::Muted)
29242            .shape(IconButtonShape::Square)
29243            .tooltip(move |_window, cx| {
29244                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29245            })
29246            .on_click(cx.listener(|this, _, window, cx| {
29247                this.confirm(&menu::Confirm, window, cx);
29248            }))
29249    }
29250}
29251
29252impl Render for BreakpointPromptEditor {
29253    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29254        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29255        let editor_margins = *self.editor_margins.lock();
29256        let gutter_dimensions = editor_margins.gutter;
29257        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29258        let right_padding = editor_margins.right + px(9.);
29259        h_flex()
29260            .key_context("Editor")
29261            .bg(cx.theme().colors().editor_background)
29262            .border_y_1()
29263            .border_color(cx.theme().status().info_border)
29264            .size_full()
29265            .py(window.line_height() / 2.5)
29266            .pr(right_padding)
29267            .on_action(cx.listener(Self::confirm))
29268            .on_action(cx.listener(Self::cancel))
29269            .child(
29270                WithRemSize::new(ui_font_size)
29271                    .h_full()
29272                    .w(left_gutter_width)
29273                    .flex()
29274                    .flex_row()
29275                    .flex_shrink_0()
29276                    .items_center()
29277                    .justify_center()
29278                    .gap_1()
29279                    .child(self.render_close_button(cx)),
29280            )
29281            .child(
29282                h_flex()
29283                    .w_full()
29284                    .justify_between()
29285                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29286                    .child(
29287                        WithRemSize::new(ui_font_size)
29288                            .flex()
29289                            .flex_row()
29290                            .items_center()
29291                            .child(self.render_confirm_button(cx)),
29292                    ),
29293            )
29294    }
29295}
29296
29297impl Focusable for BreakpointPromptEditor {
29298    fn focus_handle(&self, cx: &App) -> FocusHandle {
29299        self.prompt.focus_handle(cx)
29300    }
29301}
29302
29303fn all_edits_insertions_or_deletions(
29304    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29305    snapshot: &MultiBufferSnapshot,
29306) -> bool {
29307    let mut all_insertions = true;
29308    let mut all_deletions = true;
29309
29310    for (range, new_text) in edits.iter() {
29311        let range_is_empty = range.to_offset(snapshot).is_empty();
29312        let text_is_empty = new_text.is_empty();
29313
29314        if range_is_empty != text_is_empty {
29315            if range_is_empty {
29316                all_deletions = false;
29317            } else {
29318                all_insertions = false;
29319            }
29320        } else {
29321            return false;
29322        }
29323
29324        if !all_insertions && !all_deletions {
29325            return false;
29326        }
29327    }
29328    all_insertions || all_deletions
29329}
29330
29331struct MissingEditPredictionKeybindingTooltip;
29332
29333impl Render for MissingEditPredictionKeybindingTooltip {
29334    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29335        ui::tooltip_container(cx, |container, cx| {
29336            container
29337                .flex_shrink_0()
29338                .max_w_80()
29339                .min_h(rems_from_px(124.))
29340                .justify_between()
29341                .child(
29342                    v_flex()
29343                        .flex_1()
29344                        .text_ui_sm(cx)
29345                        .child(Label::new("Conflict with Accept Keybinding"))
29346                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29347                )
29348                .child(
29349                    h_flex()
29350                        .pb_1()
29351                        .gap_1()
29352                        .items_end()
29353                        .w_full()
29354                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29355                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29356                        }))
29357                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29358                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29359                        })),
29360                )
29361        })
29362    }
29363}
29364
29365#[derive(Debug, Clone, Copy, PartialEq)]
29366pub struct LineHighlight {
29367    pub background: Background,
29368    pub border: Option<gpui::Hsla>,
29369    pub include_gutter: bool,
29370    pub type_id: Option<TypeId>,
29371}
29372
29373struct LineManipulationResult {
29374    pub new_text: String,
29375    pub line_count_before: usize,
29376    pub line_count_after: usize,
29377}
29378
29379fn render_diff_hunk_controls(
29380    row: u32,
29381    status: &DiffHunkStatus,
29382    hunk_range: Range<Anchor>,
29383    is_created_file: bool,
29384    line_height: Pixels,
29385    editor: &Entity<Editor>,
29386    _window: &mut Window,
29387    cx: &mut App,
29388) -> AnyElement {
29389    h_flex()
29390        .h(line_height)
29391        .mr_1()
29392        .gap_1()
29393        .px_0p5()
29394        .pb_1()
29395        .border_x_1()
29396        .border_b_1()
29397        .border_color(cx.theme().colors().border_variant)
29398        .rounded_b_lg()
29399        .bg(cx.theme().colors().editor_background)
29400        .gap_1()
29401        .block_mouse_except_scroll()
29402        .shadow_md()
29403        .child(if status.has_secondary_hunk() {
29404            Button::new(("stage", row as u64), "Stage")
29405                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29406                .tooltip({
29407                    let focus_handle = editor.focus_handle(cx);
29408                    move |_window, cx| {
29409                        Tooltip::for_action_in(
29410                            "Stage Hunk",
29411                            &::git::ToggleStaged,
29412                            &focus_handle,
29413                            cx,
29414                        )
29415                    }
29416                })
29417                .on_click({
29418                    let editor = editor.clone();
29419                    move |_event, _window, cx| {
29420                        editor.update(cx, |editor, cx| {
29421                            editor.stage_or_unstage_diff_hunks(
29422                                true,
29423                                vec![hunk_range.start..hunk_range.start],
29424                                cx,
29425                            );
29426                        });
29427                    }
29428                })
29429        } else {
29430            Button::new(("unstage", row as u64), "Unstage")
29431                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29432                .tooltip({
29433                    let focus_handle = editor.focus_handle(cx);
29434                    move |_window, cx| {
29435                        Tooltip::for_action_in(
29436                            "Unstage Hunk",
29437                            &::git::ToggleStaged,
29438                            &focus_handle,
29439                            cx,
29440                        )
29441                    }
29442                })
29443                .on_click({
29444                    let editor = editor.clone();
29445                    move |_event, _window, cx| {
29446                        editor.update(cx, |editor, cx| {
29447                            editor.stage_or_unstage_diff_hunks(
29448                                false,
29449                                vec![hunk_range.start..hunk_range.start],
29450                                cx,
29451                            );
29452                        });
29453                    }
29454                })
29455        })
29456        .child(
29457            Button::new(("restore", row as u64), "Restore")
29458                .tooltip({
29459                    let focus_handle = editor.focus_handle(cx);
29460                    move |_window, cx| {
29461                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29462                    }
29463                })
29464                .on_click({
29465                    let editor = editor.clone();
29466                    move |_event, window, cx| {
29467                        editor.update(cx, |editor, cx| {
29468                            let snapshot = editor.snapshot(window, cx);
29469                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29470                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29471                        });
29472                    }
29473                })
29474                .disabled(is_created_file),
29475        )
29476        .when(
29477            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29478            |el| {
29479                el.child(
29480                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29481                        .shape(IconButtonShape::Square)
29482                        .icon_size(IconSize::Small)
29483                        // .disabled(!has_multiple_hunks)
29484                        .tooltip({
29485                            let focus_handle = editor.focus_handle(cx);
29486                            move |_window, cx| {
29487                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29488                            }
29489                        })
29490                        .on_click({
29491                            let editor = editor.clone();
29492                            move |_event, window, cx| {
29493                                editor.update(cx, |editor, cx| {
29494                                    let snapshot = editor.snapshot(window, cx);
29495                                    let position =
29496                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29497                                    editor.go_to_hunk_before_or_after_position(
29498                                        &snapshot,
29499                                        position,
29500                                        Direction::Next,
29501                                        true,
29502                                        window,
29503                                        cx,
29504                                    );
29505                                    editor.expand_selected_diff_hunks(cx);
29506                                });
29507                            }
29508                        }),
29509                )
29510                .child(
29511                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29512                        .shape(IconButtonShape::Square)
29513                        .icon_size(IconSize::Small)
29514                        // .disabled(!has_multiple_hunks)
29515                        .tooltip({
29516                            let focus_handle = editor.focus_handle(cx);
29517                            move |_window, cx| {
29518                                Tooltip::for_action_in(
29519                                    "Previous Hunk",
29520                                    &GoToPreviousHunk,
29521                                    &focus_handle,
29522                                    cx,
29523                                )
29524                            }
29525                        })
29526                        .on_click({
29527                            let editor = editor.clone();
29528                            move |_event, window, cx| {
29529                                editor.update(cx, |editor, cx| {
29530                                    let snapshot = editor.snapshot(window, cx);
29531                                    let point =
29532                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29533                                    editor.go_to_hunk_before_or_after_position(
29534                                        &snapshot,
29535                                        point,
29536                                        Direction::Prev,
29537                                        true,
29538                                        window,
29539                                        cx,
29540                                    );
29541                                    editor.expand_selected_diff_hunks(cx);
29542                                });
29543                            }
29544                        }),
29545                )
29546            },
29547        )
29548        .into_any_element()
29549}
29550
29551pub fn multibuffer_context_lines(cx: &App) -> u32 {
29552    EditorSettings::try_get(cx)
29553        .map(|settings| settings.excerpt_context_lines)
29554        .unwrap_or(2)
29555        .min(32)
29556}